blob: 67056959f969ce3307a2f5f46d54a7c50868f140 [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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "api/video/i420_buffer.h"
Erik Språng4529fbc2018-10-12 10:30:31 +020018#include "api/video_codecs/create_vp8_temporal_layers.h"
19#include "api/video_codecs/vp8_temporal_layers.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "media/base/videoadapter.h"
Sergey Silkin86684962018-03-28 19:32:37 +020021#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
23#include "rtc_base/fakeclock.h"
24#include "rtc_base/logging.h"
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020025#include "rtc_base/refcountedobject.h"
Mirko Bonadei17f48782018-09-28 08:51:10 +020026#include "system_wrappers/include/metrics.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020027#include "system_wrappers/include/sleep.h"
28#include "test/encoder_settings.h"
29#include "test/fake_encoder.h"
Kári Tristan Helgason639602a2018-08-02 10:51:40 +020030#include "test/field_trial.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020031#include "test/frame_generator.h"
32#include "test/gmock.h"
33#include "test/gtest.h"
Niels Möllercbcbc222018-09-28 09:07:24 +020034#include "test/video_encoder_proxy_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020035#include "video/send_statistics_proxy.h"
perkj26091b12016-09-01 01:17:40 -070036
37namespace webrtc {
38
sprangb1ca0732017-02-01 08:38:12 -080039using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080040using ::testing::_;
41using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080042
perkj803d97f2016-11-01 11:45:46 -070043namespace {
Åsa Persson8c1bf952018-09-13 10:42:19 +020044const int kMinPixelsPerFrame = 320 * 180;
45const int kMinFramerateFps = 2;
46const int kMinBalancedFramerateFps = 7;
47const int64_t kFrameTimeoutMs = 100;
asapersson5f7226f2016-11-25 04:37:00 -080048const size_t kMaxPayloadLength = 1440;
kthelgason2bc68642017-02-07 07:02:22 -080049const int kTargetBitrateBps = 1000000;
50const int kLowTargetBitrateBps = kTargetBitrateBps / 10;
51const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070052const int kDefaultFramerate = 30;
Åsa Persson8c1bf952018-09-13 10:42:19 +020053const int64_t kFrameIntervalMs = rtc::kNumMillisecsPerSec / kDefaultFramerate;
asapersson5f7226f2016-11-25 04:37:00 -080054
perkj803d97f2016-11-01 11:45:46 -070055class TestBuffer : public webrtc::I420Buffer {
56 public:
57 TestBuffer(rtc::Event* event, int width, int height)
58 : I420Buffer(width, height), event_(event) {}
59
60 private:
61 friend class rtc::RefCountedObject<TestBuffer>;
62 ~TestBuffer() override {
63 if (event_)
64 event_->Set();
65 }
66 rtc::Event* const event_;
67};
68
Niels Möller7dc26b72017-12-06 10:27:48 +010069class CpuOveruseDetectorProxy : public OveruseFrameDetector {
70 public:
Niels Möllerd1f7eb62018-03-28 16:40:58 +020071 explicit CpuOveruseDetectorProxy(CpuOveruseMetricsObserver* metrics_observer)
72 : OveruseFrameDetector(metrics_observer),
Niels Möller7dc26b72017-12-06 10:27:48 +010073 last_target_framerate_fps_(-1) {}
74 virtual ~CpuOveruseDetectorProxy() {}
75
76 void OnTargetFramerateUpdated(int framerate_fps) override {
77 rtc::CritScope cs(&lock_);
78 last_target_framerate_fps_ = framerate_fps;
79 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
80 }
81
82 int GetLastTargetFramerate() {
83 rtc::CritScope cs(&lock_);
84 return last_target_framerate_fps_;
85 }
86
Niels Möller4db138e2018-04-19 09:04:13 +020087 CpuOveruseOptions GetOptions() { return options_; }
88
Niels Möller7dc26b72017-12-06 10:27:48 +010089 private:
90 rtc::CriticalSection lock_;
91 int last_target_framerate_fps_ RTC_GUARDED_BY(lock_);
92};
93
mflodmancc3d4422017-08-03 08:27:51 -070094class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -070095 public:
Niels Möller213618e2018-07-24 09:29:58 +020096 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
97 const VideoStreamEncoderSettings& settings)
Yves Gerey665174f2018-06-19 15:03:05 +020098 : VideoStreamEncoder(1 /* number_of_cores */,
99 stats_proxy,
100 settings,
101 nullptr /* pre_encode_callback */,
102 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) {
perkj803d97f2016-11-01 11:45:46 -0700107 rtc::Event event(false, false);
kthelgason876222f2016-11-29 01:44:11 -0800108 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800109 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700110 event.Set();
111 });
perkj070ba852017-02-16 15:46:27 -0800112 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700113 }
114
kthelgason2fc52542017-03-03 00:24:41 -0800115 // This is used as a synchronisation mechanism, to make sure that the
116 // encoder queue is not blocked before we start sending it frames.
117 void WaitUntilTaskQueueIsIdle() {
118 rtc::Event event(false, false);
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)) {
194 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
195 nullptr, out_width, out_height),
196 99, 99, kVideoRotation_0);
197 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
198 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800199 last_width_.emplace(adapted_frame.width());
200 last_height_.emplace(adapted_frame.height());
201 } else {
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200202 last_width_ = absl::nullopt;
203 last_height_ = absl::nullopt;
sprangc5d62e22017-04-02 23:53:04 -0700204 }
sprangb1ca0732017-02-01 08:38:12 -0800205 } else {
206 test::FrameForwarder::IncomingCapturedFrame(video_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800207 last_width_.emplace(video_frame.width());
208 last_height_.emplace(video_frame.height());
sprangb1ca0732017-02-01 08:38:12 -0800209 }
210 }
211
212 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
213 const rtc::VideoSinkWants& wants) override {
214 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700215 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700216 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
217 wants.max_pixel_count,
218 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800219 test::FrameForwarder::AddOrUpdateSink(sink, wants);
220 }
sprangb1ca0732017-02-01 08:38:12 -0800221 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700222 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
223 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200224 absl::optional<int> last_width_;
225 absl::optional<int> last_height_;
sprangb1ca0732017-02-01 08:38:12 -0800226};
sprangc5d62e22017-04-02 23:53:04 -0700227
Niels Möller213618e2018-07-24 09:29:58 +0200228// TODO(nisse): Mock only VideoStreamEncoderObserver.
sprangc5d62e22017-04-02 23:53:04 -0700229class MockableSendStatisticsProxy : public SendStatisticsProxy {
230 public:
231 MockableSendStatisticsProxy(Clock* clock,
232 const VideoSendStream::Config& config,
233 VideoEncoderConfig::ContentType content_type)
234 : SendStatisticsProxy(clock, config, content_type) {}
235
236 VideoSendStream::Stats GetStats() override {
237 rtc::CritScope cs(&lock_);
238 if (mock_stats_)
239 return *mock_stats_;
240 return SendStatisticsProxy::GetStats();
241 }
242
Niels Möller213618e2018-07-24 09:29:58 +0200243 int GetInputFrameRate() const override {
244 rtc::CritScope cs(&lock_);
245 if (mock_stats_)
246 return mock_stats_->input_frame_rate;
247 return SendStatisticsProxy::GetInputFrameRate();
248 }
sprangc5d62e22017-04-02 23:53:04 -0700249 void SetMockStats(const VideoSendStream::Stats& stats) {
250 rtc::CritScope cs(&lock_);
251 mock_stats_.emplace(stats);
252 }
253
254 void ResetMockStats() {
255 rtc::CritScope cs(&lock_);
256 mock_stats_.reset();
257 }
258
259 private:
260 rtc::CriticalSection lock_;
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200261 absl::optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700262};
263
sprang4847ae62017-06-27 07:06:52 -0700264class MockBitrateObserver : public VideoBitrateAllocationObserver {
265 public:
Erik Språng566124a2018-04-23 12:32:22 +0200266 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const VideoBitrateAllocation&));
sprang4847ae62017-06-27 07:06:52 -0700267};
268
perkj803d97f2016-11-01 11:45:46 -0700269} // namespace
270
mflodmancc3d4422017-08-03 08:27:51 -0700271class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700272 public:
273 static const int kDefaultTimeoutMs = 30 * 1000;
274
mflodmancc3d4422017-08-03 08:27:51 -0700275 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700276 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700277 codec_width_(320),
278 codec_height_(240),
Åsa Persson8c1bf952018-09-13 10:42:19 +0200279 max_framerate_(kDefaultFramerate),
perkj26091b12016-09-01 01:17:40 -0700280 fake_encoder_(),
Niels Möller4db138e2018-04-19 09:04:13 +0200281 encoder_factory_(&fake_encoder_),
sprangc5d62e22017-04-02 23:53:04 -0700282 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700283 Clock::GetRealTimeClock(),
284 video_send_config_,
285 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700286 sink_(&fake_encoder_) {}
287
288 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700289 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700290 video_send_config_ = VideoSendStream::Config(nullptr);
Niels Möller4db138e2018-04-19 09:04:13 +0200291 video_send_config_.encoder_settings.encoder_factory = &encoder_factory_;
Niels Möller259a4972018-04-05 15:36:51 +0200292 video_send_config_.rtp.payload_name = "FAKE";
293 video_send_config_.rtp.payload_type = 125;
perkj26091b12016-09-01 01:17:40 -0700294
Per512ecb32016-09-23 15:52:06 +0200295 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200296 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700297 video_encoder_config.video_stream_factory =
298 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100299 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700300
301 // Framerate limit is specified by the VideoStreamFactory.
302 std::vector<VideoStream> streams =
303 video_encoder_config.video_stream_factory->CreateEncoderStreams(
304 codec_width_, codec_height_, video_encoder_config);
305 max_framerate_ = streams[0].max_framerate;
306 fake_clock_.SetTimeMicros(1234);
307
Niels Möllerf1338562018-04-26 09:51:47 +0200308 ConfigureEncoder(std::move(video_encoder_config));
asapersson5f7226f2016-11-25 04:37:00 -0800309 }
310
Niels Möllerf1338562018-04-26 09:51:47 +0200311 void ConfigureEncoder(VideoEncoderConfig video_encoder_config) {
mflodmancc3d4422017-08-03 08:27:51 -0700312 if (video_stream_encoder_)
313 video_stream_encoder_->Stop();
314 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700315 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700316 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
317 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700318 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -0700319 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
320 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200321 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -0700322 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800323 }
324
325 void ResetEncoder(const std::string& payload_name,
326 size_t num_streams,
327 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700328 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700329 bool screenshare) {
Niels Möller259a4972018-04-05 15:36:51 +0200330 video_send_config_.rtp.payload_name = payload_name;
asapersson5f7226f2016-11-25 04:37:00 -0800331
332 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200333 video_encoder_config.codec_type = PayloadStringToCodecType(payload_name);
asapersson5f7226f2016-11-25 04:37:00 -0800334 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800335 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800336 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700337 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
338 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700339 video_encoder_config.content_type =
340 screenshare ? VideoEncoderConfig::ContentType::kScreen
341 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700342 if (payload_name == "VP9") {
343 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
344 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
345 video_encoder_config.encoder_specific_settings =
346 new rtc::RefCountedObject<
347 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
348 }
Niels Möllerf1338562018-04-26 09:51:47 +0200349 ConfigureEncoder(std::move(video_encoder_config));
perkj26091b12016-09-01 01:17:40 -0700350 }
351
sprang57c2fff2017-01-16 06:24:02 -0800352 VideoFrame CreateFrame(int64_t ntp_time_ms,
353 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200354 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
355 destruction_event, codec_width_, codec_height_),
356 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800357 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700358 return frame;
359 }
360
sprang57c2fff2017-01-16 06:24:02 -0800361 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700362 VideoFrame frame(
363 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
364 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800365 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700366 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700367 return frame;
368 }
369
asapersson02465b82017-04-10 01:12:52 -0700370 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700371 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700372 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
373 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700374 }
375
asapersson09f05612017-05-15 23:40:18 -0700376 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
377 const rtc::VideoSinkWants& wants2) {
378 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
379 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
380 }
381
Åsa Persson8c1bf952018-09-13 10:42:19 +0200382 void VerifyFpsMaxResolutionMax(const rtc::VideoSinkWants& wants) {
383 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
384 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
385 EXPECT_FALSE(wants.target_pixel_count);
386 }
387
asapersson09f05612017-05-15 23:40:18 -0700388 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
389 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200390 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700391 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
392 EXPECT_GT(wants1.max_pixel_count, 0);
393 }
394
395 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
396 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200397 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700398 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
399 }
400
asaperssonf7e294d2017-06-13 23:25:22 -0700401 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
402 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200403 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700404 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
405 }
406
407 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
408 const rtc::VideoSinkWants& wants2) {
409 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
410 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
411 }
412
413 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
414 const rtc::VideoSinkWants& wants2) {
415 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
416 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
417 }
418
419 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
420 const rtc::VideoSinkWants& wants2) {
421 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
422 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
423 EXPECT_GT(wants1.max_pixel_count, 0);
424 }
425
426 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
427 const rtc::VideoSinkWants& wants2) {
428 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
429 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
430 }
431
asapersson09f05612017-05-15 23:40:18 -0700432 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
433 int pixel_count) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200434 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700435 EXPECT_LT(wants.max_pixel_count, pixel_count);
436 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700437 }
438
439 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
440 EXPECT_LT(wants.max_framerate_fps, fps);
441 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
442 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700443 }
444
asaperssonf7e294d2017-06-13 23:25:22 -0700445 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
446 int expected_fps) {
447 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
448 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
449 EXPECT_FALSE(wants.target_pixel_count);
450 }
451
Jonathan Yubc771b72017-12-08 17:04:29 -0800452 void VerifyBalancedModeFpsRange(const rtc::VideoSinkWants& wants,
453 int last_frame_pixels) {
454 // Balanced mode should always scale FPS to the desired range before
455 // attempting to scale resolution.
456 int fps_limit = wants.max_framerate_fps;
457 if (last_frame_pixels <= 320 * 240) {
458 EXPECT_TRUE(7 <= fps_limit && fps_limit <= 10);
459 } else if (last_frame_pixels <= 480 * 270) {
460 EXPECT_TRUE(10 <= fps_limit && fps_limit <= 15);
461 } else if (last_frame_pixels <= 640 * 480) {
462 EXPECT_LE(15, fps_limit);
463 } else {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200464 EXPECT_EQ(kDefaultFramerate, fps_limit);
Jonathan Yubc771b72017-12-08 17:04:29 -0800465 }
466 }
467
sprang4847ae62017-06-27 07:06:52 -0700468 void WaitForEncodedFrame(int64_t expected_ntp_time) {
469 sink_.WaitForEncodedFrame(expected_ntp_time);
470 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
471 }
472
473 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
474 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
475 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
476 return ok;
477 }
478
479 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
480 sink_.WaitForEncodedFrame(expected_width, expected_height);
481 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
482 }
483
484 void ExpectDroppedFrame() {
485 sink_.ExpectDroppedFrame();
486 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
487 }
488
489 bool WaitForFrame(int64_t timeout_ms) {
490 bool ok = sink_.WaitForFrame(timeout_ms);
491 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
492 return ok;
493 }
494
perkj26091b12016-09-01 01:17:40 -0700495 class TestEncoder : public test::FakeEncoder {
496 public:
497 TestEncoder()
498 : FakeEncoder(Clock::GetRealTimeClock()),
499 continue_encode_event_(false, false) {}
500
asaperssonfab67072017-04-04 05:51:49 -0700501 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800502 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700503 return config_;
504 }
505
506 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800507 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700508 block_next_encode_ = true;
509 }
510
Erik Språngaed30702018-11-05 12:57:17 +0100511 VideoEncoder::EncoderInfo GetEncoderInfo() const override {
512 EncoderInfo info;
kthelgason2fc52542017-03-03 00:24:41 -0800513 rtc::CritScope lock(&local_crit_sect_);
Erik Språngaed30702018-11-05 12:57:17 +0100514 if (quality_scaling_) {
515 info.scaling_settings =
516 VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
517 }
518 return info;
kthelgason876222f2016-11-29 01:44:11 -0800519 }
520
perkjfa10b552016-10-02 23:45:26 -0700521 void ContinueEncode() { continue_encode_event_.Set(); }
522
523 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
524 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800525 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700526 EXPECT_EQ(timestamp_, timestamp);
527 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
528 }
529
kthelgason2fc52542017-03-03 00:24:41 -0800530 void SetQualityScaling(bool b) {
531 rtc::CritScope lock(&local_crit_sect_);
532 quality_scaling_ = b;
533 }
kthelgasonad9010c2017-02-14 00:46:51 -0800534
sprangfe627f32017-03-29 08:24:59 -0700535 void ForceInitEncodeFailure(bool force_failure) {
536 rtc::CritScope lock(&local_crit_sect_);
537 force_init_encode_failed_ = force_failure;
538 }
539
perkjfa10b552016-10-02 23:45:26 -0700540 private:
perkj26091b12016-09-01 01:17:40 -0700541 int32_t Encode(const VideoFrame& input_image,
542 const CodecSpecificInfo* codec_specific_info,
543 const std::vector<FrameType>* frame_types) override {
544 bool block_encode;
545 {
brandtre78d2662017-01-16 05:57:16 -0800546 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700547 EXPECT_GT(input_image.timestamp(), timestamp_);
548 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
549 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
550
551 timestamp_ = input_image.timestamp();
552 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700553 last_input_width_ = input_image.width();
554 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700555 block_encode = block_next_encode_;
556 block_next_encode_ = false;
557 }
558 int32_t result =
559 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
560 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700561 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700562 return result;
563 }
564
sprangfe627f32017-03-29 08:24:59 -0700565 int32_t InitEncode(const VideoCodec* config,
566 int32_t number_of_cores,
567 size_t max_payload_size) override {
568 int res =
569 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
570 rtc::CritScope lock(&local_crit_sect_);
Erik Språng82fad3d2018-03-21 09:57:23 +0100571 if (config->codecType == kVideoCodecVP8) {
sprangfe627f32017-03-29 08:24:59 -0700572 // Simulate setting up temporal layers, in order to validate the life
573 // cycle of these objects.
574 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
sprangfe627f32017-03-29 08:24:59 -0700575 for (int i = 0; i < num_streams; ++i) {
576 allocated_temporal_layers_.emplace_back(
Erik Språng4529fbc2018-10-12 10:30:31 +0200577 CreateVp8TemporalLayers(Vp8TemporalLayersType::kFixedPattern,
578 config->VP8().numberOfTemporalLayers));
sprangfe627f32017-03-29 08:24:59 -0700579 }
580 }
581 if (force_init_encode_failed_)
582 return -1;
583 return res;
584 }
585
brandtre78d2662017-01-16 05:57:16 -0800586 rtc::CriticalSection local_crit_sect_;
danilchapa37de392017-09-09 04:17:22 -0700587 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700588 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700589 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
590 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
591 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
592 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
593 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
Erik Språng4529fbc2018-10-12 10:30:31 +0200594 std::vector<std::unique_ptr<Vp8TemporalLayers>> allocated_temporal_layers_
danilchapa37de392017-09-09 04:17:22 -0700595 RTC_GUARDED_BY(local_crit_sect_);
596 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700597 };
598
mflodmancc3d4422017-08-03 08:27:51 -0700599 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700600 public:
601 explicit TestSink(TestEncoder* test_encoder)
602 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
603
perkj26091b12016-09-01 01:17:40 -0700604 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700605 EXPECT_TRUE(
606 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
607 }
608
609 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
610 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700611 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700612 if (!encoded_frame_event_.Wait(timeout_ms))
613 return false;
perkj26091b12016-09-01 01:17:40 -0700614 {
615 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800616 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700617 }
618 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700619 return true;
perkj26091b12016-09-01 01:17:40 -0700620 }
621
sprangb1ca0732017-02-01 08:38:12 -0800622 void WaitForEncodedFrame(uint32_t expected_width,
623 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700624 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100625 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700626 }
627
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100628 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700629 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800630 uint32_t width = 0;
631 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800632 {
633 rtc::CritScope lock(&crit_);
634 width = last_width_;
635 height = last_height_;
636 }
637 EXPECT_EQ(expected_height, height);
638 EXPECT_EQ(expected_width, width);
639 }
640
kthelgason2fc52542017-03-03 00:24:41 -0800641 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800642
sprangc5d62e22017-04-02 23:53:04 -0700643 bool WaitForFrame(int64_t timeout_ms) {
644 return encoded_frame_event_.Wait(timeout_ms);
645 }
646
perkj26091b12016-09-01 01:17:40 -0700647 void SetExpectNoFrames() {
648 rtc::CritScope lock(&crit_);
649 expect_frames_ = false;
650 }
651
asaperssonfab67072017-04-04 05:51:49 -0700652 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200653 rtc::CritScope lock(&crit_);
654 return number_of_reconfigurations_;
655 }
656
asaperssonfab67072017-04-04 05:51:49 -0700657 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200658 rtc::CritScope lock(&crit_);
659 return min_transmit_bitrate_bps_;
660 }
661
perkj26091b12016-09-01 01:17:40 -0700662 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700663 Result OnEncodedImage(
664 const EncodedImage& encoded_image,
665 const CodecSpecificInfo* codec_specific_info,
666 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200667 rtc::CritScope lock(&crit_);
668 EXPECT_TRUE(expect_frames_);
Niels Möller23775882018-08-16 10:24:12 +0200669 last_timestamp_ = encoded_image.Timestamp();
sprangb1ca0732017-02-01 08:38:12 -0800670 last_width_ = encoded_image._encodedWidth;
671 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200672 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800673 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200674 }
675
676 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
677 int min_transmit_bitrate_bps) override {
678 rtc::CriticalSection crit_;
679 ++number_of_reconfigurations_;
680 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
681 }
682
perkj26091b12016-09-01 01:17:40 -0700683 rtc::CriticalSection crit_;
684 TestEncoder* test_encoder_;
685 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800686 uint32_t last_timestamp_ = 0;
687 uint32_t last_height_ = 0;
688 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700689 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200690 int number_of_reconfigurations_ = 0;
691 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700692 };
693
694 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100695 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200696 int codec_width_;
697 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700698 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700699 TestEncoder fake_encoder_;
Niels Möllercbcbc222018-09-28 09:07:24 +0200700 test::VideoEncoderProxyFactory encoder_factory_;
sprangc5d62e22017-04-02 23:53:04 -0700701 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700702 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800703 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700704 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700705 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700706};
707
mflodmancc3d4422017-08-03 08:27:51 -0700708TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
709 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700710 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700711 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700712 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700713 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700714 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700715}
716
mflodmancc3d4422017-08-03 08:27:51 -0700717TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700718 // Dropped since no target bitrate has been set.
719 rtc::Event frame_destroyed_event(false, false);
Sebastian Janssona3177052018-04-10 13:05:49 +0200720 // The encoder will cache up to one frame for a short duration. Adding two
721 // frames means that the first frame will be dropped and the second frame will
722 // be sent when the encoder is enabled.
perkja49cbd32016-09-16 07:53:41 -0700723 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
Sebastian Janssona3177052018-04-10 13:05:49 +0200724 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkja49cbd32016-09-16 07:53:41 -0700725 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700726
mflodmancc3d4422017-08-03 08:27:51 -0700727 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700728
Sebastian Janssona3177052018-04-10 13:05:49 +0200729 // The pending frame should be received.
sprang4847ae62017-06-27 07:06:52 -0700730 WaitForEncodedFrame(2);
Sebastian Janssona3177052018-04-10 13:05:49 +0200731 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
732
733 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700734 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700735}
736
mflodmancc3d4422017-08-03 08:27:51 -0700737TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
738 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700739 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700740 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700741
mflodmancc3d4422017-08-03 08:27:51 -0700742 video_stream_encoder_->OnBitrateUpdated(0, 0, 0);
Sebastian Janssona3177052018-04-10 13:05:49 +0200743 // The encoder will cache up to one frame for a short duration. Adding two
744 // frames means that the first frame will be dropped and the second frame will
745 // be sent when the encoder is resumed.
perkja49cbd32016-09-16 07:53:41 -0700746 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Sebastian Janssona3177052018-04-10 13:05:49 +0200747 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700748
mflodmancc3d4422017-08-03 08:27:51 -0700749 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -0700750 WaitForEncodedFrame(3);
Sebastian Janssona3177052018-04-10 13:05:49 +0200751 video_source_.IncomingCapturedFrame(CreateFrame(4, nullptr));
752 WaitForEncodedFrame(4);
mflodmancc3d4422017-08-03 08:27:51 -0700753 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700754}
755
mflodmancc3d4422017-08-03 08:27:51 -0700756TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
757 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700758 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700759 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700760
761 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700762 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700763
perkja49cbd32016-09-16 07:53:41 -0700764 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700765 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700766 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700767}
768
mflodmancc3d4422017-08-03 08:27:51 -0700769TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
770 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700771
perkja49cbd32016-09-16 07:53:41 -0700772 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700773 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700774
mflodmancc3d4422017-08-03 08:27:51 -0700775 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700776 sink_.SetExpectNoFrames();
777 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700778 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
779 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700780}
781
mflodmancc3d4422017-08-03 08:27:51 -0700782TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
783 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700784
785 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700786 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700787 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700788 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
789 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700790 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
791 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700792 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700793 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700794
mflodmancc3d4422017-08-03 08:27:51 -0700795 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700796}
797
mflodmancc3d4422017-08-03 08:27:51 -0700798TEST_F(VideoStreamEncoderTest,
799 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
800 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100801 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200802
803 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200804 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700805 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100806 // The encoder will have been configured once when the first frame is
807 // received.
808 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200809
810 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200811 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200812 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -0700813 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200814 kMaxPayloadLength);
Per512ecb32016-09-23 15:52:06 +0200815
816 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200817 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700818 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100819 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700820 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700821
mflodmancc3d4422017-08-03 08:27:51 -0700822 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -0700823}
824
mflodmancc3d4422017-08-03 08:27:51 -0700825TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
826 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkjfa10b552016-10-02 23:45:26 -0700827
828 // Capture a frame and wait for it to synchronize with the encoder thread.
829 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700830 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100831 // The encoder will have been configured once.
832 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700833 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
834 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
835
836 codec_width_ *= 2;
837 codec_height_ *= 2;
838 // Capture a frame with a higher resolution and wait for it to synchronize
839 // with the encoder thread.
840 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700841 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700842 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
843 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100844 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700845
mflodmancc3d4422017-08-03 08:27:51 -0700846 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -0700847}
848
mflodmancc3d4422017-08-03 08:27:51 -0700849TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -0700850 EXPECT_TRUE(video_source_.has_sinks());
851 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700852 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700853 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -0700854 EXPECT_FALSE(video_source_.has_sinks());
855 EXPECT_TRUE(new_video_source.has_sinks());
856
mflodmancc3d4422017-08-03 08:27:51 -0700857 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700858}
859
mflodmancc3d4422017-08-03 08:27:51 -0700860TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -0700861 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700862 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -0700863 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700864 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700865}
866
Jonathan Yubc771b72017-12-08 17:04:29 -0800867TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
868 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -0700869 const int kWidth = 1280;
870 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -0800871
872 // We rely on the automatic resolution adaptation, but we handle framerate
873 // adaptation manually by mocking the stats proxy.
874 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -0700875
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700876 // Enable BALANCED preference, no initial limitation.
Jonathan Yubc771b72017-12-08 17:04:29 -0800877 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700878 video_stream_encoder_->SetSource(&video_source_,
879 webrtc::DegradationPreference::BALANCED);
Jonathan Yubc771b72017-12-08 17:04:29 -0800880 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -0700881 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800882 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -0700883 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
884
Jonathan Yubc771b72017-12-08 17:04:29 -0800885 // Adapt down as far as possible.
886 rtc::VideoSinkWants last_wants;
887 int64_t t = 1;
888 int loop_count = 0;
889 do {
890 ++loop_count;
891 last_wants = video_source_.sink_wants();
892
893 // Simulate the framerate we've been asked to adapt to.
894 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
895 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
896 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
897 mock_stats.input_frame_rate = fps;
898 stats_proxy_->SetMockStats(mock_stats);
899
900 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
901 sink_.WaitForEncodedFrame(t);
902 t += frame_interval_ms;
903
mflodmancc3d4422017-08-03 08:27:51 -0700904 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -0800905 VerifyBalancedModeFpsRange(
906 video_source_.sink_wants(),
907 *video_source_.last_sent_width() * *video_source_.last_sent_height());
908 } while (video_source_.sink_wants().max_pixel_count <
909 last_wants.max_pixel_count ||
910 video_source_.sink_wants().max_framerate_fps <
911 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700912
Jonathan Yubc771b72017-12-08 17:04:29 -0800913 // Verify that we've adapted all the way down.
914 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700915 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800916 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
917 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -0700918 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -0800919 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
920 *video_source_.last_sent_height());
921 EXPECT_EQ(kMinBalancedFramerateFps,
922 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700923
Jonathan Yubc771b72017-12-08 17:04:29 -0800924 // Adapt back up the same number of times we adapted down.
925 for (int i = 0; i < loop_count - 1; ++i) {
926 last_wants = video_source_.sink_wants();
927
928 // Simulate the framerate we've been asked to adapt to.
929 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
930 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
931 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
932 mock_stats.input_frame_rate = fps;
933 stats_proxy_->SetMockStats(mock_stats);
934
935 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
936 sink_.WaitForEncodedFrame(t);
937 t += frame_interval_ms;
938
mflodmancc3d4422017-08-03 08:27:51 -0700939 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -0800940 VerifyBalancedModeFpsRange(
941 video_source_.sink_wants(),
942 *video_source_.last_sent_width() * *video_source_.last_sent_height());
943 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
944 last_wants.max_pixel_count ||
945 video_source_.sink_wants().max_framerate_fps >
946 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700947 }
948
Åsa Persson8c1bf952018-09-13 10:42:19 +0200949 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -0800950 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700951 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800952 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
953 EXPECT_EQ((loop_count - 1) * 2,
954 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -0700955
mflodmancc3d4422017-08-03 08:27:51 -0700956 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -0700957}
mflodmancc3d4422017-08-03 08:27:51 -0700958TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
959 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -0700960 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700961
sprangc5d62e22017-04-02 23:53:04 -0700962 const int kFrameWidth = 1280;
963 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -0700964
Åsa Persson8c1bf952018-09-13 10:42:19 +0200965 int64_t frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -0700966
kthelgason5e13d412016-12-01 03:59:51 -0800967 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700968 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700969 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700970 frame_timestamp += kFrameIntervalMs;
971
perkj803d97f2016-11-01 11:45:46 -0700972 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -0700973 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700974 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700975 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -0700976 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700977 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -0700978
asapersson0944a802017-04-07 00:57:58 -0700979 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -0700980 // wanted resolution.
981 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
982 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
983 kFrameWidth * kFrameHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +0200984 EXPECT_EQ(kDefaultFramerate, video_source_.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -0700985
986 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -0700987 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700988 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700989 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -0700990
sprangc5d62e22017-04-02 23:53:04 -0700991 // Initially no degradation registered.
Åsa Persson8c1bf952018-09-13 10:42:19 +0200992 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700993
sprangc5d62e22017-04-02 23:53:04 -0700994 // Force an input frame rate to be available, or the adaptation call won't
995 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -0700996 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -0700997 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -0700998 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -0700999 stats_proxy_->SetMockStats(stats);
1000
mflodmancc3d4422017-08-03 08:27:51 -07001001 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001002 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001003 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001004 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001005 frame_timestamp += kFrameIntervalMs;
1006
1007 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001008 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001009 EXPECT_EQ(std::numeric_limits<int>::max(),
1010 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001011 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001012
asapersson02465b82017-04-10 01:12:52 -07001013 // Turn off degradation completely.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001014 video_stream_encoder_->SetSource(&new_video_source,
1015 webrtc::DegradationPreference::DISABLED);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001016 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001017
mflodmancc3d4422017-08-03 08:27:51 -07001018 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001019 new_video_source.IncomingCapturedFrame(
1020 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 // Still no degradation.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001025 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001026
1027 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001028 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001029 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
sprangc5d62e22017-04-02 23:53:04 -07001030 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1031 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001032 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001033 EXPECT_EQ(kDefaultFramerate, new_video_source.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001034
1035 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001036 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001037 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001038 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1039 EXPECT_EQ(std::numeric_limits<int>::max(),
1040 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001041 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001042
mflodmancc3d4422017-08-03 08:27:51 -07001043 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001044}
1045
mflodmancc3d4422017-08-03 08:27:51 -07001046TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
1047 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001048
asaperssonfab67072017-04-04 05:51:49 -07001049 const int kWidth = 1280;
1050 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001051 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001052 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001053 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1054 EXPECT_FALSE(stats.bw_limited_resolution);
1055 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1056
1057 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001058 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001059 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001060 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001061
1062 stats = stats_proxy_->GetStats();
1063 EXPECT_TRUE(stats.bw_limited_resolution);
1064 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1065
1066 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001067 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001068 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001069 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001070
1071 stats = stats_proxy_->GetStats();
1072 EXPECT_FALSE(stats.bw_limited_resolution);
1073 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1074 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1075
mflodmancc3d4422017-08-03 08:27:51 -07001076 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001077}
1078
mflodmancc3d4422017-08-03 08:27:51 -07001079TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
1080 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001081
1082 const int kWidth = 1280;
1083 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001084 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001085 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001086 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1087 EXPECT_FALSE(stats.cpu_limited_resolution);
1088 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1089
1090 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001091 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001092 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001093 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001094
1095 stats = stats_proxy_->GetStats();
1096 EXPECT_TRUE(stats.cpu_limited_resolution);
1097 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1098
1099 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001100 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001101 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001102 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001103
1104 stats = stats_proxy_->GetStats();
1105 EXPECT_FALSE(stats.cpu_limited_resolution);
1106 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001107 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001108
mflodmancc3d4422017-08-03 08:27:51 -07001109 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001110}
1111
mflodmancc3d4422017-08-03 08:27:51 -07001112TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
1113 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001114
asaperssonfab67072017-04-04 05:51:49 -07001115 const int kWidth = 1280;
1116 const int kHeight = 720;
1117 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001118 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001119 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001120 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001121 EXPECT_FALSE(stats.cpu_limited_resolution);
1122 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1123
asaperssonfab67072017-04-04 05:51:49 -07001124 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001125 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001126 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001127 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001128 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001129 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001130 EXPECT_TRUE(stats.cpu_limited_resolution);
1131 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1132
1133 // Set new source with adaptation still enabled.
1134 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001135 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001136 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001137
asaperssonfab67072017-04-04 05:51:49 -07001138 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001139 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001140 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001141 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001142 EXPECT_TRUE(stats.cpu_limited_resolution);
1143 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1144
1145 // Set adaptation disabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001146 video_stream_encoder_->SetSource(&new_video_source,
1147 webrtc::DegradationPreference::DISABLED);
kthelgason876222f2016-11-29 01:44:11 -08001148
asaperssonfab67072017-04-04 05:51:49 -07001149 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001150 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001151 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001152 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001153 EXPECT_FALSE(stats.cpu_limited_resolution);
1154 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1155
1156 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001157 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001158 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001159
asaperssonfab67072017-04-04 05:51:49 -07001160 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001161 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001162 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001163 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001164 EXPECT_TRUE(stats.cpu_limited_resolution);
1165 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1166
asaperssonfab67072017-04-04 05:51:49 -07001167 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001168 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001169 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001170 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001171 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001172 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001173 EXPECT_FALSE(stats.cpu_limited_resolution);
1174 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001175 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001176
mflodmancc3d4422017-08-03 08:27:51 -07001177 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001178}
1179
mflodmancc3d4422017-08-03 08:27:51 -07001180TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
1181 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001182
asaperssonfab67072017-04-04 05:51:49 -07001183 const int kWidth = 1280;
1184 const int kHeight = 720;
1185 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001186 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001187 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001188 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001189 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001190 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001191
1192 // Set new source with adaptation still enabled.
1193 test::FrameForwarder new_video_source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001194 video_stream_encoder_->SetSource(&new_video_source,
1195 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001196
asaperssonfab67072017-04-04 05:51:49 -07001197 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001198 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001199 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001200 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001201 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001202 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001203
asaperssonfab67072017-04-04 05:51:49 -07001204 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001205 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001206 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001207 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001208 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001209 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001210 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001211 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001212
asaperssonfab67072017-04-04 05:51:49 -07001213 // Set new source with adaptation still enabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001214 video_stream_encoder_->SetSource(&new_video_source,
1215 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001216
asaperssonfab67072017-04-04 05:51:49 -07001217 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001218 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001219 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001220 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001221 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001222 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001223
asapersson02465b82017-04-10 01:12:52 -07001224 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001225 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001226 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001227
asaperssonfab67072017-04-04 05:51:49 -07001228 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001229 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001230 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001231 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001232 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001233 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1234 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001235
mflodmancc3d4422017-08-03 08:27:51 -07001236 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001237}
1238
mflodmancc3d4422017-08-03 08:27:51 -07001239TEST_F(VideoStreamEncoderTest,
1240 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1241 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001242
1243 const int kWidth = 1280;
1244 const int kHeight = 720;
Åsa Persson8c1bf952018-09-13 10:42:19 +02001245 int64_t timestamp_ms = kFrameIntervalMs;
asapersson36e9eb42017-03-31 05:29:12 -07001246 video_source_.set_adaptation_enabled(true);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001247 video_source_.IncomingCapturedFrame(
1248 CreateFrame(timestamp_ms, kWidth, kHeight));
1249 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001250 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1251 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1252 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1253
1254 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001255 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001256 timestamp_ms += kFrameIntervalMs;
1257 video_source_.IncomingCapturedFrame(
1258 CreateFrame(timestamp_ms, kWidth, kHeight));
1259 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001260 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1261 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1262 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1263
1264 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001265 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001266 timestamp_ms += kFrameIntervalMs;
1267 video_source_.IncomingCapturedFrame(
1268 CreateFrame(timestamp_ms, kWidth, kHeight));
1269 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001270 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1271 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1272 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1273
Niels Möller4db138e2018-04-19 09:04:13 +02001274 // Leave source unchanged, but disable quality scaler.
asapersson36e9eb42017-03-31 05:29:12 -07001275 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02001276
1277 VideoEncoderConfig video_encoder_config;
1278 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
1279 // Make format different, to force recreation of encoder.
1280 video_encoder_config.video_format.parameters["foo"] = "foo";
1281 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001282 kMaxPayloadLength);
Å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_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1289 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1290
mflodmancc3d4422017-08-03 08:27:51 -07001291 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001292}
1293
mflodmancc3d4422017-08-03 08:27:51 -07001294TEST_F(VideoStreamEncoderTest,
1295 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
1296 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001297
asapersson0944a802017-04-07 00:57:58 -07001298 const int kWidth = 1280;
1299 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001300 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001301
asaperssonfab67072017-04-04 05:51:49 -07001302 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001303 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001304 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001305 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001306 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001307 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1308
asapersson02465b82017-04-10 01:12:52 -07001309 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001310 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001311 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001312 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001313 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001314 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001315 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001316 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1317
1318 // Set new source with adaptation still enabled.
1319 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001320 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001321 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001322
1323 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001324 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001325 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001326 stats = stats_proxy_->GetStats();
1327 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001328 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001329 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1330
sprangc5d62e22017-04-02 23:53:04 -07001331 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001332 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001333 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001334 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001335 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001336 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001337 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001338 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001339 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001340 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001341 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1342
sprangc5d62e22017-04-02 23:53:04 -07001343 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001344 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001345 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1346 mock_stats.input_frame_rate = 30;
1347 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001348 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001349 stats_proxy_->ResetMockStats();
1350
1351 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001352 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001353 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001354
1355 // Framerate now adapted.
1356 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001357 EXPECT_FALSE(stats.cpu_limited_resolution);
1358 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001359 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1360
1361 // Disable CPU adaptation.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001362 video_stream_encoder_->SetSource(&new_video_source,
1363 webrtc::DegradationPreference::DISABLED);
sprangc5d62e22017-04-02 23:53:04 -07001364 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001365 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001366 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001367
1368 stats = stats_proxy_->GetStats();
1369 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001370 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001371 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1372
1373 // Try to trigger overuse. Should not succeed.
1374 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001375 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001376 stats_proxy_->ResetMockStats();
1377
1378 stats = stats_proxy_->GetStats();
1379 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001380 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001381 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1382
1383 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001384 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001385 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssonfab67072017-04-04 05:51:49 -07001386 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001387 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001388 stats = stats_proxy_->GetStats();
1389 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001390 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001391 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001392
1393 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001394 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001395 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001396 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001397 stats = stats_proxy_->GetStats();
1398 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001399 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001400 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1401
1402 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001403 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001404 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001405 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001406 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001407 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001408 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001409 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001410 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001411 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001412 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1413
1414 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001415 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001416 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001417 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001418 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001419 stats = stats_proxy_->GetStats();
1420 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001421 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001422 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001423 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001424
mflodmancc3d4422017-08-03 08:27:51 -07001425 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001426}
1427
mflodmancc3d4422017-08-03 08:27:51 -07001428TEST_F(VideoStreamEncoderTest,
1429 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001430 const int kWidth = 1280;
1431 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001432 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001433
asaperssonfab67072017-04-04 05:51:49 -07001434 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001435 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001436
asaperssonfab67072017-04-04 05:51:49 -07001437 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001438 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001439
asaperssonfab67072017-04-04 05:51:49 -07001440 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001441 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001442
asaperssonfab67072017-04-04 05:51:49 -07001443 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001444 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001445
kthelgason876222f2016-11-29 01:44:11 -08001446 // Expect a scale down.
1447 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001448 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001449
asapersson02465b82017-04-10 01:12:52 -07001450 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001451 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001452 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001453 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001454
asaperssonfab67072017-04-04 05:51:49 -07001455 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001456 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001457 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001458 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001459
asaperssonfab67072017-04-04 05:51:49 -07001460 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001461 EXPECT_EQ(std::numeric_limits<int>::max(),
1462 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001463
asaperssonfab67072017-04-04 05:51:49 -07001464 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001465 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001466 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001467 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001468
asapersson02465b82017-04-10 01:12:52 -07001469 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001470 EXPECT_EQ(std::numeric_limits<int>::max(),
1471 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001472
mflodmancc3d4422017-08-03 08:27:51 -07001473 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001474}
1475
mflodmancc3d4422017-08-03 08:27:51 -07001476TEST_F(VideoStreamEncoderTest,
1477 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001478 const int kWidth = 1280;
1479 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001480 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001481
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001482 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001483 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001484 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001485 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001486
1487 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001488 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001489 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001490 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1491 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1492
1493 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001494 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001495 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001496 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1497 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1498 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1499
1500 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001501 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001502 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1503 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1504 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1505
mflodmancc3d4422017-08-03 08:27:51 -07001506 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001507}
1508
mflodmancc3d4422017-08-03 08:27:51 -07001509TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001510 const int kWidth = 1280;
1511 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001512 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001513
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001514 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001515 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001516 video_stream_encoder_->SetSource(&source,
1517 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001518 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1519 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001520 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001521
1522 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001523 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001524 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1525 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1526 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1527 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1528
1529 // Trigger adapt down for same input resolution, expect no change.
1530 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1531 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001532 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001533 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1534 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1535 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1536
1537 // Trigger adapt down for larger input resolution, expect no change.
1538 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1539 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001540 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001541 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1542 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1543 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1544
mflodmancc3d4422017-08-03 08:27:51 -07001545 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001546}
1547
mflodmancc3d4422017-08-03 08:27:51 -07001548TEST_F(VideoStreamEncoderTest,
1549 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001550 const int kWidth = 1280;
1551 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001552 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001553
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001554 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001555 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001556 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001557 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001558
1559 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001560 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001561 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001562 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1563 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1564
1565 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001566 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001567 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001568 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1569 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1570
mflodmancc3d4422017-08-03 08:27:51 -07001571 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001572}
1573
mflodmancc3d4422017-08-03 08:27:51 -07001574TEST_F(VideoStreamEncoderTest,
1575 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001576 const int kWidth = 1280;
1577 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001578 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001579
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001580 // Enable MAINTAIN_RESOLUTION preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001581 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001582 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001583 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
asapersson02465b82017-04-10 01:12:52 -07001584
1585 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001586 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001587 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001588 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001589 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1590
1591 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001592 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001593 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001594 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001595 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1596
mflodmancc3d4422017-08-03 08:27:51 -07001597 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001598}
1599
mflodmancc3d4422017-08-03 08:27:51 -07001600TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001601 const int kWidth = 1280;
1602 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001603 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001604
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001605 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001606 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001607 video_stream_encoder_->SetSource(&source,
1608 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001609
1610 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1611 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001612 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001613 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1614 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1615 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1616
1617 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001618 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001619 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001620 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1621 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1622 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1623
mflodmancc3d4422017-08-03 08:27:51 -07001624 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001625}
1626
mflodmancc3d4422017-08-03 08:27:51 -07001627TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001628 const int kWidth = 1280;
1629 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001630 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001631
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001632 // Enable DISABLED preference, no initial limitation.
asapersson09f05612017-05-15 23:40:18 -07001633 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001634 video_stream_encoder_->SetSource(&source,
1635 webrtc::DegradationPreference::DISABLED);
asapersson09f05612017-05-15 23:40:18 -07001636
1637 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1638 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001639 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001640 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1641 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1642 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1643
1644 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001645 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001646 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001647 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1648 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1649 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1650
mflodmancc3d4422017-08-03 08:27:51 -07001651 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001652}
1653
mflodmancc3d4422017-08-03 08:27:51 -07001654TEST_F(VideoStreamEncoderTest,
1655 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001656 const int kWidth = 1280;
1657 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001658 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001659
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001660 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001661 AdaptingFrameForwarder source;
1662 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001663 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001664 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001665
1666 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001667 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001668 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001669 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1670 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1671
1672 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001673 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001674 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001675 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001676 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001677 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1678 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1679
1680 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001681 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001682 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001683 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1684 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1685 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1686
mflodmancc3d4422017-08-03 08:27:51 -07001687 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001688}
1689
mflodmancc3d4422017-08-03 08:27:51 -07001690TEST_F(VideoStreamEncoderTest,
1691 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001692 const int kWidth = 1280;
1693 const int kHeight = 720;
1694 const int kInputFps = 30;
mflodmancc3d4422017-08-03 08:27:51 -07001695 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001696
1697 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1698 stats.input_frame_rate = kInputFps;
1699 stats_proxy_->SetMockStats(stats);
1700
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001701 // Expect no scaling to begin with (preference: MAINTAIN_FRAMERATE).
asapersson09f05612017-05-15 23:40:18 -07001702 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1703 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001704 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001705
1706 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001707 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001708 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1709 sink_.WaitForEncodedFrame(2);
1710 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1711
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001712 // Enable MAINTAIN_RESOLUTION preference.
asapersson09f05612017-05-15 23:40:18 -07001713 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001714 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001715 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001716 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001717
1718 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001719 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001720 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1721 sink_.WaitForEncodedFrame(3);
1722 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1723
1724 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001725 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001726 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001727
mflodmancc3d4422017-08-03 08:27:51 -07001728 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001729}
1730
mflodmancc3d4422017-08-03 08:27:51 -07001731TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001732 const int kWidth = 1280;
1733 const int kHeight = 720;
1734 const size_t kNumFrames = 10;
1735
mflodmancc3d4422017-08-03 08:27:51 -07001736 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001737
asaperssond0de2952017-04-21 01:47:31 -07001738 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001739 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001740 video_source_.set_adaptation_enabled(true);
1741
1742 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1743 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1744
1745 int downscales = 0;
1746 for (size_t i = 1; i <= kNumFrames; i++) {
Åsa Persson8c1bf952018-09-13 10:42:19 +02001747 video_source_.IncomingCapturedFrame(
1748 CreateFrame(i * kFrameIntervalMs, kWidth, kHeight));
1749 WaitForEncodedFrame(i * kFrameIntervalMs);
asaperssond0de2952017-04-21 01:47:31 -07001750
asaperssonfab67072017-04-04 05:51:49 -07001751 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001752 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001753 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001754 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001755
1756 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1757 ++downscales;
1758
1759 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1760 EXPECT_EQ(downscales,
1761 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1762 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001763 }
mflodmancc3d4422017-08-03 08:27:51 -07001764 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001765}
1766
mflodmancc3d4422017-08-03 08:27:51 -07001767TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001768 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1769 const int kWidth = 1280;
1770 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001771 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001772
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001773 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001774 AdaptingFrameForwarder source;
1775 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001776 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001777 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001778
Åsa Persson8c1bf952018-09-13 10:42:19 +02001779 int64_t timestamp_ms = kFrameIntervalMs;
1780 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001781 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001782 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001783 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1784 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1785
1786 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001787 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001788 timestamp_ms += kFrameIntervalMs;
1789 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1790 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001791 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001792 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1793 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1794
1795 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001796 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001797 timestamp_ms += kFrameIntervalMs;
1798 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001799 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001800 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001801 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1802 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1803
1804 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001805 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001806 timestamp_ms += kFrameIntervalMs;
1807 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1808 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001809 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001810 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1811 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1812
1813 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001814 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001815 timestamp_ms += kFrameIntervalMs;
1816 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asapersson09f05612017-05-15 23:40:18 -07001817 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001818 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001819 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1820 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1821
mflodmancc3d4422017-08-03 08:27:51 -07001822 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001823}
1824
mflodmancc3d4422017-08-03 08:27:51 -07001825TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07001826 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
1827 const int kWidth = 1280;
1828 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001829 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001830
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001831 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001832 AdaptingFrameForwarder source;
1833 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001834 video_stream_encoder_->SetSource(&source,
1835 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001836
Åsa Persson8c1bf952018-09-13 10:42:19 +02001837 int64_t timestamp_ms = kFrameIntervalMs;
1838 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001839 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001840 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001841 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1842 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1843
1844 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001845 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001846 timestamp_ms += kFrameIntervalMs;
1847 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1848 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07001849 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1850 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1851 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1852
1853 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001854 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001855 timestamp_ms += kFrameIntervalMs;
1856 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001857 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001858 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001859 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1860 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1861
1862 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001863 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001864 timestamp_ms += kFrameIntervalMs;
1865 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1866 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07001867 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1868 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1869 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1870
1871 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001872 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001873 timestamp_ms += kFrameIntervalMs;
1874 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001875 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001876 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001877 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1878 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1879
mflodmancc3d4422017-08-03 08:27:51 -07001880 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001881}
1882
mflodmancc3d4422017-08-03 08:27:51 -07001883TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001884 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
1885 const int kWidth = 1280;
1886 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001887 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001888
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001889 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001890 AdaptingFrameForwarder source;
1891 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001892 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001893 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001894
Åsa Persson8c1bf952018-09-13 10:42:19 +02001895 int64_t timestamp_ms = kFrameIntervalMs;
1896 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001897 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001898 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001899 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1900 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1901 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1902 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1903
1904 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001905 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001906 timestamp_ms += kFrameIntervalMs;
1907 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1908 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001909 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001910 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1911 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1912 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1913 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1914
1915 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07001916 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001917 timestamp_ms += kFrameIntervalMs;
1918 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1919 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001920 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001921 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1922 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1923 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1924 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1925
Jonathan Yubc771b72017-12-08 17:04:29 -08001926 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001927 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001928 timestamp_ms += kFrameIntervalMs;
1929 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1930 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001931 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001932 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1933 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001934 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001935 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1936
Jonathan Yubc771b72017-12-08 17:04:29 -08001937 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07001938 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001939 timestamp_ms += kFrameIntervalMs;
1940 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1941 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001942 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001943 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07001944 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1945 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1946 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1947 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1948
Jonathan Yubc771b72017-12-08 17:04:29 -08001949 // Trigger quality adapt down, expect no change (min resolution reached).
1950 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001951 timestamp_ms += kFrameIntervalMs;
1952 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1953 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001954 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
1955 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1956 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1957 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1958 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1959
1960 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001961 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001962 timestamp_ms += kFrameIntervalMs;
1963 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1964 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001965 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001966 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1967 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1968 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1969 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1970
1971 // Trigger cpu adapt up, expect upscaled resolution (640x360).
1972 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001973 timestamp_ms += kFrameIntervalMs;
1974 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1975 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001976 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
1977 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1978 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1979 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1980 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1981
1982 // Trigger cpu adapt up, expect upscaled resolution (960x540).
1983 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001984 timestamp_ms += kFrameIntervalMs;
1985 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1986 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001987 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001988 last_wants = source.sink_wants();
1989 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1990 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001991 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001992 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1993
1994 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001995 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001996 timestamp_ms += kFrameIntervalMs;
1997 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1998 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001999 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002000 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2001 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002002 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002003 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2004
2005 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002006 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002007 timestamp_ms += kFrameIntervalMs;
2008 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002009 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002010 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002011 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002012 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2013 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002014 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002015 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002016
mflodmancc3d4422017-08-03 08:27:51 -07002017 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002018}
2019
mflodmancc3d4422017-08-03 08:27:51 -07002020TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002021 const int kWidth = 640;
2022 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002023
mflodmancc3d4422017-08-03 08:27:51 -07002024 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002025
perkj803d97f2016-11-01 11:45:46 -07002026 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002027 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002028 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002029 }
2030
mflodmancc3d4422017-08-03 08:27:51 -07002031 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002032 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002033 video_source_.IncomingCapturedFrame(CreateFrame(
2034 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002035 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002036 }
2037
mflodmancc3d4422017-08-03 08:27:51 -07002038 video_stream_encoder_->Stop();
2039 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002040 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002041
perkj803d97f2016-11-01 11:45:46 -07002042 EXPECT_EQ(1,
2043 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2044 EXPECT_EQ(
2045 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2046}
2047
mflodmancc3d4422017-08-03 08:27:51 -07002048TEST_F(VideoStreamEncoderTest,
2049 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2050 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002051 const int kWidth = 640;
2052 const int kHeight = 360;
2053
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002054 video_stream_encoder_->SetSource(&video_source_,
2055 webrtc::DegradationPreference::DISABLED);
asaperssonf4e44af2017-04-19 02:01:06 -07002056
2057 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2058 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002059 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002060 }
2061
mflodmancc3d4422017-08-03 08:27:51 -07002062 video_stream_encoder_->Stop();
2063 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002064 stats_proxy_.reset();
2065
2066 EXPECT_EQ(0,
2067 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2068}
2069
mflodmancc3d4422017-08-03 08:27:51 -07002070TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002071 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02002072 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002073
2074 const int kDefaultFps = 30;
Erik Språng566124a2018-04-23 12:32:22 +02002075 const VideoBitrateAllocation expected_bitrate =
sprang57c2fff2017-01-16 06:24:02 -08002076 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002077 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002078
2079 // First called on bitrate updated, then again on first frame.
2080 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2081 .Times(2);
mflodmancc3d4422017-08-03 08:27:51 -07002082 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002083
2084 const int64_t kStartTimeMs = 1;
2085 video_source_.IncomingCapturedFrame(
2086 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002087 WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002088
2089 // Not called on second frame.
2090 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2091 .Times(0);
2092 video_source_.IncomingCapturedFrame(
2093 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002094 WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002095
2096 // Called after a process interval.
2097 const int64_t kProcessIntervalMs =
2098 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang4847ae62017-06-27 07:06:52 -07002099 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec *
2100 (kProcessIntervalMs + (1000 / kDefaultFps)));
sprang57c2fff2017-01-16 06:24:02 -08002101 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2102 .Times(1);
2103 video_source_.IncomingCapturedFrame(CreateFrame(
2104 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002105 WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002106
mflodmancc3d4422017-08-03 08:27:51 -07002107 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002108}
2109
Niels Möller7dc26b72017-12-06 10:27:48 +01002110TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2111 const int kFrameWidth = 1280;
2112 const int kFrameHeight = 720;
2113 const int kFramerate = 24;
2114
2115 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2116 test::FrameForwarder source;
2117 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002118 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002119
2120 // Insert a single frame, triggering initial configuration.
2121 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2122 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2123
2124 EXPECT_EQ(
2125 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2126 kDefaultFramerate);
2127
2128 // Trigger reconfigure encoder (without resetting the entire instance).
2129 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002130 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002131 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2132 video_encoder_config.number_of_streams = 1;
2133 video_encoder_config.video_stream_factory =
2134 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2135 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002136 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002137 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2138
2139 // Detector should be updated with fps limit from codec config.
2140 EXPECT_EQ(
2141 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2142 kFramerate);
2143
2144 // Trigger overuse, max framerate should be reduced.
2145 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2146 stats.input_frame_rate = kFramerate;
2147 stats_proxy_->SetMockStats(stats);
2148 video_stream_encoder_->TriggerCpuOveruse();
2149 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2150 int adapted_framerate =
2151 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2152 EXPECT_LT(adapted_framerate, kFramerate);
2153
2154 // Trigger underuse, max framerate should go back to codec configured fps.
2155 // Set extra low fps, to make sure it's actually reset, not just incremented.
2156 stats = stats_proxy_->GetStats();
2157 stats.input_frame_rate = adapted_framerate / 2;
2158 stats_proxy_->SetMockStats(stats);
2159 video_stream_encoder_->TriggerCpuNormalUsage();
2160 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2161 EXPECT_EQ(
2162 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2163 kFramerate);
2164
2165 video_stream_encoder_->Stop();
2166}
2167
2168TEST_F(VideoStreamEncoderTest,
2169 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2170 const int kFrameWidth = 1280;
2171 const int kFrameHeight = 720;
2172 const int kLowFramerate = 15;
2173 const int kHighFramerate = 25;
2174
2175 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2176 test::FrameForwarder source;
2177 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002178 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002179
2180 // Trigger initial configuration.
2181 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002182 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002183 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2184 video_encoder_config.number_of_streams = 1;
2185 video_encoder_config.video_stream_factory =
2186 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2187 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2188 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002189 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002190 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2191
2192 EXPECT_EQ(
2193 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2194 kLowFramerate);
2195
2196 // Trigger overuse, max framerate should be reduced.
2197 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2198 stats.input_frame_rate = kLowFramerate;
2199 stats_proxy_->SetMockStats(stats);
2200 video_stream_encoder_->TriggerCpuOveruse();
2201 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2202 int adapted_framerate =
2203 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2204 EXPECT_LT(adapted_framerate, kLowFramerate);
2205
2206 // Reconfigure the encoder with a new (higher max framerate), max fps should
2207 // still respect the adaptation.
2208 video_encoder_config.video_stream_factory =
2209 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2210 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2211 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002212 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002213 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2214
2215 EXPECT_EQ(
2216 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2217 adapted_framerate);
2218
2219 // Trigger underuse, max framerate should go back to codec configured fps.
2220 stats = stats_proxy_->GetStats();
2221 stats.input_frame_rate = adapted_framerate;
2222 stats_proxy_->SetMockStats(stats);
2223 video_stream_encoder_->TriggerCpuNormalUsage();
2224 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2225 EXPECT_EQ(
2226 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2227 kHighFramerate);
2228
2229 video_stream_encoder_->Stop();
2230}
2231
mflodmancc3d4422017-08-03 08:27:51 -07002232TEST_F(VideoStreamEncoderTest,
2233 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002234 const int kFrameWidth = 1280;
2235 const int kFrameHeight = 720;
2236 const int kFramerate = 24;
2237
mflodmancc3d4422017-08-03 08:27:51 -07002238 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002239 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002240 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002241 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangfda496a2017-06-15 04:21:07 -07002242
2243 // Trigger initial configuration.
2244 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002245 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002246 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2247 video_encoder_config.number_of_streams = 1;
2248 video_encoder_config.video_stream_factory =
2249 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2250 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002251 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002252 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002253 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002254
Niels Möller7dc26b72017-12-06 10:27:48 +01002255 EXPECT_EQ(
2256 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2257 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002258
2259 // Trigger overuse, max framerate should be reduced.
2260 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2261 stats.input_frame_rate = kFramerate;
2262 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002263 video_stream_encoder_->TriggerCpuOveruse();
2264 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002265 int adapted_framerate =
2266 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002267 EXPECT_LT(adapted_framerate, kFramerate);
2268
2269 // Change degradation preference to not enable framerate scaling. Target
2270 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002271 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002272 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -07002273 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002274 EXPECT_EQ(
2275 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2276 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002277
mflodmancc3d4422017-08-03 08:27:51 -07002278 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002279}
2280
mflodmancc3d4422017-08-03 08:27:51 -07002281TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002282 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002283 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002284 const int kWidth = 640;
2285 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002286
asaperssonfab67072017-04-04 05:51:49 -07002287 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002288
2289 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002290 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002291
2292 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002293 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002294
sprangc5d62e22017-04-02 23:53:04 -07002295 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002296
asaperssonfab67072017-04-04 05:51:49 -07002297 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002298 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002299 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002300
2301 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002302 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002303
sprangc5d62e22017-04-02 23:53:04 -07002304 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002305
mflodmancc3d4422017-08-03 08:27:51 -07002306 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002307}
2308
mflodmancc3d4422017-08-03 08:27:51 -07002309TEST_F(VideoStreamEncoderTest,
2310 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002311 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002312 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002313 const int kWidth = 640;
2314 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002315
2316 // We expect the n initial frames to get dropped.
2317 int i;
2318 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002319 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002320 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002321 }
2322 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002323 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002324 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002325
2326 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002327 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002328
mflodmancc3d4422017-08-03 08:27:51 -07002329 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002330}
2331
mflodmancc3d4422017-08-03 08:27:51 -07002332TEST_F(VideoStreamEncoderTest,
2333 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002334 const int kWidth = 640;
2335 const int kHeight = 360;
mflodmancc3d4422017-08-03 08:27:51 -07002336 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002337
2338 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002339 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002340 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason2bc68642017-02-07 07:02:22 -08002341
asaperssonfab67072017-04-04 05:51:49 -07002342 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002343 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002344 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002345
mflodmancc3d4422017-08-03 08:27:51 -07002346 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002347}
2348
mflodmancc3d4422017-08-03 08:27:51 -07002349TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002350 const int kWidth = 640;
2351 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002352 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02002353
2354 VideoEncoderConfig video_encoder_config;
2355 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
2356 // Make format different, to force recreation of encoder.
2357 video_encoder_config.video_format.parameters["foo"] = "foo";
2358 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002359 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002360 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002361
kthelgasonb83797b2017-02-14 11:57:25 -08002362 // Force quality scaler reconfiguration by resetting the source.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002363 video_stream_encoder_->SetSource(&video_source_,
2364 webrtc::DegradationPreference::BALANCED);
kthelgasonad9010c2017-02-14 00:46:51 -08002365
asaperssonfab67072017-04-04 05:51:49 -07002366 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002367 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002368 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002369
mflodmancc3d4422017-08-03 08:27:51 -07002370 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002371 fake_encoder_.SetQualityScaling(true);
2372}
2373
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002374TEST_F(VideoStreamEncoderTest, InitialFrameDropActivatesWhenBWEstimateReady) {
2375 webrtc::test::ScopedFieldTrials field_trials(
2376 "WebRTC-InitialFramedrop/Enabled/");
2377 // Reset encoder for field trials to take effect.
2378 ConfigureEncoder(video_encoder_config_.Copy());
2379 const int kTooLowBitrateForFrameSizeBps = 10000;
2380 const int kWidth = 640;
2381 const int kHeight = 360;
2382
2383 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2384 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2385 // Frame should not be dropped.
2386 WaitForEncodedFrame(1);
2387
2388 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
2389 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
2390 // Expect to drop this frame, the wait should time out.
2391 ExpectDroppedFrame();
2392
2393 // Expect the sink_wants to specify a scaled frame.
2394 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
2395 video_stream_encoder_->Stop();
2396}
2397
mflodmancc3d4422017-08-03 08:27:51 -07002398TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002399 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2400 const int kTooSmallWidth = 10;
2401 const int kTooSmallHeight = 10;
mflodmancc3d4422017-08-03 08:27:51 -07002402 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002403
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002404 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002405 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002406 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002407 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002408 VerifyNoLimitation(source.sink_wants());
2409 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2410
2411 // Trigger adapt down, too small frame, expect no change.
2412 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002413 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002414 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002415 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002416 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2417 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2418
mflodmancc3d4422017-08-03 08:27:51 -07002419 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002420}
2421
mflodmancc3d4422017-08-03 08:27:51 -07002422TEST_F(VideoStreamEncoderTest,
2423 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002424 const int kTooSmallWidth = 10;
2425 const int kTooSmallHeight = 10;
2426 const int kFpsLimit = 7;
mflodmancc3d4422017-08-03 08:27:51 -07002427 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002428
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002429 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002430 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002431 video_stream_encoder_->SetSource(&source,
2432 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002433 VerifyNoLimitation(source.sink_wants());
2434 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2435 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2436
2437 // Trigger adapt down, expect limited framerate.
2438 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002439 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002440 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002441 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2442 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2443 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2444 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2445
2446 // Trigger adapt down, too small frame, expect no change.
2447 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002448 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002449 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002450 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2451 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2452 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2453 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2454
mflodmancc3d4422017-08-03 08:27:51 -07002455 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002456}
2457
mflodmancc3d4422017-08-03 08:27:51 -07002458TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002459 fake_encoder_.ForceInitEncodeFailure(true);
mflodmancc3d4422017-08-03 08:27:51 -07002460 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Niels Möllerf1338562018-04-26 09:51:47 +02002461 ResetEncoder("VP8", 2, 1, 1, false);
asapersson02465b82017-04-10 01:12:52 -07002462 const int kFrameWidth = 1280;
2463 const int kFrameHeight = 720;
2464 video_source_.IncomingCapturedFrame(
2465 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002466 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002467 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002468}
2469
sprangb1ca0732017-02-01 08:38:12 -08002470// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002471TEST_F(VideoStreamEncoderTest,
2472 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
2473 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002474
2475 const int kFrameWidth = 1280;
2476 const int kFrameHeight = 720;
2477 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002478 // requested by
2479 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002480 video_source_.set_adaptation_enabled(true);
2481
2482 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002483 CreateFrame(1 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002484 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002485
2486 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002487 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002488 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002489 CreateFrame(2 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002490 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002491
asaperssonfab67072017-04-04 05:51:49 -07002492 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002493 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002494 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002495 CreateFrame(3 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002496 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002497
mflodmancc3d4422017-08-03 08:27:51 -07002498 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002499}
sprangfe627f32017-03-29 08:24:59 -07002500
mflodmancc3d4422017-08-03 08:27:51 -07002501TEST_F(VideoStreamEncoderTest,
2502 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002503 const int kFrameWidth = 1280;
2504 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07002505
mflodmancc3d4422017-08-03 08:27:51 -07002506 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2507 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002508 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002509 video_source_.set_adaptation_enabled(true);
2510
sprang4847ae62017-06-27 07:06:52 -07002511 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002512
2513 video_source_.IncomingCapturedFrame(
2514 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002515 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002516
2517 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002518 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002519
2520 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002521 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002522 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002523 video_source_.IncomingCapturedFrame(
2524 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002525 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002526 }
2527
2528 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002529 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002530 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002531 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002532 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002533 video_source_.IncomingCapturedFrame(
2534 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002535 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002536 ++num_frames_dropped;
2537 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002538 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002539 }
2540 }
2541
sprang4847ae62017-06-27 07:06:52 -07002542 // Add some slack to account for frames dropped by the frame dropper.
2543 const int kErrorMargin = 1;
2544 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002545 kErrorMargin);
2546
2547 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002548 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002549 num_frames_dropped = 0;
Åsa Persson8c1bf952018-09-13 10:42:19 +02002550 for (int i = 0; i <= max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002551 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002552 video_source_.IncomingCapturedFrame(
2553 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002554 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002555 ++num_frames_dropped;
2556 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002557 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002558 }
2559 }
sprang4847ae62017-06-27 07:06:52 -07002560 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002561 kErrorMargin);
2562
2563 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002564 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002565 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002566 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002567 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002568 video_source_.IncomingCapturedFrame(
2569 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002570 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002571 ++num_frames_dropped;
2572 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002573 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002574 }
2575 }
sprang4847ae62017-06-27 07:06:52 -07002576 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002577 kErrorMargin);
2578
2579 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002580 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002581 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002582 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002583 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002584 video_source_.IncomingCapturedFrame(
2585 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002586 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002587 ++num_frames_dropped;
2588 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002589 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002590 }
2591 }
2592 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2593
mflodmancc3d4422017-08-03 08:27:51 -07002594 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002595}
2596
mflodmancc3d4422017-08-03 08:27:51 -07002597TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002598 const int kFramerateFps = 5;
2599 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002600 const int kFrameWidth = 1280;
2601 const int kFrameHeight = 720;
2602
sprang4847ae62017-06-27 07:06:52 -07002603 // Reconfigure encoder with two temporal layers and screensharing, which will
2604 // disable frame dropping and make testing easier.
Niels Möllerf1338562018-04-26 09:51:47 +02002605 ResetEncoder("VP8", 1, 2, 1, true);
sprang4847ae62017-06-27 07:06:52 -07002606
mflodmancc3d4422017-08-03 08:27:51 -07002607 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2608 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002609 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002610 video_source_.set_adaptation_enabled(true);
2611
sprang4847ae62017-06-27 07:06:52 -07002612 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002613
2614 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08002615 rtc::VideoSinkWants last_wants;
2616 do {
2617 last_wants = video_source_.sink_wants();
2618
sprangc5d62e22017-04-02 23:53:04 -07002619 // Insert frames to get a new fps estimate...
2620 for (int j = 0; j < kFramerateFps; ++j) {
2621 video_source_.IncomingCapturedFrame(
2622 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08002623 if (video_source_.last_sent_width()) {
2624 sink_.WaitForEncodedFrame(timestamp_ms);
2625 }
sprangc5d62e22017-04-02 23:53:04 -07002626 timestamp_ms += kFrameIntervalMs;
Yves Gerey665174f2018-06-19 15:03:05 +02002627 fake_clock_.AdvanceTimeMicros(kFrameIntervalMs *
2628 rtc::kNumMicrosecsPerMillisec);
sprangc5d62e22017-04-02 23:53:04 -07002629 }
2630 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002631 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08002632 } while (video_source_.sink_wants().max_framerate_fps <
2633 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07002634
Jonathan Yubc771b72017-12-08 17:04:29 -08002635 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07002636
mflodmancc3d4422017-08-03 08:27:51 -07002637 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002638}
asaperssonf7e294d2017-06-13 23:25:22 -07002639
mflodmancc3d4422017-08-03 08:27:51 -07002640TEST_F(VideoStreamEncoderTest,
2641 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002642 const int kWidth = 1280;
2643 const int kHeight = 720;
2644 const int64_t kFrameIntervalMs = 150;
2645 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002646 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002647
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002648 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002649 AdaptingFrameForwarder source;
2650 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002651 video_stream_encoder_->SetSource(&source,
2652 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002653 timestamp_ms += kFrameIntervalMs;
2654 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002655 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002656 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002657 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2658 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2659 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2660
2661 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002662 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002663 timestamp_ms += kFrameIntervalMs;
2664 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002665 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002666 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2667 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2668 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2669 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2670
2671 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002672 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002673 timestamp_ms += kFrameIntervalMs;
2674 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002675 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002676 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2677 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2678 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2679 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2680
2681 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002682 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002683 timestamp_ms += kFrameIntervalMs;
2684 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002685 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002686 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2687 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2688 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2689 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2690
2691 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002692 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002693 timestamp_ms += kFrameIntervalMs;
2694 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002695 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002696 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2697 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2698 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2699 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2700
2701 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002702 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002703 timestamp_ms += kFrameIntervalMs;
2704 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002705 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002706 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2707 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2708 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2709 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2710
2711 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002712 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002713 timestamp_ms += kFrameIntervalMs;
2714 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002715 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002716 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2717 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2718 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2719 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2720
2721 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002722 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002723 timestamp_ms += kFrameIntervalMs;
2724 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002725 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002726 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2727 rtc::VideoSinkWants last_wants = source.sink_wants();
2728 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2729 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2730 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2731
2732 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002733 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002734 timestamp_ms += kFrameIntervalMs;
2735 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002736 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002737 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2738 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2739 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2740 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2741
2742 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002743 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002744 timestamp_ms += kFrameIntervalMs;
2745 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002746 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002747 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2748 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2749 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2750 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2751
2752 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002753 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002754 timestamp_ms += kFrameIntervalMs;
2755 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002756 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002757 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2758 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2759 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2760 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2761
2762 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002763 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002764 timestamp_ms += kFrameIntervalMs;
2765 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002766 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002767 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2768 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2769 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2770 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2771
2772 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002773 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002774 timestamp_ms += kFrameIntervalMs;
2775 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002776 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002777 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2778 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2779 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2780 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2781
2782 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002783 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002784 timestamp_ms += kFrameIntervalMs;
2785 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002786 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002787 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2788 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2789 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2790 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2791
2792 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002793 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002794 timestamp_ms += kFrameIntervalMs;
2795 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002796 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002797 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2798 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2799 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2800 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2801
2802 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002803 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002804 timestamp_ms += kFrameIntervalMs;
2805 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002806 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002807 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002808 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002809 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2810 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2811 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2812
2813 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002814 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002815 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002816 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2817
mflodmancc3d4422017-08-03 08:27:51 -07002818 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002819}
2820
mflodmancc3d4422017-08-03 08:27:51 -07002821TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07002822 const int kWidth = 1280;
2823 const int kHeight = 720;
2824 const int64_t kFrameIntervalMs = 150;
2825 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002826 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002827
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002828 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002829 AdaptingFrameForwarder source;
2830 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002831 video_stream_encoder_->SetSource(&source,
2832 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002833 timestamp_ms += kFrameIntervalMs;
2834 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002835 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002836 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002837 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2838 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2839 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2840 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2841 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2842 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2843
2844 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002845 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002846 timestamp_ms += kFrameIntervalMs;
2847 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002848 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002849 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2850 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2851 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2852 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2853 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2854 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2855 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2856
2857 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002858 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002859 timestamp_ms += kFrameIntervalMs;
2860 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002861 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002862 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2863 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2864 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2865 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2866 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2867 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2868 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2869
2870 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002871 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002872 timestamp_ms += kFrameIntervalMs;
2873 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002874 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002875 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2876 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2877 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2878 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2879 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2880 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2881 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2882
2883 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002884 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002885 timestamp_ms += kFrameIntervalMs;
2886 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002887 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002888 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2889 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2890 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2891 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2892 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2893 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2894 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2895
2896 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002897 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002898 timestamp_ms += kFrameIntervalMs;
2899 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002900 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002901 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2902 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2903 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2904 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2905 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2906 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2907 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2908
2909 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002910 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002911 timestamp_ms += kFrameIntervalMs;
2912 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002913 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002914 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002915 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002916 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2917 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2918 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2919 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2920 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2921 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2922
2923 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002924 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002925 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002926 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2927 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2928
mflodmancc3d4422017-08-03 08:27:51 -07002929 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002930}
2931
mflodmancc3d4422017-08-03 08:27:51 -07002932TEST_F(VideoStreamEncoderTest,
2933 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07002934 const int kWidth = 640;
2935 const int kHeight = 360;
2936 const int kFpsLimit = 15;
2937 const int64_t kFrameIntervalMs = 150;
2938 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002939 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002940
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002941 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002942 AdaptingFrameForwarder source;
2943 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002944 video_stream_encoder_->SetSource(&source,
2945 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002946 timestamp_ms += kFrameIntervalMs;
2947 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002948 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002949 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002950 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2951 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2952 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2953 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2954 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2955 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2956
2957 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002958 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002959 timestamp_ms += kFrameIntervalMs;
2960 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002961 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002962 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2963 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2964 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2965 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2966 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2967 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2968 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2969
2970 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002971 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002972 timestamp_ms += kFrameIntervalMs;
2973 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002974 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002975 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2976 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2977 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2978 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2979 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2980 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2981 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2982
2983 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002984 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002985 timestamp_ms += kFrameIntervalMs;
2986 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002987 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002988 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2989 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2990 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2991 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2992 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2993 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2994 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2995
2996 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002997 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002998 timestamp_ms += kFrameIntervalMs;
2999 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003000 WaitForEncodedFrame(timestamp_ms);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003001 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003002 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3003 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3004 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3005 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3006 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3007 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3008
3009 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003010 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003011 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003012 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3013 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3014
mflodmancc3d4422017-08-03 08:27:51 -07003015 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003016}
3017
mflodmancc3d4422017-08-03 08:27:51 -07003018TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003019 // Simulates simulcast behavior and makes highest stream resolutions divisible
3020 // by 4.
3021 class CroppingVideoStreamFactory
3022 : public VideoEncoderConfig::VideoStreamFactoryInterface {
3023 public:
3024 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
3025 int framerate)
3026 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
3027 EXPECT_GT(num_temporal_layers, 0u);
3028 EXPECT_GT(framerate, 0);
3029 }
3030
3031 private:
3032 std::vector<VideoStream> CreateEncoderStreams(
3033 int width,
3034 int height,
3035 const VideoEncoderConfig& encoder_config) override {
Yves Gerey665174f2018-06-19 15:03:05 +02003036 std::vector<VideoStream> streams = test::CreateVideoStreams(
3037 width - width % 4, height - height % 4, encoder_config);
ilnik6b826ef2017-06-16 06:53:48 -07003038 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +01003039 stream.num_temporal_layers = num_temporal_layers_;
ilnik6b826ef2017-06-16 06:53:48 -07003040 stream.max_framerate = framerate_;
3041 }
3042 return streams;
3043 }
3044
3045 const size_t num_temporal_layers_;
3046 const int framerate_;
3047 };
3048
3049 const int kFrameWidth = 1920;
3050 const int kFrameHeight = 1080;
3051 // 3/4 of 1920.
3052 const int kAdaptedFrameWidth = 1440;
3053 // 3/4 of 1080 rounded down to multiple of 4.
3054 const int kAdaptedFrameHeight = 808;
3055 const int kFramerate = 24;
3056
mflodmancc3d4422017-08-03 08:27:51 -07003057 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003058 // Trigger reconfigure encoder (without resetting the entire instance).
3059 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02003060 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07003061 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3062 video_encoder_config.number_of_streams = 1;
3063 video_encoder_config.video_stream_factory =
3064 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003065 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02003066 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07003067 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003068
3069 video_source_.set_adaptation_enabled(true);
3070
3071 video_source_.IncomingCapturedFrame(
3072 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003073 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003074
3075 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003076 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003077 video_source_.IncomingCapturedFrame(
3078 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003079 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003080
mflodmancc3d4422017-08-03 08:27:51 -07003081 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003082}
3083
mflodmancc3d4422017-08-03 08:27:51 -07003084TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003085 const int kFrameWidth = 1280;
3086 const int kFrameHeight = 720;
3087 const int kLowFps = 2;
3088 const int kHighFps = 30;
3089
mflodmancc3d4422017-08-03 08:27:51 -07003090 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003091
3092 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3093 max_framerate_ = kLowFps;
3094
3095 // Insert 2 seconds of 2fps video.
3096 for (int i = 0; i < kLowFps * 2; ++i) {
3097 video_source_.IncomingCapturedFrame(
3098 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3099 WaitForEncodedFrame(timestamp_ms);
3100 timestamp_ms += 1000 / kLowFps;
3101 }
3102
3103 // Make sure encoder is updated with new target.
mflodmancc3d4422017-08-03 08:27:51 -07003104 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003105 video_source_.IncomingCapturedFrame(
3106 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3107 WaitForEncodedFrame(timestamp_ms);
3108 timestamp_ms += 1000 / kLowFps;
3109
3110 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3111
3112 // Insert 30fps frames for just a little more than the forced update period.
3113 const int kVcmTimerIntervalFrames =
3114 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3115 const int kFrameIntervalMs = 1000 / kHighFps;
3116 max_framerate_ = kHighFps;
3117 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3118 video_source_.IncomingCapturedFrame(
3119 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3120 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3121 // be dropped if the encoder hans't been updated with the new higher target
3122 // framerate yet, causing it to overshoot the target bitrate and then
3123 // suffering the wrath of the media optimizer.
3124 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3125 timestamp_ms += kFrameIntervalMs;
3126 }
3127
3128 // Don expect correct measurement just yet, but it should be higher than
3129 // before.
3130 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3131
mflodmancc3d4422017-08-03 08:27:51 -07003132 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003133}
3134
mflodmancc3d4422017-08-03 08:27:51 -07003135TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003136 const int kFrameWidth = 1280;
3137 const int kFrameHeight = 720;
3138 const int kTargetBitrateBps = 1000000;
3139
3140 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02003141 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang4847ae62017-06-27 07:06:52 -07003142
3143 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3144 // Initial bitrate update.
mflodmancc3d4422017-08-03 08:27:51 -07003145 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3146 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003147
3148 // Insert a first video frame, causes another bitrate update.
3149 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3150 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3151 video_source_.IncomingCapturedFrame(
3152 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3153 WaitForEncodedFrame(timestamp_ms);
3154
3155 // Next, simulate video suspension due to pacer queue overrun.
mflodmancc3d4422017-08-03 08:27:51 -07003156 video_stream_encoder_->OnBitrateUpdated(0, 0, 1);
sprang4847ae62017-06-27 07:06:52 -07003157
3158 // Skip ahead until a new periodic parameter update should have occured.
3159 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3160 fake_clock_.AdvanceTimeMicros(
3161 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3162 rtc::kNumMicrosecsPerMillisec);
3163
3164 // Bitrate observer should not be called.
3165 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3166 video_source_.IncomingCapturedFrame(
3167 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3168 ExpectDroppedFrame();
3169
mflodmancc3d4422017-08-03 08:27:51 -07003170 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003171}
ilnik6b826ef2017-06-16 06:53:48 -07003172
Niels Möller4db138e2018-04-19 09:04:13 +02003173TEST_F(VideoStreamEncoderTest,
3174 DefaultCpuAdaptationThresholdsForSoftwareEncoder) {
3175 const int kFrameWidth = 1280;
3176 const int kFrameHeight = 720;
3177 const CpuOveruseOptions default_options;
3178 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3179 video_source_.IncomingCapturedFrame(
3180 CreateFrame(1, kFrameWidth, kFrameHeight));
3181 WaitForEncodedFrame(1);
3182 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3183 .low_encode_usage_threshold_percent,
3184 default_options.low_encode_usage_threshold_percent);
3185 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3186 .high_encode_usage_threshold_percent,
3187 default_options.high_encode_usage_threshold_percent);
3188 video_stream_encoder_->Stop();
3189}
3190
3191TEST_F(VideoStreamEncoderTest,
3192 HigherCpuAdaptationThresholdsForHardwareEncoder) {
3193 const int kFrameWidth = 1280;
3194 const int kFrameHeight = 720;
3195 CpuOveruseOptions hardware_options;
3196 hardware_options.low_encode_usage_threshold_percent = 150;
3197 hardware_options.high_encode_usage_threshold_percent = 200;
3198 encoder_factory_.SetIsHardwareAccelerated(true);
3199
3200 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3201 video_source_.IncomingCapturedFrame(
3202 CreateFrame(1, kFrameWidth, kFrameHeight));
3203 WaitForEncodedFrame(1);
3204 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3205 .low_encode_usage_threshold_percent,
3206 hardware_options.low_encode_usage_threshold_percent);
3207 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3208 .high_encode_usage_threshold_percent,
3209 hardware_options.high_encode_usage_threshold_percent);
3210 video_stream_encoder_->Stop();
3211}
3212
perkj26091b12016-09-01 01:17:40 -07003213} // namespace webrtc