blob: 09d259abf52814ec657ba064a37d4646c92e5a2b [file] [log] [blame]
perkj26091b12016-09-01 01:17:40 -07001/*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
sprangfe627f32017-03-29 08:24:59 -070011#include <algorithm>
perkj803d97f2016-11-01 11:45:46 -070012#include <limits>
Per512ecb32016-09-23 15:52:06 +020013#include <utility>
14
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "api/video/i420_buffer.h"
16#include "media/base/videoadapter.h"
17#include "modules/video_coding/codecs/vp8/temporal_layers.h"
Sergey Silkin86684962018-03-28 19:32:37 +020018#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
20#include "rtc_base/fakeclock.h"
21#include "rtc_base/logging.h"
22#include "system_wrappers/include/metrics_default.h"
23#include "system_wrappers/include/sleep.h"
24#include "test/encoder_settings.h"
25#include "test/fake_encoder.h"
26#include "test/frame_generator.h"
27#include "test/gmock.h"
28#include "test/gtest.h"
29#include "video/send_statistics_proxy.h"
30#include "video/video_stream_encoder.h"
perkj26091b12016-09-01 01:17:40 -070031
kthelgason33ce8892016-12-09 03:53:59 -080032namespace {
kthelgason33ce8892016-12-09 03:53:59 -080033const int kMinPixelsPerFrame = 320 * 180;
sprangc5d62e22017-04-02 23:53:04 -070034const int kMinFramerateFps = 2;
Jonathan Yubc771b72017-12-08 17:04:29 -080035const int kMinBalancedFramerateFps = 7;
sprangc5d62e22017-04-02 23:53:04 -070036const int64_t kFrameTimeoutMs = 100;
emircanbbcc3562017-08-18 00:28:40 -070037const unsigned char kNumSlDummy = 0;
sprangc5d62e22017-04-02 23:53:04 -070038} // namespace
kthelgason33ce8892016-12-09 03:53:59 -080039
perkj26091b12016-09-01 01:17:40 -070040namespace webrtc {
41
kthelgason876222f2016-11-29 01:44:11 -080042using DegredationPreference = VideoSendStream::DegradationPreference;
sprangb1ca0732017-02-01 08:38:12 -080043using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080044using ::testing::_;
45using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080046
perkj803d97f2016-11-01 11:45:46 -070047namespace {
asapersson5f7226f2016-11-25 04:37:00 -080048const size_t kMaxPayloadLength = 1440;
kthelgason2bc68642017-02-07 07:02:22 -080049const int kTargetBitrateBps = 1000000;
50const int kLowTargetBitrateBps = kTargetBitrateBps / 10;
51const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070052const int kDefaultFramerate = 30;
asapersson5f7226f2016-11-25 04:37:00 -080053
perkj803d97f2016-11-01 11:45:46 -070054class TestBuffer : public webrtc::I420Buffer {
55 public:
56 TestBuffer(rtc::Event* event, int width, int height)
57 : I420Buffer(width, height), event_(event) {}
58
59 private:
60 friend class rtc::RefCountedObject<TestBuffer>;
61 ~TestBuffer() override {
62 if (event_)
63 event_->Set();
64 }
65 rtc::Event* const event_;
66};
67
Niels Möller7dc26b72017-12-06 10:27:48 +010068class CpuOveruseDetectorProxy : public OveruseFrameDetector {
69 public:
Niels Möllerd1f7eb62018-03-28 16:40:58 +020070 explicit CpuOveruseDetectorProxy(CpuOveruseMetricsObserver* metrics_observer)
71 : OveruseFrameDetector(metrics_observer),
Niels Möller7dc26b72017-12-06 10:27:48 +010072 last_target_framerate_fps_(-1) {}
73 virtual ~CpuOveruseDetectorProxy() {}
74
75 void OnTargetFramerateUpdated(int framerate_fps) override {
76 rtc::CritScope cs(&lock_);
77 last_target_framerate_fps_ = framerate_fps;
78 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
79 }
80
81 int GetLastTargetFramerate() {
82 rtc::CritScope cs(&lock_);
83 return last_target_framerate_fps_;
84 }
85
86 private:
87 rtc::CriticalSection lock_;
88 int last_target_framerate_fps_ RTC_GUARDED_BY(lock_);
89};
90
mflodmancc3d4422017-08-03 08:27:51 -070091class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -070092 public:
Niels Möller7dc26b72017-12-06 10:27:48 +010093 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
94 const VideoSendStream::Config::EncoderSettings& settings)
mflodmancc3d4422017-08-03 08:27:51 -070095 : VideoStreamEncoder(
96 1 /* number_of_cores */,
97 stats_proxy,
98 settings,
99 nullptr /* pre_encode_callback */,
mflodmancc3d4422017-08-03 08:27:51 -0700100 std::unique_ptr<OveruseFrameDetector>(
Niels Möller7dc26b72017-12-06 10:27:48 +0100101 overuse_detector_proxy_ = new CpuOveruseDetectorProxy(
mflodmancc3d4422017-08-03 08:27:51 -0700102 stats_proxy))) {}
perkj803d97f2016-11-01 11:45:46 -0700103
sprangb1ca0732017-02-01 08:38:12 -0800104 void PostTaskAndWait(bool down, AdaptReason reason) {
perkj803d97f2016-11-01 11:45:46 -0700105 rtc::Event event(false, false);
kthelgason876222f2016-11-29 01:44:11 -0800106 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800107 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700108 event.Set();
109 });
perkj070ba852017-02-16 15:46:27 -0800110 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700111 }
112
kthelgason2fc52542017-03-03 00:24:41 -0800113 // This is used as a synchronisation mechanism, to make sure that the
114 // encoder queue is not blocked before we start sending it frames.
115 void WaitUntilTaskQueueIsIdle() {
116 rtc::Event event(false, false);
117 encoder_queue()->PostTask([&event] {
118 event.Set();
119 });
120 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
ilnik6b826ef2017-06-16 06:53:48 -0700161
sprangb1ca0732017-02-01 08:38:12 -0800162class AdaptingFrameForwarder : public test::FrameForwarder {
163 public:
164 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700165 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800166
167 void set_adaptation_enabled(bool enabled) {
168 rtc::CritScope cs(&crit_);
169 adaptation_enabled_ = enabled;
170 }
171
asaperssonfab67072017-04-04 05:51:49 -0700172 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800173 rtc::CritScope cs(&crit_);
174 return adaptation_enabled_;
175 }
176
asapersson09f05612017-05-15 23:40:18 -0700177 rtc::VideoSinkWants last_wants() const {
178 rtc::CritScope cs(&crit_);
179 return last_wants_;
180 }
181
Jonathan Yubc771b72017-12-08 17:04:29 -0800182 rtc::Optional<int> last_sent_width() const { return last_width_; }
183 rtc::Optional<int> last_sent_height() const { return last_height_; }
184
sprangb1ca0732017-02-01 08:38:12 -0800185 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
186 int cropped_width = 0;
187 int cropped_height = 0;
188 int out_width = 0;
189 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700190 if (adaption_enabled()) {
191 if (adapter_.AdaptFrameResolution(
192 video_frame.width(), video_frame.height(),
193 video_frame.timestamp_us() * 1000, &cropped_width,
194 &cropped_height, &out_width, &out_height)) {
195 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
196 nullptr, out_width, out_height),
197 99, 99, kVideoRotation_0);
198 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
199 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800200 last_width_.emplace(adapted_frame.width());
201 last_height_.emplace(adapted_frame.height());
202 } else {
203 last_width_ = rtc::nullopt;
204 last_height_ = rtc::nullopt;
sprangc5d62e22017-04-02 23:53:04 -0700205 }
sprangb1ca0732017-02-01 08:38:12 -0800206 } else {
207 test::FrameForwarder::IncomingCapturedFrame(video_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800208 last_width_.emplace(video_frame.width());
209 last_height_.emplace(video_frame.height());
sprangb1ca0732017-02-01 08:38:12 -0800210 }
211 }
212
213 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
214 const rtc::VideoSinkWants& wants) override {
215 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700216 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700217 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
218 wants.max_pixel_count,
219 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800220 test::FrameForwarder::AddOrUpdateSink(sink, wants);
221 }
sprangb1ca0732017-02-01 08:38:12 -0800222 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700223 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
224 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
Jonathan Yubc771b72017-12-08 17:04:29 -0800225 rtc::Optional<int> last_width_;
226 rtc::Optional<int> last_height_;
sprangb1ca0732017-02-01 08:38:12 -0800227};
sprangc5d62e22017-04-02 23:53:04 -0700228
229class 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
243 void SetMockStats(const VideoSendStream::Stats& stats) {
244 rtc::CritScope cs(&lock_);
245 mock_stats_.emplace(stats);
246 }
247
248 void ResetMockStats() {
249 rtc::CritScope cs(&lock_);
250 mock_stats_.reset();
251 }
252
253 private:
254 rtc::CriticalSection lock_;
danilchapa37de392017-09-09 04:17:22 -0700255 rtc::Optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700256};
257
sprang4847ae62017-06-27 07:06:52 -0700258class MockBitrateObserver : public VideoBitrateAllocationObserver {
259 public:
260 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const BitrateAllocation&));
261};
262
perkj803d97f2016-11-01 11:45:46 -0700263} // namespace
264
mflodmancc3d4422017-08-03 08:27:51 -0700265class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700266 public:
267 static const int kDefaultTimeoutMs = 30 * 1000;
268
mflodmancc3d4422017-08-03 08:27:51 -0700269 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700270 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700271 codec_width_(320),
272 codec_height_(240),
sprang4847ae62017-06-27 07:06:52 -0700273 max_framerate_(30),
perkj26091b12016-09-01 01:17:40 -0700274 fake_encoder_(),
sprangc5d62e22017-04-02 23:53:04 -0700275 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700276 Clock::GetRealTimeClock(),
277 video_send_config_,
278 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700279 sink_(&fake_encoder_) {}
280
281 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700282 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700283 video_send_config_ = VideoSendStream::Config(nullptr);
284 video_send_config_.encoder_settings.encoder = &fake_encoder_;
Niels Möller259a4972018-04-05 15:36:51 +0200285 video_send_config_.rtp.payload_name = "FAKE";
286 video_send_config_.rtp.payload_type = 125;
perkj26091b12016-09-01 01:17:40 -0700287
Per512ecb32016-09-23 15:52:06 +0200288 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200289 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700290 video_encoder_config.video_stream_factory =
291 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100292 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700293
294 // Framerate limit is specified by the VideoStreamFactory.
295 std::vector<VideoStream> streams =
296 video_encoder_config.video_stream_factory->CreateEncoderStreams(
297 codec_width_, codec_height_, video_encoder_config);
298 max_framerate_ = streams[0].max_framerate;
299 fake_clock_.SetTimeMicros(1234);
300
asapersson5f7226f2016-11-25 04:37:00 -0800301 ConfigureEncoder(std::move(video_encoder_config), true /* nack_enabled */);
302 }
303
304 void ConfigureEncoder(VideoEncoderConfig video_encoder_config,
305 bool nack_enabled) {
mflodmancc3d4422017-08-03 08:27:51 -0700306 if (video_stream_encoder_)
307 video_stream_encoder_->Stop();
308 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700309 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700310 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
311 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -0700312 &video_source_,
313 VideoSendStream::DegradationPreference::kMaintainFramerate);
mflodmancc3d4422017-08-03 08:27:51 -0700314 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
315 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
316 kMaxPayloadLength, nack_enabled);
317 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800318 }
319
320 void ResetEncoder(const std::string& payload_name,
321 size_t num_streams,
322 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700323 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700324 bool nack_enabled,
325 bool screenshare) {
Niels Möller259a4972018-04-05 15:36:51 +0200326 video_send_config_.rtp.payload_name = payload_name;
asapersson5f7226f2016-11-25 04:37:00 -0800327
328 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200329 video_encoder_config.codec_type = PayloadStringToCodecType(payload_name);
asapersson5f7226f2016-11-25 04:37:00 -0800330 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800331 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800332 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700333 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
334 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700335 video_encoder_config.content_type =
336 screenshare ? VideoEncoderConfig::ContentType::kScreen
337 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700338 if (payload_name == "VP9") {
339 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
340 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
341 video_encoder_config.encoder_specific_settings =
342 new rtc::RefCountedObject<
343 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
344 }
asapersson5f7226f2016-11-25 04:37:00 -0800345 ConfigureEncoder(std::move(video_encoder_config), nack_enabled);
perkj26091b12016-09-01 01:17:40 -0700346 }
347
sprang57c2fff2017-01-16 06:24:02 -0800348 VideoFrame CreateFrame(int64_t ntp_time_ms,
349 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200350 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
351 destruction_event, codec_width_, codec_height_),
352 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800353 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700354 return frame;
355 }
356
sprang57c2fff2017-01-16 06:24:02 -0800357 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700358 VideoFrame frame(
359 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
360 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800361 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700362 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700363 return frame;
364 }
365
asapersson02465b82017-04-10 01:12:52 -0700366 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700367 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700368 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
369 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700370 }
371
asapersson09f05612017-05-15 23:40:18 -0700372 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
373 const rtc::VideoSinkWants& wants2) {
374 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
375 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
376 }
377
378 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
379 const rtc::VideoSinkWants& wants2) {
380 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
381 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
382 EXPECT_GT(wants1.max_pixel_count, 0);
383 }
384
385 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
386 const rtc::VideoSinkWants& wants2) {
387 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
388 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
389 }
390
asaperssonf7e294d2017-06-13 23:25:22 -0700391 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
392 const rtc::VideoSinkWants& wants2) {
393 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
394 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
395 }
396
397 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
398 const rtc::VideoSinkWants& wants2) {
399 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
400 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
401 }
402
403 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
404 const rtc::VideoSinkWants& wants2) {
405 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
406 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
407 }
408
409 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
410 const rtc::VideoSinkWants& wants2) {
411 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
412 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
413 EXPECT_GT(wants1.max_pixel_count, 0);
414 }
415
416 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
417 const rtc::VideoSinkWants& wants2) {
418 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
419 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
420 }
421
asapersson09f05612017-05-15 23:40:18 -0700422 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
423 int pixel_count) {
424 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700425 EXPECT_LT(wants.max_pixel_count, pixel_count);
426 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700427 }
428
429 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
430 EXPECT_LT(wants.max_framerate_fps, fps);
431 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
432 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700433 }
434
asaperssonf7e294d2017-06-13 23:25:22 -0700435 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
436 int expected_fps) {
437 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
438 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
439 EXPECT_FALSE(wants.target_pixel_count);
440 }
441
Jonathan Yubc771b72017-12-08 17:04:29 -0800442 void VerifyBalancedModeFpsRange(const rtc::VideoSinkWants& wants,
443 int last_frame_pixels) {
444 // Balanced mode should always scale FPS to the desired range before
445 // attempting to scale resolution.
446 int fps_limit = wants.max_framerate_fps;
447 if (last_frame_pixels <= 320 * 240) {
448 EXPECT_TRUE(7 <= fps_limit && fps_limit <= 10);
449 } else if (last_frame_pixels <= 480 * 270) {
450 EXPECT_TRUE(10 <= fps_limit && fps_limit <= 15);
451 } else if (last_frame_pixels <= 640 * 480) {
452 EXPECT_LE(15, fps_limit);
453 } else {
454 EXPECT_EQ(std::numeric_limits<int>::max(), fps_limit);
455 }
456 }
457
sprang4847ae62017-06-27 07:06:52 -0700458 void WaitForEncodedFrame(int64_t expected_ntp_time) {
459 sink_.WaitForEncodedFrame(expected_ntp_time);
460 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
461 }
462
463 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
464 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
465 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
466 return ok;
467 }
468
469 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
470 sink_.WaitForEncodedFrame(expected_width, expected_height);
471 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
472 }
473
474 void ExpectDroppedFrame() {
475 sink_.ExpectDroppedFrame();
476 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
477 }
478
479 bool WaitForFrame(int64_t timeout_ms) {
480 bool ok = sink_.WaitForFrame(timeout_ms);
481 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
482 return ok;
483 }
484
perkj26091b12016-09-01 01:17:40 -0700485 class TestEncoder : public test::FakeEncoder {
486 public:
487 TestEncoder()
488 : FakeEncoder(Clock::GetRealTimeClock()),
489 continue_encode_event_(false, false) {}
490
asaperssonfab67072017-04-04 05:51:49 -0700491 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800492 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700493 return config_;
494 }
495
496 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800497 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700498 block_next_encode_ = true;
499 }
500
kthelgason876222f2016-11-29 01:44:11 -0800501 VideoEncoder::ScalingSettings GetScalingSettings() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800502 rtc::CritScope lock(&local_crit_sect_);
kthelgasonad9010c2017-02-14 00:46:51 -0800503 if (quality_scaling_)
Niels Möller225c7872018-02-22 15:03:53 +0100504 return VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
505 return VideoEncoder::ScalingSettings::kOff;
kthelgason876222f2016-11-29 01:44:11 -0800506 }
507
perkjfa10b552016-10-02 23:45:26 -0700508 void ContinueEncode() { continue_encode_event_.Set(); }
509
510 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
511 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800512 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700513 EXPECT_EQ(timestamp_, timestamp);
514 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
515 }
516
kthelgason2fc52542017-03-03 00:24:41 -0800517 void SetQualityScaling(bool b) {
518 rtc::CritScope lock(&local_crit_sect_);
519 quality_scaling_ = b;
520 }
kthelgasonad9010c2017-02-14 00:46:51 -0800521
sprangfe627f32017-03-29 08:24:59 -0700522 void ForceInitEncodeFailure(bool force_failure) {
523 rtc::CritScope lock(&local_crit_sect_);
524 force_init_encode_failed_ = force_failure;
525 }
526
perkjfa10b552016-10-02 23:45:26 -0700527 private:
perkj26091b12016-09-01 01:17:40 -0700528 int32_t Encode(const VideoFrame& input_image,
529 const CodecSpecificInfo* codec_specific_info,
530 const std::vector<FrameType>* frame_types) override {
531 bool block_encode;
532 {
brandtre78d2662017-01-16 05:57:16 -0800533 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700534 EXPECT_GT(input_image.timestamp(), timestamp_);
535 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
536 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
537
538 timestamp_ = input_image.timestamp();
539 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700540 last_input_width_ = input_image.width();
541 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700542 block_encode = block_next_encode_;
543 block_next_encode_ = false;
544 }
545 int32_t result =
546 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
547 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700548 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700549 return result;
550 }
551
sprangfe627f32017-03-29 08:24:59 -0700552 int32_t InitEncode(const VideoCodec* config,
553 int32_t number_of_cores,
554 size_t max_payload_size) override {
555 int res =
556 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
557 rtc::CritScope lock(&local_crit_sect_);
Erik Språng82fad3d2018-03-21 09:57:23 +0100558 if (config->codecType == kVideoCodecVP8) {
sprangfe627f32017-03-29 08:24:59 -0700559 // Simulate setting up temporal layers, in order to validate the life
560 // cycle of these objects.
561 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
sprangfe627f32017-03-29 08:24:59 -0700562 for (int i = 0; i < num_streams; ++i) {
563 allocated_temporal_layers_.emplace_back(
Niels Möller150dcb02018-03-27 14:16:55 +0200564 TemporalLayers::CreateTemporalLayers(*config, i));
sprangfe627f32017-03-29 08:24:59 -0700565 }
566 }
567 if (force_init_encode_failed_)
568 return -1;
569 return res;
570 }
571
brandtre78d2662017-01-16 05:57:16 -0800572 rtc::CriticalSection local_crit_sect_;
danilchapa37de392017-09-09 04:17:22 -0700573 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700574 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700575 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
576 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
577 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
578 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
579 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
sprangfe627f32017-03-29 08:24:59 -0700580 std::vector<std::unique_ptr<TemporalLayers>> allocated_temporal_layers_
danilchapa37de392017-09-09 04:17:22 -0700581 RTC_GUARDED_BY(local_crit_sect_);
582 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700583 };
584
mflodmancc3d4422017-08-03 08:27:51 -0700585 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700586 public:
587 explicit TestSink(TestEncoder* test_encoder)
588 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
589
perkj26091b12016-09-01 01:17:40 -0700590 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700591 EXPECT_TRUE(
592 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
593 }
594
595 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
596 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700597 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700598 if (!encoded_frame_event_.Wait(timeout_ms))
599 return false;
perkj26091b12016-09-01 01:17:40 -0700600 {
601 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800602 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700603 }
604 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700605 return true;
perkj26091b12016-09-01 01:17:40 -0700606 }
607
sprangb1ca0732017-02-01 08:38:12 -0800608 void WaitForEncodedFrame(uint32_t expected_width,
609 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700610 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100611 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700612 }
613
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100614 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700615 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800616 uint32_t width = 0;
617 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800618 {
619 rtc::CritScope lock(&crit_);
620 width = last_width_;
621 height = last_height_;
622 }
623 EXPECT_EQ(expected_height, height);
624 EXPECT_EQ(expected_width, width);
625 }
626
kthelgason2fc52542017-03-03 00:24:41 -0800627 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800628
sprangc5d62e22017-04-02 23:53:04 -0700629 bool WaitForFrame(int64_t timeout_ms) {
630 return encoded_frame_event_.Wait(timeout_ms);
631 }
632
perkj26091b12016-09-01 01:17:40 -0700633 void SetExpectNoFrames() {
634 rtc::CritScope lock(&crit_);
635 expect_frames_ = false;
636 }
637
asaperssonfab67072017-04-04 05:51:49 -0700638 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200639 rtc::CritScope lock(&crit_);
640 return number_of_reconfigurations_;
641 }
642
asaperssonfab67072017-04-04 05:51:49 -0700643 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200644 rtc::CritScope lock(&crit_);
645 return min_transmit_bitrate_bps_;
646 }
647
perkj26091b12016-09-01 01:17:40 -0700648 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700649 Result OnEncodedImage(
650 const EncodedImage& encoded_image,
651 const CodecSpecificInfo* codec_specific_info,
652 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200653 rtc::CritScope lock(&crit_);
654 EXPECT_TRUE(expect_frames_);
sprangb1ca0732017-02-01 08:38:12 -0800655 last_timestamp_ = encoded_image._timeStamp;
656 last_width_ = encoded_image._encodedWidth;
657 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200658 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800659 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200660 }
661
662 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
663 int min_transmit_bitrate_bps) override {
664 rtc::CriticalSection crit_;
665 ++number_of_reconfigurations_;
666 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
667 }
668
perkj26091b12016-09-01 01:17:40 -0700669 rtc::CriticalSection crit_;
670 TestEncoder* test_encoder_;
671 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800672 uint32_t last_timestamp_ = 0;
673 uint32_t last_height_ = 0;
674 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700675 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200676 int number_of_reconfigurations_ = 0;
677 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700678 };
679
680 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100681 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200682 int codec_width_;
683 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700684 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700685 TestEncoder fake_encoder_;
sprangc5d62e22017-04-02 23:53:04 -0700686 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700687 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800688 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700689 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700690 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700691};
692
mflodmancc3d4422017-08-03 08:27:51 -0700693TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
694 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700695 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700696 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700697 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700698 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700699 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700700}
701
mflodmancc3d4422017-08-03 08:27:51 -0700702TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700703 // Dropped since no target bitrate has been set.
704 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700705 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
706 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700707
mflodmancc3d4422017-08-03 08:27:51 -0700708 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700709
perkja49cbd32016-09-16 07:53:41 -0700710 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700711 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700712 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700713}
714
mflodmancc3d4422017-08-03 08:27:51 -0700715TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
716 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700717 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700718 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700719
mflodmancc3d4422017-08-03 08:27:51 -0700720 video_stream_encoder_->OnBitrateUpdated(0, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700721 // Dropped since bitrate is zero.
perkja49cbd32016-09-16 07:53:41 -0700722 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkj26091b12016-09-01 01:17:40 -0700723
mflodmancc3d4422017-08-03 08:27:51 -0700724 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700725 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700726 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700727 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700728}
729
mflodmancc3d4422017-08-03 08:27:51 -0700730TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
731 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700732 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700733 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700734
735 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700736 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700737
perkja49cbd32016-09-16 07:53:41 -0700738 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700739 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700740 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700741}
742
mflodmancc3d4422017-08-03 08:27:51 -0700743TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
744 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700745
perkja49cbd32016-09-16 07:53:41 -0700746 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700747 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700748
mflodmancc3d4422017-08-03 08:27:51 -0700749 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700750 sink_.SetExpectNoFrames();
751 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700752 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
753 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700754}
755
mflodmancc3d4422017-08-03 08:27:51 -0700756TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
757 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700758
759 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700760 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700761 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700762 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
763 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700764 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
765 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700766 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700767 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700768
mflodmancc3d4422017-08-03 08:27:51 -0700769 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700770}
771
mflodmancc3d4422017-08-03 08:27:51 -0700772TEST_F(VideoStreamEncoderTest,
773 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
774 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100775 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200776
777 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200778 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700779 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100780 // The encoder will have been configured once when the first frame is
781 // received.
782 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200783
784 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200785 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200786 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -0700787 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
788 kMaxPayloadLength,
789 true /* nack_enabled */);
Per512ecb32016-09-23 15:52:06 +0200790
791 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200792 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700793 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100794 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700795 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700796
mflodmancc3d4422017-08-03 08:27:51 -0700797 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -0700798}
799
mflodmancc3d4422017-08-03 08:27:51 -0700800TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
801 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkjfa10b552016-10-02 23:45:26 -0700802
803 // Capture a frame and wait for it to synchronize with the encoder thread.
804 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.
807 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700808 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
809 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
810
811 codec_width_ *= 2;
812 codec_height_ *= 2;
813 // Capture a frame with a higher resolution and wait for it to synchronize
814 // with the encoder thread.
815 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700816 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700817 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
818 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100819 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700820
mflodmancc3d4422017-08-03 08:27:51 -0700821 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -0700822}
823
mflodmancc3d4422017-08-03 08:27:51 -0700824TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOffFor1S1TLWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800825 const bool kNackEnabled = true;
826 const size_t kNumStreams = 1;
827 const size_t kNumTl = 1;
emircanbbcc3562017-08-18 00:28:40 -0700828 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700829 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800830
831 // Capture a frame and wait for it to synchronize with the encoder thread.
832 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700833 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800834 // The encoder have been configured once when the first frame is received.
835 EXPECT_EQ(1, sink_.number_of_reconfigurations());
836 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
837 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
838 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
839 // Resilience is off for no temporal layers with nack on.
840 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700841 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800842}
843
mflodmancc3d4422017-08-03 08:27:51 -0700844TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOffFor2S1TlWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800845 const bool kNackEnabled = true;
846 const size_t kNumStreams = 2;
847 const size_t kNumTl = 1;
emircanbbcc3562017-08-18 00:28:40 -0700848 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700849 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800850
851 // Capture a frame and wait for it to synchronize with the encoder thread.
852 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700853 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800854 // The encoder have been configured once when the first frame is received.
855 EXPECT_EQ(1, sink_.number_of_reconfigurations());
856 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
857 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
858 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
859 // Resilience is off for no temporal layers and >1 streams with nack on.
860 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700861 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800862}
863
mflodmancc3d4422017-08-03 08:27:51 -0700864TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOnFor1S1TLWithNackDisabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800865 const bool kNackEnabled = false;
866 const size_t kNumStreams = 1;
867 const size_t kNumTl = 1;
emircanbbcc3562017-08-18 00:28:40 -0700868 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700869 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800870
871 // Capture a frame and wait for it to synchronize with the encoder thread.
872 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700873 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800874 // The encoder have been configured once when the first frame is received.
875 EXPECT_EQ(1, sink_.number_of_reconfigurations());
876 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
877 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
878 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
879 // Resilience is on for no temporal layers with nack off.
880 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700881 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800882}
883
mflodmancc3d4422017-08-03 08:27:51 -0700884TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOnFor1S2TlWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800885 const bool kNackEnabled = true;
886 const size_t kNumStreams = 1;
887 const size_t kNumTl = 2;
emircanbbcc3562017-08-18 00:28:40 -0700888 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700889 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800890
891 // Capture a frame and wait for it to synchronize with the encoder thread.
892 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700893 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800894 // The encoder have been configured once when the first frame is received.
895 EXPECT_EQ(1, sink_.number_of_reconfigurations());
896 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
897 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
898 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
899 // Resilience is on for temporal layers.
900 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700901 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800902}
903
emircanbbcc3562017-08-18 00:28:40 -0700904TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOffFor1SL1TLWithNackEnabled) {
905 const bool kNackEnabled = true;
906 const size_t kNumStreams = 1;
907 const size_t kNumTl = 1;
908 const unsigned char kNumSl = 1;
909 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
910 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
911
912 // Capture a frame and wait for it to synchronize with the encoder thread.
913 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
914 sink_.WaitForEncodedFrame(1);
915 // The encoder have been configured once when the first frame is received.
916 EXPECT_EQ(1, sink_.number_of_reconfigurations());
917 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
918 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
919 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
920 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
921 // Resilience is off for no spatial and temporal layers with nack on.
922 EXPECT_FALSE(fake_encoder_.codec_config().VP9()->resilienceOn);
923 video_stream_encoder_->Stop();
924}
925
926TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOnFor1SL1TLWithNackDisabled) {
927 const bool kNackEnabled = false;
928 const size_t kNumStreams = 1;
929 const size_t kNumTl = 1;
930 const unsigned char kNumSl = 1;
931 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
932 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
933
934 // Capture a frame and wait for it to synchronize with the encoder thread.
935 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
936 sink_.WaitForEncodedFrame(1);
937 // The encoder have been configured once when the first frame is received.
938 EXPECT_EQ(1, sink_.number_of_reconfigurations());
939 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
940 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
941 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
942 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
943 // Resilience is on if nack is off.
944 EXPECT_TRUE(fake_encoder_.codec_config().VP9()->resilienceOn);
945 video_stream_encoder_->Stop();
946}
947
948TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOnFor2SL1TLWithNackEnabled) {
949 const bool kNackEnabled = true;
950 const size_t kNumStreams = 1;
951 const size_t kNumTl = 1;
952 const unsigned char kNumSl = 2;
Sergey Silkin86684962018-03-28 19:32:37 +0200953 const int kFrameWidth = kMinVp9SpatialLayerWidth << (kNumSl - 1);
954 const int kFrameHeight = kMinVp9SpatialLayerHeight << (kNumSl - 1);
emircanbbcc3562017-08-18 00:28:40 -0700955 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
956 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
957
958 // Capture a frame and wait for it to synchronize with the encoder thread.
Sergey Silkin86684962018-03-28 19:32:37 +0200959 video_source_.IncomingCapturedFrame(
960 CreateFrame(1, kFrameWidth, kFrameHeight));
emircanbbcc3562017-08-18 00:28:40 -0700961 sink_.WaitForEncodedFrame(1);
962 // The encoder have been configured once when the first frame is received.
963 EXPECT_EQ(1, sink_.number_of_reconfigurations());
964 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
965 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
966 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
967 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
968 // Resilience is on for spatial layers.
969 EXPECT_TRUE(fake_encoder_.codec_config().VP9()->resilienceOn);
970 video_stream_encoder_->Stop();
971}
972
973TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOnFor1SL2TLWithNackEnabled) {
974 const bool kNackEnabled = true;
975 const size_t kNumStreams = 1;
976 const size_t kNumTl = 2;
977 const unsigned char kNumSl = 1;
978 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
979 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
980
981 // Capture a frame and wait for it to synchronize with the encoder thread.
982 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
983 sink_.WaitForEncodedFrame(1);
984 // The encoder have been configured once when the first frame is received.
985 EXPECT_EQ(1, sink_.number_of_reconfigurations());
986 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
987 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
988 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
989 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
990 // Resilience is on for temporal layers.
991 EXPECT_TRUE(fake_encoder_.codec_config().VP9()->resilienceOn);
992 video_stream_encoder_->Stop();
993}
994
mflodmancc3d4422017-08-03 08:27:51 -0700995TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -0700996 EXPECT_TRUE(video_source_.has_sinks());
997 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700998 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -0700999 &new_video_source,
1000 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001001 EXPECT_FALSE(video_source_.has_sinks());
1002 EXPECT_TRUE(new_video_source.has_sinks());
1003
mflodmancc3d4422017-08-03 08:27:51 -07001004 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001005}
1006
mflodmancc3d4422017-08-03 08:27:51 -07001007TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -07001008 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -07001009 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -07001010 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -07001011 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001012}
1013
Jonathan Yubc771b72017-12-08 17:04:29 -08001014TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
1015 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -07001016 const int kWidth = 1280;
1017 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -08001018
1019 // We rely on the automatic resolution adaptation, but we handle framerate
1020 // adaptation manually by mocking the stats proxy.
1021 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -07001022
1023 // Enable kBalanced preference, no initial limitation.
Jonathan Yubc771b72017-12-08 17:04:29 -08001024 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -07001025 video_stream_encoder_->SetSource(
Jonathan Yubc771b72017-12-08 17:04:29 -08001026 &video_source_,
mflodmancc3d4422017-08-03 08:27:51 -07001027 VideoSendStream::DegradationPreference::kBalanced);
Jonathan Yubc771b72017-12-08 17:04:29 -08001028 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001029 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001030 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -07001031 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1032
Jonathan Yubc771b72017-12-08 17:04:29 -08001033 // Adapt down as far as possible.
1034 rtc::VideoSinkWants last_wants;
1035 int64_t t = 1;
1036 int loop_count = 0;
1037 do {
1038 ++loop_count;
1039 last_wants = video_source_.sink_wants();
1040
1041 // Simulate the framerate we've been asked to adapt to.
1042 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
1043 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
1044 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1045 mock_stats.input_frame_rate = fps;
1046 stats_proxy_->SetMockStats(mock_stats);
1047
1048 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1049 sink_.WaitForEncodedFrame(t);
1050 t += frame_interval_ms;
1051
mflodmancc3d4422017-08-03 08:27:51 -07001052 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08001053 VerifyBalancedModeFpsRange(
1054 video_source_.sink_wants(),
1055 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1056 } while (video_source_.sink_wants().max_pixel_count <
1057 last_wants.max_pixel_count ||
1058 video_source_.sink_wants().max_framerate_fps <
1059 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001060
Jonathan Yubc771b72017-12-08 17:04:29 -08001061 // Verify that we've adapted all the way down.
1062 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001063 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001064 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
1065 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -07001066 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -08001067 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
1068 *video_source_.last_sent_height());
1069 EXPECT_EQ(kMinBalancedFramerateFps,
1070 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001071
Jonathan Yubc771b72017-12-08 17:04:29 -08001072 // Adapt back up the same number of times we adapted down.
1073 for (int i = 0; i < loop_count - 1; ++i) {
1074 last_wants = video_source_.sink_wants();
1075
1076 // Simulate the framerate we've been asked to adapt to.
1077 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
1078 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
1079 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1080 mock_stats.input_frame_rate = fps;
1081 stats_proxy_->SetMockStats(mock_stats);
1082
1083 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1084 sink_.WaitForEncodedFrame(t);
1085 t += frame_interval_ms;
1086
mflodmancc3d4422017-08-03 08:27:51 -07001087 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -08001088 VerifyBalancedModeFpsRange(
1089 video_source_.sink_wants(),
1090 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1091 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
1092 last_wants.max_pixel_count ||
1093 video_source_.sink_wants().max_framerate_fps >
1094 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001095 }
1096
Jonathan Yubc771b72017-12-08 17:04:29 -08001097 VerifyNoLimitation(video_source_.sink_wants());
1098 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001099 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001100 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1101 EXPECT_EQ((loop_count - 1) * 2,
1102 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -07001103
mflodmancc3d4422017-08-03 08:27:51 -07001104 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001105}
mflodmancc3d4422017-08-03 08:27:51 -07001106TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
1107 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001108 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001109
sprangc5d62e22017-04-02 23:53:04 -07001110 const int kFrameWidth = 1280;
1111 const int kFrameHeight = 720;
1112 const int kFrameIntervalMs = 1000 / 30;
1113
1114 int frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -07001115
kthelgason5e13d412016-12-01 03:59:51 -08001116 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001117 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001118 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001119 frame_timestamp += kFrameIntervalMs;
1120
perkj803d97f2016-11-01 11:45:46 -07001121 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001122 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001123 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001124 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001125 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001126 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -07001127
asapersson0944a802017-04-07 00:57:58 -07001128 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -07001129 // wanted resolution.
1130 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
1131 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
1132 kFrameWidth * kFrameHeight);
1133 EXPECT_EQ(std::numeric_limits<int>::max(),
1134 video_source_.sink_wants().max_framerate_fps);
1135
1136 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -07001137 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001138 video_stream_encoder_->SetSource(
perkj803d97f2016-11-01 11:45:46 -07001139 &new_video_source,
1140 VideoSendStream::DegradationPreference::kMaintainResolution);
1141
sprangc5d62e22017-04-02 23:53:04 -07001142 // Initially no degradation registered.
asapersson02465b82017-04-10 01:12:52 -07001143 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001144
sprangc5d62e22017-04-02 23:53:04 -07001145 // Force an input frame rate to be available, or the adaptation call won't
1146 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -07001147 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -07001148 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -07001149 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -07001150 stats_proxy_->SetMockStats(stats);
1151
mflodmancc3d4422017-08-03 08:27:51 -07001152 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001153 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001154 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001155 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001156 frame_timestamp += kFrameIntervalMs;
1157
1158 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001159 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001160 EXPECT_EQ(std::numeric_limits<int>::max(),
1161 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001162 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001163
asapersson02465b82017-04-10 01:12:52 -07001164 // Turn off degradation completely.
mflodmancc3d4422017-08-03 08:27:51 -07001165 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001166 &new_video_source,
1167 VideoSendStream::DegradationPreference::kDegradationDisabled);
asapersson02465b82017-04-10 01:12:52 -07001168 VerifyNoLimitation(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001169
mflodmancc3d4422017-08-03 08:27:51 -07001170 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001171 new_video_source.IncomingCapturedFrame(
1172 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001173 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001174 frame_timestamp += kFrameIntervalMs;
1175
1176 // Still no degradation.
asapersson02465b82017-04-10 01:12:52 -07001177 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001178
1179 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001180 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001181 &new_video_source,
1182 VideoSendStream::DegradationPreference::kMaintainFramerate);
1183 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1184 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001185 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001186 EXPECT_EQ(std::numeric_limits<int>::max(),
1187 new_video_source.sink_wants().max_framerate_fps);
1188
1189 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001190 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001191 &new_video_source,
1192 VideoSendStream::DegradationPreference::kMaintainResolution);
1193 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1194 EXPECT_EQ(std::numeric_limits<int>::max(),
1195 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001196 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001197
mflodmancc3d4422017-08-03 08:27:51 -07001198 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001199}
1200
mflodmancc3d4422017-08-03 08:27:51 -07001201TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
1202 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001203
asaperssonfab67072017-04-04 05:51:49 -07001204 const int kWidth = 1280;
1205 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001206 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001207 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001208 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1209 EXPECT_FALSE(stats.bw_limited_resolution);
1210 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1211
1212 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001213 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001214 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001215 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001216
1217 stats = stats_proxy_->GetStats();
1218 EXPECT_TRUE(stats.bw_limited_resolution);
1219 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1220
1221 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001222 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001223 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001224 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001225
1226 stats = stats_proxy_->GetStats();
1227 EXPECT_FALSE(stats.bw_limited_resolution);
1228 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1229 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1230
mflodmancc3d4422017-08-03 08:27:51 -07001231 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001232}
1233
mflodmancc3d4422017-08-03 08:27:51 -07001234TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
1235 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001236
1237 const int kWidth = 1280;
1238 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001239 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001240 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001241 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1242 EXPECT_FALSE(stats.cpu_limited_resolution);
1243 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1244
1245 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001246 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001247 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001248 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001249
1250 stats = stats_proxy_->GetStats();
1251 EXPECT_TRUE(stats.cpu_limited_resolution);
1252 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1253
1254 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001255 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001256 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001257 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001258
1259 stats = stats_proxy_->GetStats();
1260 EXPECT_FALSE(stats.cpu_limited_resolution);
1261 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001262 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001263
mflodmancc3d4422017-08-03 08:27:51 -07001264 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001265}
1266
mflodmancc3d4422017-08-03 08:27:51 -07001267TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
1268 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001269
asaperssonfab67072017-04-04 05:51:49 -07001270 const int kWidth = 1280;
1271 const int kHeight = 720;
1272 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001273 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001274 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001275 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001276 EXPECT_FALSE(stats.cpu_limited_resolution);
1277 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1278
asaperssonfab67072017-04-04 05:51:49 -07001279 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001280 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001281 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001282 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001283 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001284 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001285 EXPECT_TRUE(stats.cpu_limited_resolution);
1286 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1287
1288 // Set new source with adaptation still enabled.
1289 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001290 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001291 &new_video_source,
1292 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001293
asaperssonfab67072017-04-04 05:51:49 -07001294 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001295 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001296 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001297 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001298 EXPECT_TRUE(stats.cpu_limited_resolution);
1299 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1300
1301 // Set adaptation disabled.
mflodmancc3d4422017-08-03 08:27:51 -07001302 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001303 &new_video_source,
sprangc5d62e22017-04-02 23:53:04 -07001304 VideoSendStream::DegradationPreference::kDegradationDisabled);
kthelgason876222f2016-11-29 01:44:11 -08001305
asaperssonfab67072017-04-04 05:51:49 -07001306 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001307 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001308 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001309 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001310 EXPECT_FALSE(stats.cpu_limited_resolution);
1311 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1312
1313 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001314 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001315 &new_video_source,
1316 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001317
asaperssonfab67072017-04-04 05:51:49 -07001318 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001319 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001320 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001321 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001322 EXPECT_TRUE(stats.cpu_limited_resolution);
1323 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1324
asaperssonfab67072017-04-04 05:51:49 -07001325 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001326 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001327 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001328 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001329 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001330 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001331 EXPECT_FALSE(stats.cpu_limited_resolution);
1332 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001333 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001334
mflodmancc3d4422017-08-03 08:27:51 -07001335 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001336}
1337
mflodmancc3d4422017-08-03 08:27:51 -07001338TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
1339 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001340
asaperssonfab67072017-04-04 05:51:49 -07001341 const int kWidth = 1280;
1342 const int kHeight = 720;
1343 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001344 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001345 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001346 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001347 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001348 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001349
1350 // Set new source with adaptation still enabled.
1351 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001352 video_stream_encoder_->SetSource(
1353 &new_video_source,
1354 VideoSendStream::DegradationPreference::kBalanced);
kthelgason876222f2016-11-29 01:44:11 -08001355
asaperssonfab67072017-04-04 05:51:49 -07001356 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001357 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001358 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001359 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001360 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001361 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001362
asaperssonfab67072017-04-04 05:51:49 -07001363 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001364 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001365 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001366 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001367 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001368 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001369 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001370 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001371
asaperssonfab67072017-04-04 05:51:49 -07001372 // Set new source with adaptation still enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001373 video_stream_encoder_->SetSource(
1374 &new_video_source,
1375 VideoSendStream::DegradationPreference::kBalanced);
kthelgason876222f2016-11-29 01:44:11 -08001376
asaperssonfab67072017-04-04 05:51:49 -07001377 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001378 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001379 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001380 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001381 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001382 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001383
asapersson02465b82017-04-10 01:12:52 -07001384 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001385 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001386 &new_video_source,
1387 VideoSendStream::DegradationPreference::kMaintainResolution);
1388
asaperssonfab67072017-04-04 05:51:49 -07001389 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001390 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001391 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001392 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001393 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001394 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1395 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001396
mflodmancc3d4422017-08-03 08:27:51 -07001397 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001398}
1399
mflodmancc3d4422017-08-03 08:27:51 -07001400TEST_F(VideoStreamEncoderTest,
1401 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1402 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001403
1404 const int kWidth = 1280;
1405 const int kHeight = 720;
1406 video_source_.set_adaptation_enabled(true);
1407 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001408 WaitForEncodedFrame(1);
asapersson36e9eb42017-03-31 05:29:12 -07001409 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1410 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1411 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1412
1413 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001414 video_stream_encoder_->TriggerQualityLow();
asapersson36e9eb42017-03-31 05:29:12 -07001415 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001416 WaitForEncodedFrame(2);
asapersson36e9eb42017-03-31 05:29:12 -07001417 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1418 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1419 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1420
1421 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001422 video_stream_encoder_->TriggerCpuOveruse();
asapersson36e9eb42017-03-31 05:29:12 -07001423 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001424 WaitForEncodedFrame(3);
asapersson36e9eb42017-03-31 05:29:12 -07001425 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1426 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1427 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1428
1429 // Set source with adaptation still enabled but quality scaler is off.
1430 fake_encoder_.SetQualityScaling(false);
mflodmancc3d4422017-08-03 08:27:51 -07001431 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001432 &video_source_,
1433 VideoSendStream::DegradationPreference::kMaintainFramerate);
asapersson36e9eb42017-03-31 05:29:12 -07001434
1435 video_source_.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001436 WaitForEncodedFrame(4);
asapersson36e9eb42017-03-31 05:29:12 -07001437 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1438 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1439 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1440
mflodmancc3d4422017-08-03 08:27:51 -07001441 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001442}
1443
mflodmancc3d4422017-08-03 08:27:51 -07001444TEST_F(VideoStreamEncoderTest,
1445 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
1446 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001447
asapersson0944a802017-04-07 00:57:58 -07001448 const int kWidth = 1280;
1449 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001450 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001451
asaperssonfab67072017-04-04 05:51:49 -07001452 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001453 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001454 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001455 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001456 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001457 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1458
asapersson02465b82017-04-10 01:12:52 -07001459 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001460 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001461 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001462 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001463 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001464 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001465 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001466 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1467
1468 // Set new source with adaptation still enabled.
1469 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001470 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001471 &new_video_source,
1472 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001473
1474 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001475 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001476 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001477 stats = stats_proxy_->GetStats();
1478 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001479 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001480 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1481
sprangc5d62e22017-04-02 23:53:04 -07001482 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001483 video_stream_encoder_->SetSource(
perkj803d97f2016-11-01 11:45:46 -07001484 &new_video_source,
1485 VideoSendStream::DegradationPreference::kMaintainResolution);
1486 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001487 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001488 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001489 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001490 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001491 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001492 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001493 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1494
sprangc5d62e22017-04-02 23:53:04 -07001495 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001496 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001497 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1498 mock_stats.input_frame_rate = 30;
1499 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001500 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001501 stats_proxy_->ResetMockStats();
1502
1503 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001504 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001505 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001506
1507 // Framerate now adapted.
1508 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001509 EXPECT_FALSE(stats.cpu_limited_resolution);
1510 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001511 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1512
1513 // Disable CPU adaptation.
mflodmancc3d4422017-08-03 08:27:51 -07001514 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001515 &new_video_source,
1516 VideoSendStream::DegradationPreference::kDegradationDisabled);
1517 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001518 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001519 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001520
1521 stats = stats_proxy_->GetStats();
1522 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001523 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001524 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1525
1526 // Try to trigger overuse. Should not succeed.
1527 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001528 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001529 stats_proxy_->ResetMockStats();
1530
1531 stats = stats_proxy_->GetStats();
1532 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001533 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001534 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1535
1536 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001537 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001538 &video_source_,
1539 VideoSendStream::DegradationPreference::kMaintainFramerate);
asaperssonfab67072017-04-04 05:51:49 -07001540 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001541 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001542 stats = stats_proxy_->GetStats();
1543 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001544 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001545 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001546
1547 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001548 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001549 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001550 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001551 stats = stats_proxy_->GetStats();
1552 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001553 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001554 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1555
1556 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001557 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001558 &new_video_source,
1559 VideoSendStream::DegradationPreference::kMaintainResolution);
1560 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001561 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001562 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001563 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001564 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001565 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001566 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001567 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1568
1569 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001570 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001571 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001572 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001573 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001574 stats = stats_proxy_->GetStats();
1575 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001576 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001577 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001578 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001579
mflodmancc3d4422017-08-03 08:27:51 -07001580 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001581}
1582
mflodmancc3d4422017-08-03 08:27:51 -07001583TEST_F(VideoStreamEncoderTest, StatsTracksPreferredBitrate) {
1584 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Erik Språng08127a92016-11-16 16:41:30 +01001585
asaperssonfab67072017-04-04 05:51:49 -07001586 const int kWidth = 1280;
1587 const int kHeight = 720;
1588 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001589 WaitForEncodedFrame(1);
Erik Språng08127a92016-11-16 16:41:30 +01001590
1591 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1592 EXPECT_EQ(video_encoder_config_.max_bitrate_bps,
1593 stats.preferred_media_bitrate_bps);
1594
mflodmancc3d4422017-08-03 08:27:51 -07001595 video_stream_encoder_->Stop();
Erik Språng08127a92016-11-16 16:41:30 +01001596}
1597
mflodmancc3d4422017-08-03 08:27:51 -07001598TEST_F(VideoStreamEncoderTest,
1599 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001600 const int kWidth = 1280;
1601 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001602 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001603
asaperssonfab67072017-04-04 05:51:49 -07001604 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001605 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001606
asaperssonfab67072017-04-04 05:51:49 -07001607 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001608 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001609
asaperssonfab67072017-04-04 05:51:49 -07001610 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001611 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001612
asaperssonfab67072017-04-04 05:51:49 -07001613 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001614 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001615
kthelgason876222f2016-11-29 01:44:11 -08001616 // Expect a scale down.
1617 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001618 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001619
asapersson02465b82017-04-10 01:12:52 -07001620 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001621 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001622 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001623 &new_video_source,
1624 VideoSendStream::DegradationPreference::kMaintainResolution);
1625
asaperssonfab67072017-04-04 05:51:49 -07001626 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001627 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001628 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001629 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001630
asaperssonfab67072017-04-04 05:51:49 -07001631 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001632 EXPECT_EQ(std::numeric_limits<int>::max(),
1633 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001634
asaperssonfab67072017-04-04 05:51:49 -07001635 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001636 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001637 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001638 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001639
asapersson02465b82017-04-10 01:12:52 -07001640 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001641 EXPECT_EQ(std::numeric_limits<int>::max(),
1642 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001643
mflodmancc3d4422017-08-03 08:27:51 -07001644 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001645}
1646
mflodmancc3d4422017-08-03 08:27:51 -07001647TEST_F(VideoStreamEncoderTest,
1648 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001649 const int kWidth = 1280;
1650 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001651 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001652
1653 // Enable kMaintainFramerate preference, no initial limitation.
1654 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001655 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001656 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1657
1658 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001659 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001660 VerifyNoLimitation(source.sink_wants());
1661 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1662 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1663
1664 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001665 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001666 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001667 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1668 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1669 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1670
1671 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001672 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001673 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1674 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1675 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1676
mflodmancc3d4422017-08-03 08:27:51 -07001677 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001678}
1679
mflodmancc3d4422017-08-03 08:27:51 -07001680TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001681 const int kWidth = 1280;
1682 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001683 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001684
1685 // Enable kBalanced preference, no initial limitation.
1686 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001687 video_stream_encoder_->SetSource(
1688 &source,
1689 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001690 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1691 sink_.WaitForEncodedFrame(1);
1692 VerifyNoLimitation(source.sink_wants());
1693
1694 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001695 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001696 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1697 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1698 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1699 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1700
1701 // Trigger adapt down for same input resolution, expect no change.
1702 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1703 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001704 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001705 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1706 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1707 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1708
1709 // Trigger adapt down for larger input resolution, expect no change.
1710 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1711 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001712 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001713 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1714 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1715 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1716
mflodmancc3d4422017-08-03 08:27:51 -07001717 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001718}
1719
mflodmancc3d4422017-08-03 08:27:51 -07001720TEST_F(VideoStreamEncoderTest,
1721 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001722 const int kWidth = 1280;
1723 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001724 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001725
1726 // Enable kMaintainFramerate preference, no initial limitation.
1727 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001728 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001729 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1730
1731 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001732 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001733 VerifyNoLimitation(source.sink_wants());
1734 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1735 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1736
1737 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001738 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001739 VerifyNoLimitation(source.sink_wants());
1740 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1741 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1742
mflodmancc3d4422017-08-03 08:27:51 -07001743 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001744}
1745
mflodmancc3d4422017-08-03 08:27:51 -07001746TEST_F(VideoStreamEncoderTest,
1747 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001748 const int kWidth = 1280;
1749 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001750 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001751
1752 // Enable kMaintainResolution preference, no initial limitation.
1753 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001754 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001755 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
1756
1757 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001758 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001759 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001760 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001761 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1762
1763 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001764 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001765 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001766 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001767 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1768
mflodmancc3d4422017-08-03 08:27:51 -07001769 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001770}
1771
mflodmancc3d4422017-08-03 08:27:51 -07001772TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001773 const int kWidth = 1280;
1774 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001775 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001776
1777 // Enable kBalanced preference, no initial limitation.
1778 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001779 video_stream_encoder_->SetSource(
1780 &source,
1781 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001782
1783 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1784 sink_.WaitForEncodedFrame(kWidth, kHeight);
1785 VerifyNoLimitation(source.sink_wants());
1786 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1787 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1788 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1789
1790 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001791 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001792 VerifyNoLimitation(source.sink_wants());
1793 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1794 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1795 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1796
mflodmancc3d4422017-08-03 08:27:51 -07001797 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001798}
1799
mflodmancc3d4422017-08-03 08:27:51 -07001800TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001801 const int kWidth = 1280;
1802 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001803 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001804
1805 // Enable kDegradationDisabled preference, no initial limitation.
1806 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001807 video_stream_encoder_->SetSource(
asapersson09f05612017-05-15 23:40:18 -07001808 &source, VideoSendStream::DegradationPreference::kDegradationDisabled);
1809
1810 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1811 sink_.WaitForEncodedFrame(kWidth, kHeight);
1812 VerifyNoLimitation(source.sink_wants());
1813 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1814 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1815 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1816
1817 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001818 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001819 VerifyNoLimitation(source.sink_wants());
1820 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1821 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1822 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1823
mflodmancc3d4422017-08-03 08:27:51 -07001824 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001825}
1826
mflodmancc3d4422017-08-03 08:27:51 -07001827TEST_F(VideoStreamEncoderTest,
1828 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001829 const int kWidth = 1280;
1830 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001831 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001832
1833 // Enable kMaintainFramerate preference, no initial limitation.
1834 AdaptingFrameForwarder source;
1835 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001836 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001837 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1838
1839 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001840 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001841 VerifyNoLimitation(source.sink_wants());
1842 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1843 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1844
1845 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001846 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001847 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001848 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001849 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001850 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();
asapersson02465b82017-04-10 01:12:52 -07001855 VerifyNoLimitation(source.sink_wants());
1856 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1857 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1858 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1859
mflodmancc3d4422017-08-03 08:27:51 -07001860 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001861}
1862
mflodmancc3d4422017-08-03 08:27:51 -07001863TEST_F(VideoStreamEncoderTest,
1864 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001865 const int kWidth = 1280;
1866 const int kHeight = 720;
1867 const int kInputFps = 30;
mflodmancc3d4422017-08-03 08:27:51 -07001868 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001869
1870 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1871 stats.input_frame_rate = kInputFps;
1872 stats_proxy_->SetMockStats(stats);
1873
1874 // Expect no scaling to begin with (preference: kMaintainFramerate).
1875 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1876 sink_.WaitForEncodedFrame(1);
1877 VerifyNoLimitation(video_source_.sink_wants());
1878
1879 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001880 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001881 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1882 sink_.WaitForEncodedFrame(2);
1883 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1884
1885 // Enable kMaintainResolution preference.
1886 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001887 video_stream_encoder_->SetSource(
asapersson09f05612017-05-15 23:40:18 -07001888 &new_video_source,
1889 VideoSendStream::DegradationPreference::kMaintainResolution);
1890 VerifyNoLimitation(new_video_source.sink_wants());
1891
1892 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001893 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001894 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1895 sink_.WaitForEncodedFrame(3);
1896 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1897
1898 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001899 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001900 VerifyNoLimitation(new_video_source.sink_wants());
1901
mflodmancc3d4422017-08-03 08:27:51 -07001902 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001903}
1904
mflodmancc3d4422017-08-03 08:27:51 -07001905TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001906 const int kWidth = 1280;
1907 const int kHeight = 720;
1908 const size_t kNumFrames = 10;
1909
mflodmancc3d4422017-08-03 08:27:51 -07001910 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001911
asaperssond0de2952017-04-21 01:47:31 -07001912 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001913 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001914 video_source_.set_adaptation_enabled(true);
1915
1916 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1917 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1918
1919 int downscales = 0;
1920 for (size_t i = 1; i <= kNumFrames; i++) {
1921 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001922 WaitForEncodedFrame(i);
asaperssond0de2952017-04-21 01:47:31 -07001923
asaperssonfab67072017-04-04 05:51:49 -07001924 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001925 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001926 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001927 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001928
1929 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1930 ++downscales;
1931
1932 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1933 EXPECT_EQ(downscales,
1934 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1935 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001936 }
mflodmancc3d4422017-08-03 08:27:51 -07001937 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001938}
1939
mflodmancc3d4422017-08-03 08:27:51 -07001940TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001941 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1942 const int kWidth = 1280;
1943 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001944 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001945
1946 // Enable kMaintainFramerate preference, no initial limitation.
1947 AdaptingFrameForwarder source;
1948 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001949 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07001950 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1951
1952 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001953 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001954 VerifyNoLimitation(source.sink_wants());
1955 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1956 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1957
1958 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001959 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001960 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001961 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001962 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001963 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1964 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1965
1966 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001967 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07001968 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001969 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001970 VerifyNoLimitation(source.sink_wants());
1971 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1972 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1973
1974 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001975 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001976 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001977 WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07001978 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001979 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1980 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1981
1982 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001983 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson09f05612017-05-15 23:40:18 -07001984 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1985 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001986 VerifyNoLimitation(source.sink_wants());
1987 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1988 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1989
mflodmancc3d4422017-08-03 08:27:51 -07001990 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001991}
1992
mflodmancc3d4422017-08-03 08:27:51 -07001993TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07001994 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
1995 const int kWidth = 1280;
1996 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001997 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001998
1999 // Enable kBalanced preference, no initial limitation.
2000 AdaptingFrameForwarder source;
2001 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002002 video_stream_encoder_->SetSource(
2003 &source,
2004 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002005
2006 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2007 sink_.WaitForEncodedFrame(kWidth, kHeight);
2008 VerifyNoLimitation(source.sink_wants());
2009 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2010 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2011
2012 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002013 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002014 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
2015 sink_.WaitForEncodedFrame(2);
2016 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2017 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2018 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2019
2020 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002021 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002022 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
2023 sink_.WaitForEncodedFrame(kWidth, kHeight);
2024 VerifyNoLimitation(source.sink_wants());
2025 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2026 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2027
2028 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002029 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002030 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
2031 sink_.WaitForEncodedFrame(4);
2032 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2033 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2034 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2035
2036 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002037 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002038 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
2039 sink_.WaitForEncodedFrame(kWidth, kHeight);
2040 VerifyNoLimitation(source.sink_wants());
2041 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2042 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2043
mflodmancc3d4422017-08-03 08:27:51 -07002044 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002045}
2046
mflodmancc3d4422017-08-03 08:27:51 -07002047TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002048 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
2049 const int kWidth = 1280;
2050 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07002051 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002052
2053 // Enable kMaintainFramerate preference, no initial limitation.
2054 AdaptingFrameForwarder source;
2055 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002056 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07002057 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
2058
2059 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002060 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002061 VerifyNoLimitation(source.sink_wants());
2062 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2063 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2064 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2065 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2066
2067 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002068 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002069 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002070 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07002071 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002072 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2073 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2074 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2075 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2076
2077 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07002078 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002079 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002080 WaitForEncodedFrame(3);
asapersson09f05612017-05-15 23:40:18 -07002081 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002082 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2083 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2084 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2085 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2086
Jonathan Yubc771b72017-12-08 17:04:29 -08002087 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002088 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002089 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002090 WaitForEncodedFrame(4);
Jonathan Yubc771b72017-12-08 17:04:29 -08002091 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002092 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2093 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002094 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002095 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2096
Jonathan Yubc771b72017-12-08 17:04:29 -08002097 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07002098 video_stream_encoder_->TriggerQualityLow();
asaperssond0de2952017-04-21 01:47:31 -07002099 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002100 WaitForEncodedFrame(5);
asapersson09f05612017-05-15 23:40:18 -07002101 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002102 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07002103 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2104 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2105 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2106 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2107
Jonathan Yubc771b72017-12-08 17:04:29 -08002108 // Trigger quality adapt down, expect no change (min resolution reached).
2109 video_stream_encoder_->TriggerQualityLow();
2110 source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
2111 WaitForEncodedFrame(6);
2112 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
2113 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2114 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2115 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2116 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2117
2118 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002119 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07002120 source.IncomingCapturedFrame(CreateFrame(7, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002121 WaitForEncodedFrame(7);
asapersson09f05612017-05-15 23:40:18 -07002122 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002123 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2124 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2125 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2126 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2127
2128 // Trigger cpu adapt up, expect upscaled resolution (640x360).
2129 video_stream_encoder_->TriggerCpuNormalUsage();
2130 source.IncomingCapturedFrame(CreateFrame(8, kWidth, kHeight));
2131 WaitForEncodedFrame(8);
2132 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2133 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2134 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2135 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2136 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2137
2138 // Trigger cpu adapt up, expect upscaled resolution (960x540).
2139 video_stream_encoder_->TriggerCpuNormalUsage();
2140 source.IncomingCapturedFrame(CreateFrame(9, kWidth, kHeight));
2141 WaitForEncodedFrame(9);
2142 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002143 last_wants = source.sink_wants();
2144 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2145 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002146 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002147 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2148
2149 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002150 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -08002151 source.IncomingCapturedFrame(CreateFrame(10, kWidth, kHeight));
2152 WaitForEncodedFrame(10);
asapersson09f05612017-05-15 23:40:18 -07002153 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002154 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2155 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002156 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002157 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2158
2159 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002160 video_stream_encoder_->TriggerQualityHigh();
Jonathan Yubc771b72017-12-08 17:04:29 -08002161 source.IncomingCapturedFrame(CreateFrame(11, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002162 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002163 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002164 VerifyNoLimitation(source.sink_wants());
2165 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2166 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002167 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002168 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002169
mflodmancc3d4422017-08-03 08:27:51 -07002170 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002171}
2172
mflodmancc3d4422017-08-03 08:27:51 -07002173TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002174 const int kWidth = 640;
2175 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002176
mflodmancc3d4422017-08-03 08:27:51 -07002177 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002178
perkj803d97f2016-11-01 11:45:46 -07002179 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002180 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002181 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002182 }
2183
mflodmancc3d4422017-08-03 08:27:51 -07002184 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002185 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002186 video_source_.IncomingCapturedFrame(CreateFrame(
2187 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002188 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002189 }
2190
mflodmancc3d4422017-08-03 08:27:51 -07002191 video_stream_encoder_->Stop();
2192 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002193 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002194
perkj803d97f2016-11-01 11:45:46 -07002195 EXPECT_EQ(1,
2196 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2197 EXPECT_EQ(
2198 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2199}
2200
mflodmancc3d4422017-08-03 08:27:51 -07002201TEST_F(VideoStreamEncoderTest,
2202 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2203 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002204 const int kWidth = 640;
2205 const int kHeight = 360;
2206
mflodmancc3d4422017-08-03 08:27:51 -07002207 video_stream_encoder_->SetSource(
asaperssonf4e44af2017-04-19 02:01:06 -07002208 &video_source_,
2209 VideoSendStream::DegradationPreference::kDegradationDisabled);
2210
2211 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2212 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002213 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002214 }
2215
mflodmancc3d4422017-08-03 08:27:51 -07002216 video_stream_encoder_->Stop();
2217 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002218 stats_proxy_.reset();
2219
2220 EXPECT_EQ(0,
2221 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2222}
2223
mflodmancc3d4422017-08-03 08:27:51 -07002224TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002225 MockBitrateObserver bitrate_observer;
mflodmancc3d4422017-08-03 08:27:51 -07002226 video_stream_encoder_->SetBitrateObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002227
2228 const int kDefaultFps = 30;
2229 const BitrateAllocation expected_bitrate =
2230 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002231 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002232
2233 // First called on bitrate updated, then again on first frame.
2234 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2235 .Times(2);
mflodmancc3d4422017-08-03 08:27:51 -07002236 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002237
2238 const int64_t kStartTimeMs = 1;
2239 video_source_.IncomingCapturedFrame(
2240 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002241 WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002242
2243 // Not called on second frame.
2244 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2245 .Times(0);
2246 video_source_.IncomingCapturedFrame(
2247 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002248 WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002249
2250 // Called after a process interval.
2251 const int64_t kProcessIntervalMs =
2252 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang4847ae62017-06-27 07:06:52 -07002253 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec *
2254 (kProcessIntervalMs + (1000 / kDefaultFps)));
sprang57c2fff2017-01-16 06:24:02 -08002255 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2256 .Times(1);
2257 video_source_.IncomingCapturedFrame(CreateFrame(
2258 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002259 WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002260
mflodmancc3d4422017-08-03 08:27:51 -07002261 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002262}
2263
Niels Möller7dc26b72017-12-06 10:27:48 +01002264TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2265 const int kFrameWidth = 1280;
2266 const int kFrameHeight = 720;
2267 const int kFramerate = 24;
2268
2269 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2270 test::FrameForwarder source;
2271 video_stream_encoder_->SetSource(
2272 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2273
2274 // Insert a single frame, triggering initial configuration.
2275 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2276 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2277
2278 EXPECT_EQ(
2279 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2280 kDefaultFramerate);
2281
2282 // Trigger reconfigure encoder (without resetting the entire instance).
2283 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002284 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002285 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2286 video_encoder_config.number_of_streams = 1;
2287 video_encoder_config.video_stream_factory =
2288 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2289 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2290 kMaxPayloadLength, false);
2291 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2292
2293 // Detector should be updated with fps limit from codec config.
2294 EXPECT_EQ(
2295 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2296 kFramerate);
2297
2298 // Trigger overuse, max framerate should be reduced.
2299 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2300 stats.input_frame_rate = kFramerate;
2301 stats_proxy_->SetMockStats(stats);
2302 video_stream_encoder_->TriggerCpuOveruse();
2303 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2304 int adapted_framerate =
2305 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2306 EXPECT_LT(adapted_framerate, kFramerate);
2307
2308 // Trigger underuse, max framerate should go back to codec configured fps.
2309 // Set extra low fps, to make sure it's actually reset, not just incremented.
2310 stats = stats_proxy_->GetStats();
2311 stats.input_frame_rate = adapted_framerate / 2;
2312 stats_proxy_->SetMockStats(stats);
2313 video_stream_encoder_->TriggerCpuNormalUsage();
2314 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2315 EXPECT_EQ(
2316 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2317 kFramerate);
2318
2319 video_stream_encoder_->Stop();
2320}
2321
2322TEST_F(VideoStreamEncoderTest,
2323 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2324 const int kFrameWidth = 1280;
2325 const int kFrameHeight = 720;
2326 const int kLowFramerate = 15;
2327 const int kHighFramerate = 25;
2328
2329 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2330 test::FrameForwarder source;
2331 video_stream_encoder_->SetSource(
2332 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2333
2334 // Trigger initial configuration.
2335 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002336 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002337 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2338 video_encoder_config.number_of_streams = 1;
2339 video_encoder_config.video_stream_factory =
2340 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2341 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2342 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2343 kMaxPayloadLength, false);
2344 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2345
2346 EXPECT_EQ(
2347 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2348 kLowFramerate);
2349
2350 // Trigger overuse, max framerate should be reduced.
2351 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2352 stats.input_frame_rate = kLowFramerate;
2353 stats_proxy_->SetMockStats(stats);
2354 video_stream_encoder_->TriggerCpuOveruse();
2355 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2356 int adapted_framerate =
2357 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2358 EXPECT_LT(adapted_framerate, kLowFramerate);
2359
2360 // Reconfigure the encoder with a new (higher max framerate), max fps should
2361 // still respect the adaptation.
2362 video_encoder_config.video_stream_factory =
2363 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2364 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2365 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2366 kMaxPayloadLength, false);
2367 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2368
2369 EXPECT_EQ(
2370 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2371 adapted_framerate);
2372
2373 // Trigger underuse, max framerate should go back to codec configured fps.
2374 stats = stats_proxy_->GetStats();
2375 stats.input_frame_rate = adapted_framerate;
2376 stats_proxy_->SetMockStats(stats);
2377 video_stream_encoder_->TriggerCpuNormalUsage();
2378 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2379 EXPECT_EQ(
2380 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2381 kHighFramerate);
2382
2383 video_stream_encoder_->Stop();
2384}
2385
mflodmancc3d4422017-08-03 08:27:51 -07002386TEST_F(VideoStreamEncoderTest,
2387 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002388 const int kFrameWidth = 1280;
2389 const int kFrameHeight = 720;
2390 const int kFramerate = 24;
2391
mflodmancc3d4422017-08-03 08:27:51 -07002392 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002393 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002394 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002395 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2396
2397 // Trigger initial configuration.
2398 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002399 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002400 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2401 video_encoder_config.number_of_streams = 1;
2402 video_encoder_config.video_stream_factory =
2403 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2404 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002405 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2406 kMaxPayloadLength, false);
2407 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002408
Niels Möller7dc26b72017-12-06 10:27:48 +01002409 EXPECT_EQ(
2410 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2411 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002412
2413 // Trigger overuse, max framerate should be reduced.
2414 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2415 stats.input_frame_rate = kFramerate;
2416 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002417 video_stream_encoder_->TriggerCpuOveruse();
2418 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002419 int adapted_framerate =
2420 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002421 EXPECT_LT(adapted_framerate, kFramerate);
2422
2423 // Change degradation preference to not enable framerate scaling. Target
2424 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002425 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002426 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07002427 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002428 EXPECT_EQ(
2429 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2430 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002431
mflodmancc3d4422017-08-03 08:27:51 -07002432 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002433}
2434
mflodmancc3d4422017-08-03 08:27:51 -07002435TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002436 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002437 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002438 const int kWidth = 640;
2439 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002440
asaperssonfab67072017-04-04 05:51:49 -07002441 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002442
2443 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002444 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002445
2446 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002447 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002448
sprangc5d62e22017-04-02 23:53:04 -07002449 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002450
asaperssonfab67072017-04-04 05:51:49 -07002451 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002452 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002453 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002454
2455 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002456 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002457
sprangc5d62e22017-04-02 23:53:04 -07002458 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002459
mflodmancc3d4422017-08-03 08:27:51 -07002460 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002461}
2462
mflodmancc3d4422017-08-03 08:27:51 -07002463TEST_F(VideoStreamEncoderTest,
2464 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002465 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002466 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002467 const int kWidth = 640;
2468 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002469
2470 // We expect the n initial frames to get dropped.
2471 int i;
2472 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002473 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002474 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002475 }
2476 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002477 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002478 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002479
2480 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002481 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002482
mflodmancc3d4422017-08-03 08:27:51 -07002483 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002484}
2485
mflodmancc3d4422017-08-03 08:27:51 -07002486TEST_F(VideoStreamEncoderTest,
2487 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002488 const int kWidth = 640;
2489 const int kHeight = 360;
mflodmancc3d4422017-08-03 08:27:51 -07002490 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002491
2492 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002493 video_stream_encoder_->SetSource(
kthelgason2bc68642017-02-07 07:02:22 -08002494 &video_source_,
2495 VideoSendStream::DegradationPreference::kMaintainResolution);
2496
asaperssonfab67072017-04-04 05:51:49 -07002497 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002498 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002499 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002500
mflodmancc3d4422017-08-03 08:27:51 -07002501 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002502}
2503
mflodmancc3d4422017-08-03 08:27:51 -07002504TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002505 const int kWidth = 640;
2506 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002507 fake_encoder_.SetQualityScaling(false);
mflodmancc3d4422017-08-03 08:27:51 -07002508 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002509
kthelgasonb83797b2017-02-14 11:57:25 -08002510 // Force quality scaler reconfiguration by resetting the source.
mflodmancc3d4422017-08-03 08:27:51 -07002511 video_stream_encoder_->SetSource(
2512 &video_source_,
2513 VideoSendStream::DegradationPreference::kBalanced);
kthelgasonad9010c2017-02-14 00:46:51 -08002514
asaperssonfab67072017-04-04 05:51:49 -07002515 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002516 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002517 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002518
mflodmancc3d4422017-08-03 08:27:51 -07002519 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002520 fake_encoder_.SetQualityScaling(true);
2521}
2522
mflodmancc3d4422017-08-03 08:27:51 -07002523TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002524 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2525 const int kTooSmallWidth = 10;
2526 const int kTooSmallHeight = 10;
mflodmancc3d4422017-08-03 08:27:51 -07002527 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002528
2529 // Enable kMaintainFramerate preference, no initial limitation.
2530 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002531 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07002532 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
2533 VerifyNoLimitation(source.sink_wants());
2534 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2535
2536 // Trigger adapt down, too small frame, expect no change.
2537 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002538 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002539 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002540 VerifyNoLimitation(source.sink_wants());
2541 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2542 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2543
mflodmancc3d4422017-08-03 08:27:51 -07002544 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002545}
2546
mflodmancc3d4422017-08-03 08:27:51 -07002547TEST_F(VideoStreamEncoderTest,
2548 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002549 const int kTooSmallWidth = 10;
2550 const int kTooSmallHeight = 10;
2551 const int kFpsLimit = 7;
mflodmancc3d4422017-08-03 08:27:51 -07002552 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002553
2554 // Enable kBalanced preference, no initial limitation.
2555 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002556 video_stream_encoder_->SetSource(
2557 &source,
2558 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002559 VerifyNoLimitation(source.sink_wants());
2560 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2561 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2562
2563 // Trigger adapt down, expect limited framerate.
2564 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002565 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002566 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002567 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2568 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2569 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2570 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2571
2572 // Trigger adapt down, too small frame, expect no change.
2573 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002574 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002575 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002576 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2577 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2578 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2579 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2580
mflodmancc3d4422017-08-03 08:27:51 -07002581 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002582}
2583
mflodmancc3d4422017-08-03 08:27:51 -07002584TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002585 fake_encoder_.ForceInitEncodeFailure(true);
mflodmancc3d4422017-08-03 08:27:51 -07002586 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
emircanbbcc3562017-08-18 00:28:40 -07002587 ResetEncoder("VP8", 2, 1, 1, true, false);
asapersson02465b82017-04-10 01:12:52 -07002588 const int kFrameWidth = 1280;
2589 const int kFrameHeight = 720;
2590 video_source_.IncomingCapturedFrame(
2591 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002592 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002593 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002594}
2595
sprangb1ca0732017-02-01 08:38:12 -08002596// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002597TEST_F(VideoStreamEncoderTest,
2598 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
2599 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002600
2601 const int kFrameWidth = 1280;
2602 const int kFrameHeight = 720;
2603 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002604 // requested by
2605 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002606 video_source_.set_adaptation_enabled(true);
2607
2608 video_source_.IncomingCapturedFrame(
2609 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002610 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002611
2612 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002613 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002614 video_source_.IncomingCapturedFrame(
2615 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002616 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002617
asaperssonfab67072017-04-04 05:51:49 -07002618 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002619 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002620 video_source_.IncomingCapturedFrame(
2621 CreateFrame(3, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002622 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002623
mflodmancc3d4422017-08-03 08:27:51 -07002624 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002625}
sprangfe627f32017-03-29 08:24:59 -07002626
mflodmancc3d4422017-08-03 08:27:51 -07002627TEST_F(VideoStreamEncoderTest,
2628 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002629 const int kFrameWidth = 1280;
2630 const int kFrameHeight = 720;
sprang4847ae62017-06-27 07:06:52 -07002631 int kFrameIntervalMs = rtc::kNumMillisecsPerSec / max_framerate_;
sprangc5d62e22017-04-02 23:53:04 -07002632
mflodmancc3d4422017-08-03 08:27:51 -07002633 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2634 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07002635 &video_source_,
2636 VideoSendStream::DegradationPreference::kMaintainResolution);
2637 video_source_.set_adaptation_enabled(true);
2638
sprang4847ae62017-06-27 07:06:52 -07002639 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002640
2641 video_source_.IncomingCapturedFrame(
2642 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002643 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002644
2645 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002646 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002647
2648 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002649 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002650 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002651 video_source_.IncomingCapturedFrame(
2652 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002653 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002654 }
2655
2656 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002657 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002658 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002659 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002660 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002661 video_source_.IncomingCapturedFrame(
2662 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002663 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002664 ++num_frames_dropped;
2665 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002666 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002667 }
2668 }
2669
sprang4847ae62017-06-27 07:06:52 -07002670 // Add some slack to account for frames dropped by the frame dropper.
2671 const int kErrorMargin = 1;
2672 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002673 kErrorMargin);
2674
2675 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002676 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002677 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002678 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002679 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002680 video_source_.IncomingCapturedFrame(
2681 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002682 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002683 ++num_frames_dropped;
2684 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002685 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002686 }
2687 }
sprang4847ae62017-06-27 07:06:52 -07002688 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002689 kErrorMargin);
2690
2691 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002692 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002693 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002694 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002695 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002696 video_source_.IncomingCapturedFrame(
2697 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002698 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002699 ++num_frames_dropped;
2700 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002701 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002702 }
2703 }
sprang4847ae62017-06-27 07:06:52 -07002704 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002705 kErrorMargin);
2706
2707 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002708 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002709 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002710 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002711 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002712 video_source_.IncomingCapturedFrame(
2713 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002714 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002715 ++num_frames_dropped;
2716 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002717 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002718 }
2719 }
2720 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2721
mflodmancc3d4422017-08-03 08:27:51 -07002722 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002723}
2724
mflodmancc3d4422017-08-03 08:27:51 -07002725TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002726 const int kFramerateFps = 5;
2727 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002728 const int kFrameWidth = 1280;
2729 const int kFrameHeight = 720;
2730
sprang4847ae62017-06-27 07:06:52 -07002731 // Reconfigure encoder with two temporal layers and screensharing, which will
2732 // disable frame dropping and make testing easier.
emircanbbcc3562017-08-18 00:28:40 -07002733 ResetEncoder("VP8", 1, 2, 1, true, true);
sprang4847ae62017-06-27 07:06:52 -07002734
mflodmancc3d4422017-08-03 08:27:51 -07002735 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2736 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07002737 &video_source_,
2738 VideoSendStream::DegradationPreference::kMaintainResolution);
2739 video_source_.set_adaptation_enabled(true);
2740
sprang4847ae62017-06-27 07:06:52 -07002741 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002742
2743 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08002744 rtc::VideoSinkWants last_wants;
2745 do {
2746 last_wants = video_source_.sink_wants();
2747
sprangc5d62e22017-04-02 23:53:04 -07002748 // Insert frames to get a new fps estimate...
2749 for (int j = 0; j < kFramerateFps; ++j) {
2750 video_source_.IncomingCapturedFrame(
2751 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08002752 if (video_source_.last_sent_width()) {
2753 sink_.WaitForEncodedFrame(timestamp_ms);
2754 }
sprangc5d62e22017-04-02 23:53:04 -07002755 timestamp_ms += kFrameIntervalMs;
Jonathan Yubc771b72017-12-08 17:04:29 -08002756 fake_clock_.AdvanceTimeMicros(
2757 kFrameIntervalMs * rtc::kNumMicrosecsPerMillisec);
sprangc5d62e22017-04-02 23:53:04 -07002758 }
2759 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002760 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08002761 } while (video_source_.sink_wants().max_framerate_fps <
2762 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07002763
Jonathan Yubc771b72017-12-08 17:04:29 -08002764 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07002765
mflodmancc3d4422017-08-03 08:27:51 -07002766 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002767}
asaperssonf7e294d2017-06-13 23:25:22 -07002768
mflodmancc3d4422017-08-03 08:27:51 -07002769TEST_F(VideoStreamEncoderTest,
2770 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002771 const int kWidth = 1280;
2772 const int kHeight = 720;
2773 const int64_t kFrameIntervalMs = 150;
2774 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002775 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002776
2777 // Enable kBalanced preference, no initial limitation.
2778 AdaptingFrameForwarder source;
2779 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002780 video_stream_encoder_->SetSource(
2781 &source,
2782 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002783 timestamp_ms += kFrameIntervalMs;
2784 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002785 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002786 VerifyNoLimitation(source.sink_wants());
2787 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2788 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2789 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2790
2791 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002792 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002793 timestamp_ms += kFrameIntervalMs;
2794 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002795 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002796 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2797 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2798 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2799 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2800
2801 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002802 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002803 timestamp_ms += kFrameIntervalMs;
2804 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002805 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002806 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2807 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2808 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2809 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2810
2811 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002812 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002813 timestamp_ms += kFrameIntervalMs;
2814 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002815 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002816 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2817 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2818 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2819 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2820
2821 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002822 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002823 timestamp_ms += kFrameIntervalMs;
2824 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002825 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002826 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2827 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2828 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2829 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2830
2831 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002832 video_stream_encoder_->TriggerQualityLow();
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(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002836 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2837 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2838 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2839 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2840
2841 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002842 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002843 timestamp_ms += kFrameIntervalMs;
2844 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002845 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002846 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2847 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2848 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2849 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2850
2851 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002852 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002853 timestamp_ms += kFrameIntervalMs;
2854 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002855 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002856 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2857 rtc::VideoSinkWants last_wants = source.sink_wants();
2858 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2859 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2860 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2861
2862 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002863 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002864 timestamp_ms += kFrameIntervalMs;
2865 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002866 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002867 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2868 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2869 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2870 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2871
2872 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002873 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002874 timestamp_ms += kFrameIntervalMs;
2875 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002876 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002877 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2878 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2879 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2880 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2881
2882 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002883 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002884 timestamp_ms += kFrameIntervalMs;
2885 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002886 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002887 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2888 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2889 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2890 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2891
2892 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002893 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002894 timestamp_ms += kFrameIntervalMs;
2895 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002896 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002897 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2898 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2899 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2900 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2901
2902 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002903 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002904 timestamp_ms += kFrameIntervalMs;
2905 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002906 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002907 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2908 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2909 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2910 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2911
2912 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002913 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002914 timestamp_ms += kFrameIntervalMs;
2915 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002916 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002917 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2918 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2919 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2920 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2921
2922 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002923 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002924 timestamp_ms += kFrameIntervalMs;
2925 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002926 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002927 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2928 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2929 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2930 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2931
2932 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002933 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002934 timestamp_ms += kFrameIntervalMs;
2935 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002936 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002937 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2938 VerifyNoLimitation(source.sink_wants());
2939 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2940 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2941 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2942
2943 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002944 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002945 VerifyNoLimitation(source.sink_wants());
2946 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2947
mflodmancc3d4422017-08-03 08:27:51 -07002948 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002949}
2950
mflodmancc3d4422017-08-03 08:27:51 -07002951TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07002952 const int kWidth = 1280;
2953 const int kHeight = 720;
2954 const int64_t kFrameIntervalMs = 150;
2955 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002956 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002957
2958 // Enable kBalanced preference, no initial limitation.
2959 AdaptingFrameForwarder source;
2960 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002961 video_stream_encoder_->SetSource(
2962 &source,
2963 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002964 timestamp_ms += kFrameIntervalMs;
2965 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002966 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002967 VerifyNoLimitation(source.sink_wants());
2968 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2969 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2970 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2971 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2972 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2973 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2974
2975 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002976 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002977 timestamp_ms += kFrameIntervalMs;
2978 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002979 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002980 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2981 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2982 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2983 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2984 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2985 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2986 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2987
2988 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002989 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002990 timestamp_ms += kFrameIntervalMs;
2991 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002992 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002993 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2994 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2995 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2996 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2997 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2998 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2999 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3000
3001 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003002 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003003 timestamp_ms += kFrameIntervalMs;
3004 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003005 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003006 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
3007 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3008 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3009 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3010 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3011 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3012 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3013
3014 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003015 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003016 timestamp_ms += kFrameIntervalMs;
3017 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003018 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003019 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
3020 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3021 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3022 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3023 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3024 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3025 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3026
3027 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003028 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003029 timestamp_ms += kFrameIntervalMs;
3030 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003031 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003032 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3033 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3034 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3035 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3036 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3037 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3038 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3039
3040 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003041 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003042 timestamp_ms += kFrameIntervalMs;
3043 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003044 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003045 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3046 VerifyNoLimitation(source.sink_wants());
3047 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3048 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3049 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3050 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3051 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3052 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3053
3054 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003055 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003056 VerifyNoLimitation(source.sink_wants());
3057 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3058 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3059
mflodmancc3d4422017-08-03 08:27:51 -07003060 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003061}
3062
mflodmancc3d4422017-08-03 08:27:51 -07003063TEST_F(VideoStreamEncoderTest,
3064 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07003065 const int kWidth = 640;
3066 const int kHeight = 360;
3067 const int kFpsLimit = 15;
3068 const int64_t kFrameIntervalMs = 150;
3069 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07003070 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07003071
3072 // Enable kBalanced preference, no initial limitation.
3073 AdaptingFrameForwarder source;
3074 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07003075 video_stream_encoder_->SetSource(
3076 &source,
3077 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07003078 timestamp_ms += kFrameIntervalMs;
3079 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003080 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003081 VerifyNoLimitation(source.sink_wants());
3082 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3083 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3084 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3085 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3086 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3087 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3088
3089 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003090 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003091 timestamp_ms += kFrameIntervalMs;
3092 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003093 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003094 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
3095 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3096 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3097 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3098 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3099 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3100 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3101
3102 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003103 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003104 timestamp_ms += kFrameIntervalMs;
3105 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003106 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003107 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
3108 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3109 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3110 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3111 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3112 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3113 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3114
3115 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003116 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003117 timestamp_ms += kFrameIntervalMs;
3118 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003119 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003120 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3121 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3122 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3123 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3124 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3125 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3126 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3127
3128 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003129 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003130 timestamp_ms += kFrameIntervalMs;
3131 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003132 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003133 VerifyNoLimitation(source.sink_wants());
3134 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3135 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3136 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3137 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3138 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3139 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3140
3141 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003142 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003143 VerifyNoLimitation(source.sink_wants());
3144 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3145 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3146
mflodmancc3d4422017-08-03 08:27:51 -07003147 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003148}
3149
mflodmancc3d4422017-08-03 08:27:51 -07003150TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003151 // Simulates simulcast behavior and makes highest stream resolutions divisible
3152 // by 4.
3153 class CroppingVideoStreamFactory
3154 : public VideoEncoderConfig::VideoStreamFactoryInterface {
3155 public:
3156 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
3157 int framerate)
3158 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
3159 EXPECT_GT(num_temporal_layers, 0u);
3160 EXPECT_GT(framerate, 0);
3161 }
3162
3163 private:
3164 std::vector<VideoStream> CreateEncoderStreams(
3165 int width,
3166 int height,
3167 const VideoEncoderConfig& encoder_config) override {
3168 std::vector<VideoStream> streams =
3169 test::CreateVideoStreams(width - width % 4, height - height % 4,
3170 encoder_config);
3171 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +01003172 stream.num_temporal_layers = num_temporal_layers_;
ilnik6b826ef2017-06-16 06:53:48 -07003173 stream.max_framerate = framerate_;
3174 }
3175 return streams;
3176 }
3177
3178 const size_t num_temporal_layers_;
3179 const int framerate_;
3180 };
3181
3182 const int kFrameWidth = 1920;
3183 const int kFrameHeight = 1080;
3184 // 3/4 of 1920.
3185 const int kAdaptedFrameWidth = 1440;
3186 // 3/4 of 1080 rounded down to multiple of 4.
3187 const int kAdaptedFrameHeight = 808;
3188 const int kFramerate = 24;
3189
mflodmancc3d4422017-08-03 08:27:51 -07003190 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003191 // Trigger reconfigure encoder (without resetting the entire instance).
3192 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02003193 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07003194 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3195 video_encoder_config.number_of_streams = 1;
3196 video_encoder_config.video_stream_factory =
3197 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003198 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
3199 kMaxPayloadLength, false);
3200 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003201
3202 video_source_.set_adaptation_enabled(true);
3203
3204 video_source_.IncomingCapturedFrame(
3205 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003206 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003207
3208 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003209 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003210 video_source_.IncomingCapturedFrame(
3211 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003212 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003213
mflodmancc3d4422017-08-03 08:27:51 -07003214 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003215}
3216
mflodmancc3d4422017-08-03 08:27:51 -07003217TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003218 const int kFrameWidth = 1280;
3219 const int kFrameHeight = 720;
3220 const int kLowFps = 2;
3221 const int kHighFps = 30;
3222
mflodmancc3d4422017-08-03 08:27:51 -07003223 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003224
3225 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3226 max_framerate_ = kLowFps;
3227
3228 // Insert 2 seconds of 2fps video.
3229 for (int i = 0; i < kLowFps * 2; ++i) {
3230 video_source_.IncomingCapturedFrame(
3231 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3232 WaitForEncodedFrame(timestamp_ms);
3233 timestamp_ms += 1000 / kLowFps;
3234 }
3235
3236 // Make sure encoder is updated with new target.
mflodmancc3d4422017-08-03 08:27:51 -07003237 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003238 video_source_.IncomingCapturedFrame(
3239 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3240 WaitForEncodedFrame(timestamp_ms);
3241 timestamp_ms += 1000 / kLowFps;
3242
3243 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3244
3245 // Insert 30fps frames for just a little more than the forced update period.
3246 const int kVcmTimerIntervalFrames =
3247 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3248 const int kFrameIntervalMs = 1000 / kHighFps;
3249 max_framerate_ = kHighFps;
3250 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3251 video_source_.IncomingCapturedFrame(
3252 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3253 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3254 // be dropped if the encoder hans't been updated with the new higher target
3255 // framerate yet, causing it to overshoot the target bitrate and then
3256 // suffering the wrath of the media optimizer.
3257 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3258 timestamp_ms += kFrameIntervalMs;
3259 }
3260
3261 // Don expect correct measurement just yet, but it should be higher than
3262 // before.
3263 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3264
mflodmancc3d4422017-08-03 08:27:51 -07003265 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003266}
3267
mflodmancc3d4422017-08-03 08:27:51 -07003268TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003269 const int kFrameWidth = 1280;
3270 const int kFrameHeight = 720;
3271 const int kTargetBitrateBps = 1000000;
3272
3273 MockBitrateObserver bitrate_observer;
mflodmancc3d4422017-08-03 08:27:51 -07003274 video_stream_encoder_->SetBitrateObserver(&bitrate_observer);
sprang4847ae62017-06-27 07:06:52 -07003275
3276 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3277 // Initial bitrate update.
mflodmancc3d4422017-08-03 08:27:51 -07003278 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3279 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003280
3281 // Insert a first video frame, causes another bitrate update.
3282 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3283 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3284 video_source_.IncomingCapturedFrame(
3285 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3286 WaitForEncodedFrame(timestamp_ms);
3287
3288 // Next, simulate video suspension due to pacer queue overrun.
mflodmancc3d4422017-08-03 08:27:51 -07003289 video_stream_encoder_->OnBitrateUpdated(0, 0, 1);
sprang4847ae62017-06-27 07:06:52 -07003290
3291 // Skip ahead until a new periodic parameter update should have occured.
3292 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3293 fake_clock_.AdvanceTimeMicros(
3294 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3295 rtc::kNumMicrosecsPerMillisec);
3296
3297 // Bitrate observer should not be called.
3298 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3299 video_source_.IncomingCapturedFrame(
3300 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3301 ExpectDroppedFrame();
3302
mflodmancc3d4422017-08-03 08:27:51 -07003303 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003304}
ilnik6b826ef2017-06-16 06:53:48 -07003305
perkj26091b12016-09-01 01:17:40 -07003306} // namespace webrtc