blob: 8c12d8de71dfdbf68dbb2fbc2f2dbef1cec66045 [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"
18#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
19#include "rtc_base/fakeclock.h"
20#include "rtc_base/logging.h"
21#include "system_wrappers/include/metrics_default.h"
22#include "system_wrappers/include/sleep.h"
23#include "test/encoder_settings.h"
24#include "test/fake_encoder.h"
25#include "test/frame_generator.h"
26#include "test/gmock.h"
27#include "test/gtest.h"
28#include "video/send_statistics_proxy.h"
29#include "video/video_stream_encoder.h"
perkj26091b12016-09-01 01:17:40 -070030
kthelgason33ce8892016-12-09 03:53:59 -080031namespace {
kthelgason33ce8892016-12-09 03:53:59 -080032const int kMinPixelsPerFrame = 320 * 180;
sprangc5d62e22017-04-02 23:53:04 -070033const int kMinFramerateFps = 2;
Jonathan Yubc771b72017-12-08 17:04:29 -080034const int kMinBalancedFramerateFps = 7;
sprangc5d62e22017-04-02 23:53:04 -070035const int64_t kFrameTimeoutMs = 100;
emircanbbcc3562017-08-18 00:28:40 -070036const unsigned char kNumSlDummy = 0;
sprangc5d62e22017-04-02 23:53:04 -070037} // namespace
kthelgason33ce8892016-12-09 03:53:59 -080038
perkj26091b12016-09-01 01:17:40 -070039namespace webrtc {
40
kthelgason876222f2016-11-29 01:44:11 -080041using DegredationPreference = VideoSendStream::DegradationPreference;
sprangb1ca0732017-02-01 08:38:12 -080042using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080043using ::testing::_;
44using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080045
perkj803d97f2016-11-01 11:45:46 -070046namespace {
asapersson5f7226f2016-11-25 04:37:00 -080047const size_t kMaxPayloadLength = 1440;
kthelgason2bc68642017-02-07 07:02:22 -080048const int kTargetBitrateBps = 1000000;
49const int kLowTargetBitrateBps = kTargetBitrateBps / 10;
50const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070051const int kDefaultFramerate = 30;
asapersson5f7226f2016-11-25 04:37:00 -080052
perkj803d97f2016-11-01 11:45:46 -070053class TestBuffer : public webrtc::I420Buffer {
54 public:
55 TestBuffer(rtc::Event* event, int width, int height)
56 : I420Buffer(width, height), event_(event) {}
57
58 private:
59 friend class rtc::RefCountedObject<TestBuffer>;
60 ~TestBuffer() override {
61 if (event_)
62 event_->Set();
63 }
64 rtc::Event* const event_;
65};
66
Niels Möller7dc26b72017-12-06 10:27:48 +010067class CpuOveruseDetectorProxy : public OveruseFrameDetector {
68 public:
69 CpuOveruseDetectorProxy(const CpuOveruseOptions& options,
Niels Möller7dc26b72017-12-06 10:27:48 +010070 CpuOveruseMetricsObserver* metrics_observer)
71 : OveruseFrameDetector(options,
Niels Möller7dc26b72017-12-06 10:27:48 +010072 metrics_observer),
73 last_target_framerate_fps_(-1) {}
74 virtual ~CpuOveruseDetectorProxy() {}
75
76 void OnTargetFramerateUpdated(int framerate_fps) override {
77 rtc::CritScope cs(&lock_);
78 last_target_framerate_fps_ = framerate_fps;
79 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
80 }
81
82 int GetLastTargetFramerate() {
83 rtc::CritScope cs(&lock_);
84 return last_target_framerate_fps_;
85 }
86
87 private:
88 rtc::CriticalSection lock_;
89 int last_target_framerate_fps_ RTC_GUARDED_BY(lock_);
90};
91
mflodmancc3d4422017-08-03 08:27:51 -070092class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -070093 public:
Niels Möller7dc26b72017-12-06 10:27:48 +010094 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
95 const VideoSendStream::Config::EncoderSettings& settings)
mflodmancc3d4422017-08-03 08:27:51 -070096 : VideoStreamEncoder(
97 1 /* number_of_cores */,
98 stats_proxy,
99 settings,
100 nullptr /* pre_encode_callback */,
mflodmancc3d4422017-08-03 08:27:51 -0700101 std::unique_ptr<OveruseFrameDetector>(
Niels Möller7dc26b72017-12-06 10:27:48 +0100102 overuse_detector_proxy_ = new CpuOveruseDetectorProxy(
Niels Möller73f29cb2018-01-31 16:09:31 +0100103 CpuOveruseOptions(),
mflodmancc3d4422017-08-03 08:27:51 -0700104 stats_proxy))) {}
perkj803d97f2016-11-01 11:45:46 -0700105
sprangb1ca0732017-02-01 08:38:12 -0800106 void PostTaskAndWait(bool down, AdaptReason reason) {
perkj803d97f2016-11-01 11:45:46 -0700107 rtc::Event event(false, false);
kthelgason876222f2016-11-29 01:44:11 -0800108 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800109 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700110 event.Set();
111 });
perkj070ba852017-02-16 15:46:27 -0800112 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700113 }
114
kthelgason2fc52542017-03-03 00:24:41 -0800115 // This is used as a synchronisation mechanism, to make sure that the
116 // encoder queue is not blocked before we start sending it frames.
117 void WaitUntilTaskQueueIsIdle() {
118 rtc::Event event(false, false);
119 encoder_queue()->PostTask([&event] {
120 event.Set();
121 });
122 ASSERT_TRUE(event.Wait(5000));
123 }
124
sprangb1ca0732017-02-01 08:38:12 -0800125 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800126
sprangb1ca0732017-02-01 08:38:12 -0800127 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800128
sprangb1ca0732017-02-01 08:38:12 -0800129 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800130
sprangb1ca0732017-02-01 08:38:12 -0800131 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700132
Niels Möller7dc26b72017-12-06 10:27:48 +0100133 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700134};
135
asapersson5f7226f2016-11-25 04:37:00 -0800136class VideoStreamFactory
137 : public VideoEncoderConfig::VideoStreamFactoryInterface {
138 public:
sprangfda496a2017-06-15 04:21:07 -0700139 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
140 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800141 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700142 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800143 }
144
145 private:
146 std::vector<VideoStream> CreateEncoderStreams(
147 int width,
148 int height,
149 const VideoEncoderConfig& encoder_config) override {
150 std::vector<VideoStream> streams =
151 test::CreateVideoStreams(width, height, encoder_config);
152 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +0100153 stream.num_temporal_layers = num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700154 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800155 }
156 return streams;
157 }
sprangfda496a2017-06-15 04:21:07 -0700158
asapersson5f7226f2016-11-25 04:37:00 -0800159 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700160 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800161};
162
ilnik6b826ef2017-06-16 06:53:48 -0700163
sprangb1ca0732017-02-01 08:38:12 -0800164class AdaptingFrameForwarder : public test::FrameForwarder {
165 public:
166 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700167 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800168
169 void set_adaptation_enabled(bool enabled) {
170 rtc::CritScope cs(&crit_);
171 adaptation_enabled_ = enabled;
172 }
173
asaperssonfab67072017-04-04 05:51:49 -0700174 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800175 rtc::CritScope cs(&crit_);
176 return adaptation_enabled_;
177 }
178
asapersson09f05612017-05-15 23:40:18 -0700179 rtc::VideoSinkWants last_wants() const {
180 rtc::CritScope cs(&crit_);
181 return last_wants_;
182 }
183
Jonathan Yubc771b72017-12-08 17:04:29 -0800184 rtc::Optional<int> last_sent_width() const { return last_width_; }
185 rtc::Optional<int> last_sent_height() const { return last_height_; }
186
sprangb1ca0732017-02-01 08:38:12 -0800187 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
188 int cropped_width = 0;
189 int cropped_height = 0;
190 int out_width = 0;
191 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700192 if (adaption_enabled()) {
193 if (adapter_.AdaptFrameResolution(
194 video_frame.width(), video_frame.height(),
195 video_frame.timestamp_us() * 1000, &cropped_width,
196 &cropped_height, &out_width, &out_height)) {
197 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
198 nullptr, out_width, out_height),
199 99, 99, kVideoRotation_0);
200 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
201 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800202 last_width_.emplace(adapted_frame.width());
203 last_height_.emplace(adapted_frame.height());
204 } else {
205 last_width_ = rtc::nullopt;
206 last_height_ = rtc::nullopt;
sprangc5d62e22017-04-02 23:53:04 -0700207 }
sprangb1ca0732017-02-01 08:38:12 -0800208 } else {
209 test::FrameForwarder::IncomingCapturedFrame(video_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800210 last_width_.emplace(video_frame.width());
211 last_height_.emplace(video_frame.height());
sprangb1ca0732017-02-01 08:38:12 -0800212 }
213 }
214
215 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
216 const rtc::VideoSinkWants& wants) override {
217 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700218 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700219 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
220 wants.max_pixel_count,
221 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800222 test::FrameForwarder::AddOrUpdateSink(sink, wants);
223 }
sprangb1ca0732017-02-01 08:38:12 -0800224 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700225 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
226 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
Jonathan Yubc771b72017-12-08 17:04:29 -0800227 rtc::Optional<int> last_width_;
228 rtc::Optional<int> last_height_;
sprangb1ca0732017-02-01 08:38:12 -0800229};
sprangc5d62e22017-04-02 23:53:04 -0700230
231class MockableSendStatisticsProxy : public SendStatisticsProxy {
232 public:
233 MockableSendStatisticsProxy(Clock* clock,
234 const VideoSendStream::Config& config,
235 VideoEncoderConfig::ContentType content_type)
236 : SendStatisticsProxy(clock, config, content_type) {}
237
238 VideoSendStream::Stats GetStats() override {
239 rtc::CritScope cs(&lock_);
240 if (mock_stats_)
241 return *mock_stats_;
242 return SendStatisticsProxy::GetStats();
243 }
244
245 void SetMockStats(const VideoSendStream::Stats& stats) {
246 rtc::CritScope cs(&lock_);
247 mock_stats_.emplace(stats);
248 }
249
250 void ResetMockStats() {
251 rtc::CritScope cs(&lock_);
252 mock_stats_.reset();
253 }
254
255 private:
256 rtc::CriticalSection lock_;
danilchapa37de392017-09-09 04:17:22 -0700257 rtc::Optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700258};
259
sprang4847ae62017-06-27 07:06:52 -0700260class MockBitrateObserver : public VideoBitrateAllocationObserver {
261 public:
262 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const BitrateAllocation&));
263};
264
perkj803d97f2016-11-01 11:45:46 -0700265} // namespace
266
mflodmancc3d4422017-08-03 08:27:51 -0700267class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700268 public:
269 static const int kDefaultTimeoutMs = 30 * 1000;
270
mflodmancc3d4422017-08-03 08:27:51 -0700271 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700272 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700273 codec_width_(320),
274 codec_height_(240),
sprang4847ae62017-06-27 07:06:52 -0700275 max_framerate_(30),
perkj26091b12016-09-01 01:17:40 -0700276 fake_encoder_(),
sprangc5d62e22017-04-02 23:53:04 -0700277 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700278 Clock::GetRealTimeClock(),
279 video_send_config_,
280 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700281 sink_(&fake_encoder_) {}
282
283 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700284 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700285 video_send_config_ = VideoSendStream::Config(nullptr);
286 video_send_config_.encoder_settings.encoder = &fake_encoder_;
287 video_send_config_.encoder_settings.payload_name = "FAKE";
288 video_send_config_.encoder_settings.payload_type = 125;
289
Per512ecb32016-09-23 15:52:06 +0200290 VideoEncoderConfig video_encoder_config;
perkjfa10b552016-10-02 23:45:26 -0700291 test::FillEncoderConfiguration(1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700292 video_encoder_config.video_stream_factory =
293 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100294 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700295
296 // Framerate limit is specified by the VideoStreamFactory.
297 std::vector<VideoStream> streams =
298 video_encoder_config.video_stream_factory->CreateEncoderStreams(
299 codec_width_, codec_height_, video_encoder_config);
300 max_framerate_ = streams[0].max_framerate;
301 fake_clock_.SetTimeMicros(1234);
302
asapersson5f7226f2016-11-25 04:37:00 -0800303 ConfigureEncoder(std::move(video_encoder_config), true /* nack_enabled */);
304 }
305
306 void ConfigureEncoder(VideoEncoderConfig video_encoder_config,
307 bool nack_enabled) {
mflodmancc3d4422017-08-03 08:27:51 -0700308 if (video_stream_encoder_)
309 video_stream_encoder_->Stop();
310 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700311 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700312 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
313 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -0700314 &video_source_,
315 VideoSendStream::DegradationPreference::kMaintainFramerate);
mflodmancc3d4422017-08-03 08:27:51 -0700316 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
317 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
318 kMaxPayloadLength, nack_enabled);
319 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800320 }
321
322 void ResetEncoder(const std::string& payload_name,
323 size_t num_streams,
324 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700325 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700326 bool nack_enabled,
327 bool screenshare) {
asapersson5f7226f2016-11-25 04:37:00 -0800328 video_send_config_.encoder_settings.payload_name = payload_name;
329
330 VideoEncoderConfig video_encoder_config;
331 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800332 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800333 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700334 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
335 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700336 video_encoder_config.content_type =
337 screenshare ? VideoEncoderConfig::ContentType::kScreen
338 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700339 if (payload_name == "VP9") {
340 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
341 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
342 video_encoder_config.encoder_specific_settings =
343 new rtc::RefCountedObject<
344 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
345 }
asapersson5f7226f2016-11-25 04:37:00 -0800346 ConfigureEncoder(std::move(video_encoder_config), nack_enabled);
perkj26091b12016-09-01 01:17:40 -0700347 }
348
sprang57c2fff2017-01-16 06:24:02 -0800349 VideoFrame CreateFrame(int64_t ntp_time_ms,
350 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200351 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
352 destruction_event, codec_width_, codec_height_),
353 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800354 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700355 return frame;
356 }
357
sprang57c2fff2017-01-16 06:24:02 -0800358 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700359 VideoFrame frame(
360 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
361 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800362 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700363 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700364 return frame;
365 }
366
asapersson02465b82017-04-10 01:12:52 -0700367 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700368 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700369 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
370 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700371 }
372
asapersson09f05612017-05-15 23:40:18 -0700373 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
374 const rtc::VideoSinkWants& wants2) {
375 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
376 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
377 }
378
379 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
380 const rtc::VideoSinkWants& wants2) {
381 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
382 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
383 EXPECT_GT(wants1.max_pixel_count, 0);
384 }
385
386 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
387 const rtc::VideoSinkWants& wants2) {
388 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
389 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
390 }
391
asaperssonf7e294d2017-06-13 23:25:22 -0700392 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
393 const rtc::VideoSinkWants& wants2) {
394 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
395 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
396 }
397
398 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
399 const rtc::VideoSinkWants& wants2) {
400 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
401 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
402 }
403
404 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
405 const rtc::VideoSinkWants& wants2) {
406 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
407 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
408 }
409
410 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
411 const rtc::VideoSinkWants& wants2) {
412 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
413 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
414 EXPECT_GT(wants1.max_pixel_count, 0);
415 }
416
417 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
418 const rtc::VideoSinkWants& wants2) {
419 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
420 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
421 }
422
asapersson09f05612017-05-15 23:40:18 -0700423 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
424 int pixel_count) {
425 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700426 EXPECT_LT(wants.max_pixel_count, pixel_count);
427 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700428 }
429
430 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
431 EXPECT_LT(wants.max_framerate_fps, fps);
432 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
433 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700434 }
435
asaperssonf7e294d2017-06-13 23:25:22 -0700436 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
437 int expected_fps) {
438 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
439 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
440 EXPECT_FALSE(wants.target_pixel_count);
441 }
442
Jonathan Yubc771b72017-12-08 17:04:29 -0800443 void VerifyBalancedModeFpsRange(const rtc::VideoSinkWants& wants,
444 int last_frame_pixels) {
445 // Balanced mode should always scale FPS to the desired range before
446 // attempting to scale resolution.
447 int fps_limit = wants.max_framerate_fps;
448 if (last_frame_pixels <= 320 * 240) {
449 EXPECT_TRUE(7 <= fps_limit && fps_limit <= 10);
450 } else if (last_frame_pixels <= 480 * 270) {
451 EXPECT_TRUE(10 <= fps_limit && fps_limit <= 15);
452 } else if (last_frame_pixels <= 640 * 480) {
453 EXPECT_LE(15, fps_limit);
454 } else {
455 EXPECT_EQ(std::numeric_limits<int>::max(), fps_limit);
456 }
457 }
458
sprang4847ae62017-06-27 07:06:52 -0700459 void WaitForEncodedFrame(int64_t expected_ntp_time) {
460 sink_.WaitForEncodedFrame(expected_ntp_time);
461 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
462 }
463
464 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
465 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
466 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
467 return ok;
468 }
469
470 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
471 sink_.WaitForEncodedFrame(expected_width, expected_height);
472 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
473 }
474
475 void ExpectDroppedFrame() {
476 sink_.ExpectDroppedFrame();
477 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
478 }
479
480 bool WaitForFrame(int64_t timeout_ms) {
481 bool ok = sink_.WaitForFrame(timeout_ms);
482 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
483 return ok;
484 }
485
perkj26091b12016-09-01 01:17:40 -0700486 class TestEncoder : public test::FakeEncoder {
487 public:
488 TestEncoder()
489 : FakeEncoder(Clock::GetRealTimeClock()),
490 continue_encode_event_(false, false) {}
491
asaperssonfab67072017-04-04 05:51:49 -0700492 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800493 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700494 return config_;
495 }
496
497 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800498 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700499 block_next_encode_ = true;
500 }
501
kthelgason876222f2016-11-29 01:44:11 -0800502 VideoEncoder::ScalingSettings GetScalingSettings() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800503 rtc::CritScope lock(&local_crit_sect_);
kthelgasonad9010c2017-02-14 00:46:51 -0800504 if (quality_scaling_)
Niels Möller225c7872018-02-22 15:03:53 +0100505 return VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
506 return VideoEncoder::ScalingSettings::kOff;
kthelgason876222f2016-11-29 01:44:11 -0800507 }
508
perkjfa10b552016-10-02 23:45:26 -0700509 void ContinueEncode() { continue_encode_event_.Set(); }
510
511 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
512 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800513 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700514 EXPECT_EQ(timestamp_, timestamp);
515 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
516 }
517
kthelgason2fc52542017-03-03 00:24:41 -0800518 void SetQualityScaling(bool b) {
519 rtc::CritScope lock(&local_crit_sect_);
520 quality_scaling_ = b;
521 }
kthelgasonad9010c2017-02-14 00:46:51 -0800522
sprangfe627f32017-03-29 08:24:59 -0700523 void ForceInitEncodeFailure(bool force_failure) {
524 rtc::CritScope lock(&local_crit_sect_);
525 force_init_encode_failed_ = force_failure;
526 }
527
perkjfa10b552016-10-02 23:45:26 -0700528 private:
perkj26091b12016-09-01 01:17:40 -0700529 int32_t Encode(const VideoFrame& input_image,
530 const CodecSpecificInfo* codec_specific_info,
531 const std::vector<FrameType>* frame_types) override {
532 bool block_encode;
533 {
brandtre78d2662017-01-16 05:57:16 -0800534 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700535 EXPECT_GT(input_image.timestamp(), timestamp_);
536 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
537 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
538
539 timestamp_ = input_image.timestamp();
540 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700541 last_input_width_ = input_image.width();
542 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700543 block_encode = block_next_encode_;
544 block_next_encode_ = false;
545 }
546 int32_t result =
547 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
548 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700549 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700550 return result;
551 }
552
sprangfe627f32017-03-29 08:24:59 -0700553 int32_t InitEncode(const VideoCodec* config,
554 int32_t number_of_cores,
555 size_t max_payload_size) override {
556 int res =
557 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
558 rtc::CritScope lock(&local_crit_sect_);
Erik Språng82fad3d2018-03-21 09:57:23 +0100559 if (config->codecType == kVideoCodecVP8) {
sprangfe627f32017-03-29 08:24:59 -0700560 // Simulate setting up temporal layers, in order to validate the life
561 // cycle of these objects.
562 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
sprangfe627f32017-03-29 08:24:59 -0700563 for (int i = 0; i < num_streams; ++i) {
564 allocated_temporal_layers_.emplace_back(
Erik Språng82fad3d2018-03-21 09:57:23 +0100565 TemporalLayers::CreateTemporalLayers(*config, i, 42));
sprangfe627f32017-03-29 08:24:59 -0700566 }
567 }
568 if (force_init_encode_failed_)
569 return -1;
570 return res;
571 }
572
brandtre78d2662017-01-16 05:57:16 -0800573 rtc::CriticalSection local_crit_sect_;
danilchapa37de392017-09-09 04:17:22 -0700574 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700575 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700576 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
577 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
578 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
579 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
580 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
sprangfe627f32017-03-29 08:24:59 -0700581 std::vector<std::unique_ptr<TemporalLayers>> allocated_temporal_layers_
danilchapa37de392017-09-09 04:17:22 -0700582 RTC_GUARDED_BY(local_crit_sect_);
583 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700584 };
585
mflodmancc3d4422017-08-03 08:27:51 -0700586 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700587 public:
588 explicit TestSink(TestEncoder* test_encoder)
589 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
590
perkj26091b12016-09-01 01:17:40 -0700591 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700592 EXPECT_TRUE(
593 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
594 }
595
596 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
597 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700598 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700599 if (!encoded_frame_event_.Wait(timeout_ms))
600 return false;
perkj26091b12016-09-01 01:17:40 -0700601 {
602 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800603 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700604 }
605 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700606 return true;
perkj26091b12016-09-01 01:17:40 -0700607 }
608
sprangb1ca0732017-02-01 08:38:12 -0800609 void WaitForEncodedFrame(uint32_t expected_width,
610 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700611 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100612 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700613 }
614
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100615 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700616 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800617 uint32_t width = 0;
618 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800619 {
620 rtc::CritScope lock(&crit_);
621 width = last_width_;
622 height = last_height_;
623 }
624 EXPECT_EQ(expected_height, height);
625 EXPECT_EQ(expected_width, width);
626 }
627
kthelgason2fc52542017-03-03 00:24:41 -0800628 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800629
sprangc5d62e22017-04-02 23:53:04 -0700630 bool WaitForFrame(int64_t timeout_ms) {
631 return encoded_frame_event_.Wait(timeout_ms);
632 }
633
perkj26091b12016-09-01 01:17:40 -0700634 void SetExpectNoFrames() {
635 rtc::CritScope lock(&crit_);
636 expect_frames_ = false;
637 }
638
asaperssonfab67072017-04-04 05:51:49 -0700639 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200640 rtc::CritScope lock(&crit_);
641 return number_of_reconfigurations_;
642 }
643
asaperssonfab67072017-04-04 05:51:49 -0700644 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200645 rtc::CritScope lock(&crit_);
646 return min_transmit_bitrate_bps_;
647 }
648
perkj26091b12016-09-01 01:17:40 -0700649 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700650 Result OnEncodedImage(
651 const EncodedImage& encoded_image,
652 const CodecSpecificInfo* codec_specific_info,
653 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200654 rtc::CritScope lock(&crit_);
655 EXPECT_TRUE(expect_frames_);
sprangb1ca0732017-02-01 08:38:12 -0800656 last_timestamp_ = encoded_image._timeStamp;
657 last_width_ = encoded_image._encodedWidth;
658 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200659 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800660 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200661 }
662
663 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
664 int min_transmit_bitrate_bps) override {
665 rtc::CriticalSection crit_;
666 ++number_of_reconfigurations_;
667 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
668 }
669
perkj26091b12016-09-01 01:17:40 -0700670 rtc::CriticalSection crit_;
671 TestEncoder* test_encoder_;
672 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800673 uint32_t last_timestamp_ = 0;
674 uint32_t last_height_ = 0;
675 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700676 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200677 int number_of_reconfigurations_ = 0;
678 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700679 };
680
681 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100682 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200683 int codec_width_;
684 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700685 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700686 TestEncoder fake_encoder_;
sprangc5d62e22017-04-02 23:53:04 -0700687 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700688 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800689 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700690 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700691 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700692};
693
mflodmancc3d4422017-08-03 08:27:51 -0700694TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
695 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700696 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700697 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700698 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700699 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700700 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700701}
702
mflodmancc3d4422017-08-03 08:27:51 -0700703TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700704 // Dropped since no target bitrate has been set.
705 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700706 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
707 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700708
mflodmancc3d4422017-08-03 08:27:51 -0700709 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700710
perkja49cbd32016-09-16 07:53:41 -0700711 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700712 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700713 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700714}
715
mflodmancc3d4422017-08-03 08:27:51 -0700716TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
717 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700718 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700719 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700720
mflodmancc3d4422017-08-03 08:27:51 -0700721 video_stream_encoder_->OnBitrateUpdated(0, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700722 // Dropped since bitrate is zero.
perkja49cbd32016-09-16 07:53:41 -0700723 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkj26091b12016-09-01 01:17:40 -0700724
mflodmancc3d4422017-08-03 08:27:51 -0700725 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700726 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700727 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700728 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700729}
730
mflodmancc3d4422017-08-03 08:27:51 -0700731TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
732 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700733 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700734 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700735
736 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700737 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700738
perkja49cbd32016-09-16 07:53:41 -0700739 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700740 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700741 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700742}
743
mflodmancc3d4422017-08-03 08:27:51 -0700744TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
745 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700746
perkja49cbd32016-09-16 07:53:41 -0700747 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700748 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700749
mflodmancc3d4422017-08-03 08:27:51 -0700750 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700751 sink_.SetExpectNoFrames();
752 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700753 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
754 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700755}
756
mflodmancc3d4422017-08-03 08:27:51 -0700757TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
758 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700759
760 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700761 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700762 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700763 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
764 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700765 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
766 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700767 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700768 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700769
mflodmancc3d4422017-08-03 08:27:51 -0700770 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700771}
772
mflodmancc3d4422017-08-03 08:27:51 -0700773TEST_F(VideoStreamEncoderTest,
774 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
775 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100776 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200777
778 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200779 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700780 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100781 // The encoder will have been configured once when the first frame is
782 // received.
783 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200784
785 VideoEncoderConfig video_encoder_config;
perkjfa10b552016-10-02 23:45:26 -0700786 test::FillEncoderConfiguration(1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200787 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -0700788 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
789 kMaxPayloadLength,
790 true /* nack_enabled */);
Per512ecb32016-09-23 15:52:06 +0200791
792 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200793 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700794 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100795 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700796 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700797
mflodmancc3d4422017-08-03 08:27:51 -0700798 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -0700799}
800
mflodmancc3d4422017-08-03 08:27:51 -0700801TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
802 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkjfa10b552016-10-02 23:45:26 -0700803
804 // Capture a frame and wait for it to synchronize with the encoder thread.
805 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700806 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100807 // The encoder will have been configured once.
808 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700809 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
810 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
811
812 codec_width_ *= 2;
813 codec_height_ *= 2;
814 // Capture a frame with a higher resolution and wait for it to synchronize
815 // with the encoder thread.
816 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700817 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700818 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
819 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100820 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700821
mflodmancc3d4422017-08-03 08:27:51 -0700822 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -0700823}
824
mflodmancc3d4422017-08-03 08:27:51 -0700825TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOffFor1S1TLWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800826 const bool kNackEnabled = true;
827 const size_t kNumStreams = 1;
828 const size_t kNumTl = 1;
emircanbbcc3562017-08-18 00:28:40 -0700829 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700830 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800831
832 // Capture a frame and wait for it to synchronize with the encoder thread.
833 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700834 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800835 // The encoder have been configured once when the first frame is received.
836 EXPECT_EQ(1, sink_.number_of_reconfigurations());
837 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
838 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
839 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
840 // Resilience is off for no temporal layers with nack on.
841 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700842 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800843}
844
mflodmancc3d4422017-08-03 08:27:51 -0700845TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOffFor2S1TlWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800846 const bool kNackEnabled = true;
847 const size_t kNumStreams = 2;
848 const size_t kNumTl = 1;
emircanbbcc3562017-08-18 00:28:40 -0700849 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700850 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800851
852 // Capture a frame and wait for it to synchronize with the encoder thread.
853 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700854 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800855 // The encoder have been configured once when the first frame is received.
856 EXPECT_EQ(1, sink_.number_of_reconfigurations());
857 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
858 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
859 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
860 // Resilience is off for no temporal layers and >1 streams with nack on.
861 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700862 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800863}
864
mflodmancc3d4422017-08-03 08:27:51 -0700865TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOnFor1S1TLWithNackDisabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800866 const bool kNackEnabled = false;
867 const size_t kNumStreams = 1;
868 const size_t kNumTl = 1;
emircanbbcc3562017-08-18 00:28:40 -0700869 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700870 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800871
872 // Capture a frame and wait for it to synchronize with the encoder thread.
873 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700874 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800875 // The encoder have been configured once when the first frame is received.
876 EXPECT_EQ(1, sink_.number_of_reconfigurations());
877 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
878 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
879 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
880 // Resilience is on for no temporal layers with nack off.
881 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700882 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800883}
884
mflodmancc3d4422017-08-03 08:27:51 -0700885TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOnFor1S2TlWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800886 const bool kNackEnabled = true;
887 const size_t kNumStreams = 1;
888 const size_t kNumTl = 2;
emircanbbcc3562017-08-18 00:28:40 -0700889 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700890 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800891
892 // Capture a frame and wait for it to synchronize with the encoder thread.
893 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700894 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800895 // The encoder have been configured once when the first frame is received.
896 EXPECT_EQ(1, sink_.number_of_reconfigurations());
897 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
898 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
899 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
900 // Resilience is on for temporal layers.
901 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700902 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800903}
904
emircanbbcc3562017-08-18 00:28:40 -0700905TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOffFor1SL1TLWithNackEnabled) {
906 const bool kNackEnabled = true;
907 const size_t kNumStreams = 1;
908 const size_t kNumTl = 1;
909 const unsigned char kNumSl = 1;
910 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
911 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
912
913 // Capture a frame and wait for it to synchronize with the encoder thread.
914 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
915 sink_.WaitForEncodedFrame(1);
916 // The encoder have been configured once when the first frame is received.
917 EXPECT_EQ(1, sink_.number_of_reconfigurations());
918 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
919 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
920 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
921 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
922 // Resilience is off for no spatial and temporal layers with nack on.
923 EXPECT_FALSE(fake_encoder_.codec_config().VP9()->resilienceOn);
924 video_stream_encoder_->Stop();
925}
926
927TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOnFor1SL1TLWithNackDisabled) {
928 const bool kNackEnabled = false;
929 const size_t kNumStreams = 1;
930 const size_t kNumTl = 1;
931 const unsigned char kNumSl = 1;
932 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
933 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
934
935 // Capture a frame and wait for it to synchronize with the encoder thread.
936 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
937 sink_.WaitForEncodedFrame(1);
938 // The encoder have been configured once when the first frame is received.
939 EXPECT_EQ(1, sink_.number_of_reconfigurations());
940 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
941 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
942 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
943 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
944 // Resilience is on if nack is off.
945 EXPECT_TRUE(fake_encoder_.codec_config().VP9()->resilienceOn);
946 video_stream_encoder_->Stop();
947}
948
949TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOnFor2SL1TLWithNackEnabled) {
950 const bool kNackEnabled = true;
951 const size_t kNumStreams = 1;
952 const size_t kNumTl = 1;
953 const unsigned char kNumSl = 2;
954 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
955 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
956
957 // Capture a frame and wait for it to synchronize with the encoder thread.
958 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
959 sink_.WaitForEncodedFrame(1);
960 // The encoder have been configured once when the first frame is received.
961 EXPECT_EQ(1, sink_.number_of_reconfigurations());
962 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
963 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
964 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
965 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
966 // Resilience is on for spatial layers.
967 EXPECT_TRUE(fake_encoder_.codec_config().VP9()->resilienceOn);
968 video_stream_encoder_->Stop();
969}
970
971TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOnFor1SL2TLWithNackEnabled) {
972 const bool kNackEnabled = true;
973 const size_t kNumStreams = 1;
974 const size_t kNumTl = 2;
975 const unsigned char kNumSl = 1;
976 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
977 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
978
979 // Capture a frame and wait for it to synchronize with the encoder thread.
980 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
981 sink_.WaitForEncodedFrame(1);
982 // The encoder have been configured once when the first frame is received.
983 EXPECT_EQ(1, sink_.number_of_reconfigurations());
984 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
985 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
986 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
987 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
988 // Resilience is on for temporal layers.
989 EXPECT_TRUE(fake_encoder_.codec_config().VP9()->resilienceOn);
990 video_stream_encoder_->Stop();
991}
992
mflodmancc3d4422017-08-03 08:27:51 -0700993TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -0700994 EXPECT_TRUE(video_source_.has_sinks());
995 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700996 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -0700997 &new_video_source,
998 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -0700999 EXPECT_FALSE(video_source_.has_sinks());
1000 EXPECT_TRUE(new_video_source.has_sinks());
1001
mflodmancc3d4422017-08-03 08:27:51 -07001002 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001003}
1004
mflodmancc3d4422017-08-03 08:27:51 -07001005TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -07001006 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -07001007 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -07001008 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -07001009 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001010}
1011
Jonathan Yubc771b72017-12-08 17:04:29 -08001012TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
1013 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -07001014 const int kWidth = 1280;
1015 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -08001016
1017 // We rely on the automatic resolution adaptation, but we handle framerate
1018 // adaptation manually by mocking the stats proxy.
1019 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -07001020
1021 // Enable kBalanced preference, no initial limitation.
Jonathan Yubc771b72017-12-08 17:04:29 -08001022 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -07001023 video_stream_encoder_->SetSource(
Jonathan Yubc771b72017-12-08 17:04:29 -08001024 &video_source_,
mflodmancc3d4422017-08-03 08:27:51 -07001025 VideoSendStream::DegradationPreference::kBalanced);
Jonathan Yubc771b72017-12-08 17:04:29 -08001026 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001027 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001028 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -07001029 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1030
Jonathan Yubc771b72017-12-08 17:04:29 -08001031 // Adapt down as far as possible.
1032 rtc::VideoSinkWants last_wants;
1033 int64_t t = 1;
1034 int loop_count = 0;
1035 do {
1036 ++loop_count;
1037 last_wants = video_source_.sink_wants();
1038
1039 // Simulate the framerate we've been asked to adapt to.
1040 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
1041 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
1042 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1043 mock_stats.input_frame_rate = fps;
1044 stats_proxy_->SetMockStats(mock_stats);
1045
1046 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1047 sink_.WaitForEncodedFrame(t);
1048 t += frame_interval_ms;
1049
mflodmancc3d4422017-08-03 08:27:51 -07001050 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08001051 VerifyBalancedModeFpsRange(
1052 video_source_.sink_wants(),
1053 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1054 } while (video_source_.sink_wants().max_pixel_count <
1055 last_wants.max_pixel_count ||
1056 video_source_.sink_wants().max_framerate_fps <
1057 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001058
Jonathan Yubc771b72017-12-08 17:04:29 -08001059 // Verify that we've adapted all the way down.
1060 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001061 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001062 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
1063 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -07001064 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -08001065 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
1066 *video_source_.last_sent_height());
1067 EXPECT_EQ(kMinBalancedFramerateFps,
1068 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001069
Jonathan Yubc771b72017-12-08 17:04:29 -08001070 // Adapt back up the same number of times we adapted down.
1071 for (int i = 0; i < loop_count - 1; ++i) {
1072 last_wants = video_source_.sink_wants();
1073
1074 // Simulate the framerate we've been asked to adapt to.
1075 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
1076 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
1077 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1078 mock_stats.input_frame_rate = fps;
1079 stats_proxy_->SetMockStats(mock_stats);
1080
1081 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1082 sink_.WaitForEncodedFrame(t);
1083 t += frame_interval_ms;
1084
mflodmancc3d4422017-08-03 08:27:51 -07001085 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -08001086 VerifyBalancedModeFpsRange(
1087 video_source_.sink_wants(),
1088 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1089 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
1090 last_wants.max_pixel_count ||
1091 video_source_.sink_wants().max_framerate_fps >
1092 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001093 }
1094
Jonathan Yubc771b72017-12-08 17:04:29 -08001095 VerifyNoLimitation(video_source_.sink_wants());
1096 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001097 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001098 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1099 EXPECT_EQ((loop_count - 1) * 2,
1100 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -07001101
mflodmancc3d4422017-08-03 08:27:51 -07001102 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001103}
mflodmancc3d4422017-08-03 08:27:51 -07001104TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
1105 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001106 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001107
sprangc5d62e22017-04-02 23:53:04 -07001108 const int kFrameWidth = 1280;
1109 const int kFrameHeight = 720;
1110 const int kFrameIntervalMs = 1000 / 30;
1111
1112 int frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -07001113
kthelgason5e13d412016-12-01 03:59:51 -08001114 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001115 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001116 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001117 frame_timestamp += kFrameIntervalMs;
1118
perkj803d97f2016-11-01 11:45:46 -07001119 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001120 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001121 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001122 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001123 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001124 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -07001125
asapersson0944a802017-04-07 00:57:58 -07001126 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -07001127 // wanted resolution.
1128 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
1129 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
1130 kFrameWidth * kFrameHeight);
1131 EXPECT_EQ(std::numeric_limits<int>::max(),
1132 video_source_.sink_wants().max_framerate_fps);
1133
1134 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -07001135 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001136 video_stream_encoder_->SetSource(
perkj803d97f2016-11-01 11:45:46 -07001137 &new_video_source,
1138 VideoSendStream::DegradationPreference::kMaintainResolution);
1139
sprangc5d62e22017-04-02 23:53:04 -07001140 // Initially no degradation registered.
asapersson02465b82017-04-10 01:12:52 -07001141 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001142
sprangc5d62e22017-04-02 23:53:04 -07001143 // Force an input frame rate to be available, or the adaptation call won't
1144 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -07001145 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -07001146 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -07001147 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -07001148 stats_proxy_->SetMockStats(stats);
1149
mflodmancc3d4422017-08-03 08:27:51 -07001150 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001151 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001152 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001153 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001154 frame_timestamp += kFrameIntervalMs;
1155
1156 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001157 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001158 EXPECT_EQ(std::numeric_limits<int>::max(),
1159 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001160 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001161
asapersson02465b82017-04-10 01:12:52 -07001162 // Turn off degradation completely.
mflodmancc3d4422017-08-03 08:27:51 -07001163 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001164 &new_video_source,
1165 VideoSendStream::DegradationPreference::kDegradationDisabled);
asapersson02465b82017-04-10 01:12:52 -07001166 VerifyNoLimitation(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001167
mflodmancc3d4422017-08-03 08:27:51 -07001168 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001169 new_video_source.IncomingCapturedFrame(
1170 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001171 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001172 frame_timestamp += kFrameIntervalMs;
1173
1174 // Still no degradation.
asapersson02465b82017-04-10 01:12:52 -07001175 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001176
1177 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001178 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001179 &new_video_source,
1180 VideoSendStream::DegradationPreference::kMaintainFramerate);
1181 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1182 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001183 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001184 EXPECT_EQ(std::numeric_limits<int>::max(),
1185 new_video_source.sink_wants().max_framerate_fps);
1186
1187 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001188 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001189 &new_video_source,
1190 VideoSendStream::DegradationPreference::kMaintainResolution);
1191 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1192 EXPECT_EQ(std::numeric_limits<int>::max(),
1193 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001194 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001195
mflodmancc3d4422017-08-03 08:27:51 -07001196 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001197}
1198
mflodmancc3d4422017-08-03 08:27:51 -07001199TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
1200 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001201
asaperssonfab67072017-04-04 05:51:49 -07001202 const int kWidth = 1280;
1203 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001204 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001205 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001206 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1207 EXPECT_FALSE(stats.bw_limited_resolution);
1208 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1209
1210 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001211 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001212 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001213 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001214
1215 stats = stats_proxy_->GetStats();
1216 EXPECT_TRUE(stats.bw_limited_resolution);
1217 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1218
1219 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001220 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001221 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001222 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001223
1224 stats = stats_proxy_->GetStats();
1225 EXPECT_FALSE(stats.bw_limited_resolution);
1226 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1227 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1228
mflodmancc3d4422017-08-03 08:27:51 -07001229 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001230}
1231
mflodmancc3d4422017-08-03 08:27:51 -07001232TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
1233 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001234
1235 const int kWidth = 1280;
1236 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001237 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001238 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001239 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1240 EXPECT_FALSE(stats.cpu_limited_resolution);
1241 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1242
1243 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001244 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001245 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001246 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001247
1248 stats = stats_proxy_->GetStats();
1249 EXPECT_TRUE(stats.cpu_limited_resolution);
1250 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1251
1252 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001253 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001254 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001255 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001256
1257 stats = stats_proxy_->GetStats();
1258 EXPECT_FALSE(stats.cpu_limited_resolution);
1259 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001260 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001261
mflodmancc3d4422017-08-03 08:27:51 -07001262 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001263}
1264
mflodmancc3d4422017-08-03 08:27:51 -07001265TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
1266 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001267
asaperssonfab67072017-04-04 05:51:49 -07001268 const int kWidth = 1280;
1269 const int kHeight = 720;
1270 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001271 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001272 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001273 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001274 EXPECT_FALSE(stats.cpu_limited_resolution);
1275 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1276
asaperssonfab67072017-04-04 05:51:49 -07001277 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001278 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001279 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001280 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001281 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001282 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001283 EXPECT_TRUE(stats.cpu_limited_resolution);
1284 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1285
1286 // Set new source with adaptation still enabled.
1287 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001288 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001289 &new_video_source,
1290 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001291
asaperssonfab67072017-04-04 05:51:49 -07001292 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001293 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001294 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001295 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001296 EXPECT_TRUE(stats.cpu_limited_resolution);
1297 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1298
1299 // Set adaptation disabled.
mflodmancc3d4422017-08-03 08:27:51 -07001300 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001301 &new_video_source,
sprangc5d62e22017-04-02 23:53:04 -07001302 VideoSendStream::DegradationPreference::kDegradationDisabled);
kthelgason876222f2016-11-29 01:44:11 -08001303
asaperssonfab67072017-04-04 05:51:49 -07001304 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001305 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001306 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001307 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001308 EXPECT_FALSE(stats.cpu_limited_resolution);
1309 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1310
1311 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001312 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001313 &new_video_source,
1314 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001315
asaperssonfab67072017-04-04 05:51:49 -07001316 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001317 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001318 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001319 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001320 EXPECT_TRUE(stats.cpu_limited_resolution);
1321 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1322
asaperssonfab67072017-04-04 05:51:49 -07001323 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001324 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001325 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001326 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001327 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001328 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001329 EXPECT_FALSE(stats.cpu_limited_resolution);
1330 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001331 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001332
mflodmancc3d4422017-08-03 08:27:51 -07001333 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001334}
1335
mflodmancc3d4422017-08-03 08:27:51 -07001336TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
1337 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001338
asaperssonfab67072017-04-04 05:51:49 -07001339 const int kWidth = 1280;
1340 const int kHeight = 720;
1341 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001342 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001343 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001344 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001345 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001346 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001347
1348 // Set new source with adaptation still enabled.
1349 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001350 video_stream_encoder_->SetSource(
1351 &new_video_source,
1352 VideoSendStream::DegradationPreference::kBalanced);
kthelgason876222f2016-11-29 01:44:11 -08001353
asaperssonfab67072017-04-04 05:51:49 -07001354 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001355 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001356 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001357 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001358 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001359 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001360
asaperssonfab67072017-04-04 05:51:49 -07001361 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001362 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001363 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001364 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001365 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001366 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001367 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001368 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001369
asaperssonfab67072017-04-04 05:51:49 -07001370 // Set new source with adaptation still enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001371 video_stream_encoder_->SetSource(
1372 &new_video_source,
1373 VideoSendStream::DegradationPreference::kBalanced);
kthelgason876222f2016-11-29 01:44:11 -08001374
asaperssonfab67072017-04-04 05:51:49 -07001375 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001376 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001377 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001378 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001379 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001380 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001381
asapersson02465b82017-04-10 01:12:52 -07001382 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001383 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001384 &new_video_source,
1385 VideoSendStream::DegradationPreference::kMaintainResolution);
1386
asaperssonfab67072017-04-04 05:51:49 -07001387 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001388 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001389 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001390 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001391 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001392 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1393 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001394
mflodmancc3d4422017-08-03 08:27:51 -07001395 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001396}
1397
mflodmancc3d4422017-08-03 08:27:51 -07001398TEST_F(VideoStreamEncoderTest,
1399 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1400 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001401
1402 const int kWidth = 1280;
1403 const int kHeight = 720;
1404 video_source_.set_adaptation_enabled(true);
1405 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001406 WaitForEncodedFrame(1);
asapersson36e9eb42017-03-31 05:29:12 -07001407 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1408 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1409 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1410
1411 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001412 video_stream_encoder_->TriggerQualityLow();
asapersson36e9eb42017-03-31 05:29:12 -07001413 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001414 WaitForEncodedFrame(2);
asapersson36e9eb42017-03-31 05:29:12 -07001415 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1416 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1417 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1418
1419 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001420 video_stream_encoder_->TriggerCpuOveruse();
asapersson36e9eb42017-03-31 05:29:12 -07001421 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001422 WaitForEncodedFrame(3);
asapersson36e9eb42017-03-31 05:29:12 -07001423 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1424 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1425 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1426
1427 // Set source with adaptation still enabled but quality scaler is off.
1428 fake_encoder_.SetQualityScaling(false);
mflodmancc3d4422017-08-03 08:27:51 -07001429 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001430 &video_source_,
1431 VideoSendStream::DegradationPreference::kMaintainFramerate);
asapersson36e9eb42017-03-31 05:29:12 -07001432
1433 video_source_.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001434 WaitForEncodedFrame(4);
asapersson36e9eb42017-03-31 05:29:12 -07001435 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1436 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1437 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1438
mflodmancc3d4422017-08-03 08:27:51 -07001439 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001440}
1441
mflodmancc3d4422017-08-03 08:27:51 -07001442TEST_F(VideoStreamEncoderTest,
1443 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
1444 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001445
asapersson0944a802017-04-07 00:57:58 -07001446 const int kWidth = 1280;
1447 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001448 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001449
asaperssonfab67072017-04-04 05:51:49 -07001450 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001451 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001452 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001453 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001454 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001455 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1456
asapersson02465b82017-04-10 01:12:52 -07001457 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001458 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001459 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001460 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001461 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001462 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001463 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001464 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1465
1466 // Set new source with adaptation still enabled.
1467 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001468 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001469 &new_video_source,
1470 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001471
1472 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001473 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001474 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001475 stats = stats_proxy_->GetStats();
1476 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001477 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001478 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1479
sprangc5d62e22017-04-02 23:53:04 -07001480 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001481 video_stream_encoder_->SetSource(
perkj803d97f2016-11-01 11:45:46 -07001482 &new_video_source,
1483 VideoSendStream::DegradationPreference::kMaintainResolution);
1484 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001485 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001486 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001487 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001488 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001489 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001490 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001491 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1492
sprangc5d62e22017-04-02 23:53:04 -07001493 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001494 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001495 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1496 mock_stats.input_frame_rate = 30;
1497 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001498 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001499 stats_proxy_->ResetMockStats();
1500
1501 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001502 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001503 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001504
1505 // Framerate now adapted.
1506 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001507 EXPECT_FALSE(stats.cpu_limited_resolution);
1508 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001509 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1510
1511 // Disable CPU adaptation.
mflodmancc3d4422017-08-03 08:27:51 -07001512 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001513 &new_video_source,
1514 VideoSendStream::DegradationPreference::kDegradationDisabled);
1515 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001516 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001517 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001518
1519 stats = stats_proxy_->GetStats();
1520 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001521 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001522 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1523
1524 // Try to trigger overuse. Should not succeed.
1525 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001526 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001527 stats_proxy_->ResetMockStats();
1528
1529 stats = stats_proxy_->GetStats();
1530 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001531 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001532 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1533
1534 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001535 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001536 &video_source_,
1537 VideoSendStream::DegradationPreference::kMaintainFramerate);
asaperssonfab67072017-04-04 05:51:49 -07001538 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001539 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001540 stats = stats_proxy_->GetStats();
1541 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001542 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001543 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001544
1545 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001546 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001547 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001548 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001549 stats = stats_proxy_->GetStats();
1550 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001551 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001552 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1553
1554 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001555 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001556 &new_video_source,
1557 VideoSendStream::DegradationPreference::kMaintainResolution);
1558 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001559 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001560 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001561 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001562 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001563 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001564 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001565 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1566
1567 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001568 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001569 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001570 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001571 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001572 stats = stats_proxy_->GetStats();
1573 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001574 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001575 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001576 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001577
mflodmancc3d4422017-08-03 08:27:51 -07001578 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001579}
1580
mflodmancc3d4422017-08-03 08:27:51 -07001581TEST_F(VideoStreamEncoderTest, StatsTracksPreferredBitrate) {
1582 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Erik Språng08127a92016-11-16 16:41:30 +01001583
asaperssonfab67072017-04-04 05:51:49 -07001584 const int kWidth = 1280;
1585 const int kHeight = 720;
1586 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001587 WaitForEncodedFrame(1);
Erik Språng08127a92016-11-16 16:41:30 +01001588
1589 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1590 EXPECT_EQ(video_encoder_config_.max_bitrate_bps,
1591 stats.preferred_media_bitrate_bps);
1592
mflodmancc3d4422017-08-03 08:27:51 -07001593 video_stream_encoder_->Stop();
Erik Språng08127a92016-11-16 16:41:30 +01001594}
1595
mflodmancc3d4422017-08-03 08:27:51 -07001596TEST_F(VideoStreamEncoderTest,
1597 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001598 const int kWidth = 1280;
1599 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001600 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001601
asaperssonfab67072017-04-04 05:51:49 -07001602 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001603 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001604
asaperssonfab67072017-04-04 05:51:49 -07001605 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001606 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001607
asaperssonfab67072017-04-04 05:51:49 -07001608 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001609 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001610
asaperssonfab67072017-04-04 05:51:49 -07001611 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001612 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001613
kthelgason876222f2016-11-29 01:44:11 -08001614 // Expect a scale down.
1615 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001616 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001617
asapersson02465b82017-04-10 01:12:52 -07001618 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001619 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001620 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001621 &new_video_source,
1622 VideoSendStream::DegradationPreference::kMaintainResolution);
1623
asaperssonfab67072017-04-04 05:51:49 -07001624 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001625 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001626 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001627 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001628
asaperssonfab67072017-04-04 05:51:49 -07001629 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001630 EXPECT_EQ(std::numeric_limits<int>::max(),
1631 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001632
asaperssonfab67072017-04-04 05:51:49 -07001633 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001634 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001635 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001636 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001637
asapersson02465b82017-04-10 01:12:52 -07001638 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001639 EXPECT_EQ(std::numeric_limits<int>::max(),
1640 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001641
mflodmancc3d4422017-08-03 08:27:51 -07001642 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001643}
1644
mflodmancc3d4422017-08-03 08:27:51 -07001645TEST_F(VideoStreamEncoderTest,
1646 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001647 const int kWidth = 1280;
1648 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001649 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001650
1651 // Enable kMaintainFramerate preference, no initial limitation.
1652 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001653 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001654 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1655
1656 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001657 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001658 VerifyNoLimitation(source.sink_wants());
1659 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1660 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1661
1662 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001663 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001664 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001665 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1666 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1667 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1668
1669 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001670 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001671 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1672 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1673 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1674
mflodmancc3d4422017-08-03 08:27:51 -07001675 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001676}
1677
mflodmancc3d4422017-08-03 08:27:51 -07001678TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001679 const int kWidth = 1280;
1680 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001681 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001682
1683 // Enable kBalanced preference, no initial limitation.
1684 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001685 video_stream_encoder_->SetSource(
1686 &source,
1687 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001688 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1689 sink_.WaitForEncodedFrame(1);
1690 VerifyNoLimitation(source.sink_wants());
1691
1692 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001693 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001694 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1695 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1696 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1697 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1698
1699 // Trigger adapt down for same input resolution, expect no change.
1700 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1701 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001702 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001703 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1704 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1705 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1706
1707 // Trigger adapt down for larger input resolution, expect no change.
1708 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1709 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001710 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001711 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1712 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1713 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1714
mflodmancc3d4422017-08-03 08:27:51 -07001715 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001716}
1717
mflodmancc3d4422017-08-03 08:27:51 -07001718TEST_F(VideoStreamEncoderTest,
1719 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001720 const int kWidth = 1280;
1721 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001722 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001723
1724 // Enable kMaintainFramerate preference, no initial limitation.
1725 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001726 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001727 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1728
1729 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001730 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001731 VerifyNoLimitation(source.sink_wants());
1732 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1733 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1734
1735 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001736 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001737 VerifyNoLimitation(source.sink_wants());
1738 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1739 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1740
mflodmancc3d4422017-08-03 08:27:51 -07001741 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001742}
1743
mflodmancc3d4422017-08-03 08:27:51 -07001744TEST_F(VideoStreamEncoderTest,
1745 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001746 const int kWidth = 1280;
1747 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001748 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001749
1750 // Enable kMaintainResolution preference, no initial limitation.
1751 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001752 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001753 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
1754
1755 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001756 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001757 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001758 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001759 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1760
1761 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001762 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001763 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001764 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001765 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1766
mflodmancc3d4422017-08-03 08:27:51 -07001767 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001768}
1769
mflodmancc3d4422017-08-03 08:27:51 -07001770TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001771 const int kWidth = 1280;
1772 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001773 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001774
1775 // Enable kBalanced preference, no initial limitation.
1776 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001777 video_stream_encoder_->SetSource(
1778 &source,
1779 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001780
1781 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1782 sink_.WaitForEncodedFrame(kWidth, kHeight);
1783 VerifyNoLimitation(source.sink_wants());
1784 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1785 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1786 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1787
1788 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001789 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001790 VerifyNoLimitation(source.sink_wants());
1791 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1792 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1793 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1794
mflodmancc3d4422017-08-03 08:27:51 -07001795 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001796}
1797
mflodmancc3d4422017-08-03 08:27:51 -07001798TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001799 const int kWidth = 1280;
1800 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001801 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001802
1803 // Enable kDegradationDisabled preference, no initial limitation.
1804 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001805 video_stream_encoder_->SetSource(
asapersson09f05612017-05-15 23:40:18 -07001806 &source, VideoSendStream::DegradationPreference::kDegradationDisabled);
1807
1808 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1809 sink_.WaitForEncodedFrame(kWidth, kHeight);
1810 VerifyNoLimitation(source.sink_wants());
1811 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1812 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1813 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1814
1815 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001816 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001817 VerifyNoLimitation(source.sink_wants());
1818 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1819 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1820 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1821
mflodmancc3d4422017-08-03 08:27:51 -07001822 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001823}
1824
mflodmancc3d4422017-08-03 08:27:51 -07001825TEST_F(VideoStreamEncoderTest,
1826 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001827 const int kWidth = 1280;
1828 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001829 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001830
1831 // Enable kMaintainFramerate preference, no initial limitation.
1832 AdaptingFrameForwarder source;
1833 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001834 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001835 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1836
1837 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001838 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001839 VerifyNoLimitation(source.sink_wants());
1840 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1841 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1842
1843 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001844 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001845 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001846 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001847 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001848 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1849 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1850
1851 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001852 video_stream_encoder_->TriggerQualityHigh();
asapersson02465b82017-04-10 01:12:52 -07001853 VerifyNoLimitation(source.sink_wants());
1854 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1855 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1856 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1857
mflodmancc3d4422017-08-03 08:27:51 -07001858 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001859}
1860
mflodmancc3d4422017-08-03 08:27:51 -07001861TEST_F(VideoStreamEncoderTest,
1862 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001863 const int kWidth = 1280;
1864 const int kHeight = 720;
1865 const int kInputFps = 30;
mflodmancc3d4422017-08-03 08:27:51 -07001866 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001867
1868 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1869 stats.input_frame_rate = kInputFps;
1870 stats_proxy_->SetMockStats(stats);
1871
1872 // Expect no scaling to begin with (preference: kMaintainFramerate).
1873 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1874 sink_.WaitForEncodedFrame(1);
1875 VerifyNoLimitation(video_source_.sink_wants());
1876
1877 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001878 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001879 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1880 sink_.WaitForEncodedFrame(2);
1881 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1882
1883 // Enable kMaintainResolution preference.
1884 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001885 video_stream_encoder_->SetSource(
asapersson09f05612017-05-15 23:40:18 -07001886 &new_video_source,
1887 VideoSendStream::DegradationPreference::kMaintainResolution);
1888 VerifyNoLimitation(new_video_source.sink_wants());
1889
1890 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001891 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001892 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1893 sink_.WaitForEncodedFrame(3);
1894 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1895
1896 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001897 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001898 VerifyNoLimitation(new_video_source.sink_wants());
1899
mflodmancc3d4422017-08-03 08:27:51 -07001900 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001901}
1902
mflodmancc3d4422017-08-03 08:27:51 -07001903TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001904 const int kWidth = 1280;
1905 const int kHeight = 720;
1906 const size_t kNumFrames = 10;
1907
mflodmancc3d4422017-08-03 08:27:51 -07001908 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001909
asaperssond0de2952017-04-21 01:47:31 -07001910 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001911 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001912 video_source_.set_adaptation_enabled(true);
1913
1914 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1915 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1916
1917 int downscales = 0;
1918 for (size_t i = 1; i <= kNumFrames; i++) {
1919 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001920 WaitForEncodedFrame(i);
asaperssond0de2952017-04-21 01:47:31 -07001921
asaperssonfab67072017-04-04 05:51:49 -07001922 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001923 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001924 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001925 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001926
1927 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1928 ++downscales;
1929
1930 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1931 EXPECT_EQ(downscales,
1932 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1933 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001934 }
mflodmancc3d4422017-08-03 08:27:51 -07001935 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001936}
1937
mflodmancc3d4422017-08-03 08:27:51 -07001938TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001939 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1940 const int kWidth = 1280;
1941 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001942 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001943
1944 // Enable kMaintainFramerate preference, no initial limitation.
1945 AdaptingFrameForwarder source;
1946 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001947 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07001948 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1949
1950 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001951 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001952 VerifyNoLimitation(source.sink_wants());
1953 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1954 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1955
1956 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001957 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001958 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001959 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001960 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001961 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1962 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1963
1964 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001965 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07001966 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001967 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001968 VerifyNoLimitation(source.sink_wants());
1969 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1970 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1971
1972 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001973 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001974 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001975 WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07001976 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001977 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1978 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1979
1980 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001981 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson09f05612017-05-15 23:40:18 -07001982 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1983 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001984 VerifyNoLimitation(source.sink_wants());
1985 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1986 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1987
mflodmancc3d4422017-08-03 08:27:51 -07001988 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001989}
1990
mflodmancc3d4422017-08-03 08:27:51 -07001991TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07001992 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
1993 const int kWidth = 1280;
1994 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001995 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001996
1997 // Enable kBalanced preference, no initial limitation.
1998 AdaptingFrameForwarder source;
1999 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002000 video_stream_encoder_->SetSource(
2001 &source,
2002 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002003
2004 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2005 sink_.WaitForEncodedFrame(kWidth, kHeight);
2006 VerifyNoLimitation(source.sink_wants());
2007 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2008 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2009
2010 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002011 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002012 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
2013 sink_.WaitForEncodedFrame(2);
2014 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2015 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2016 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2017
2018 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002019 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002020 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
2021 sink_.WaitForEncodedFrame(kWidth, kHeight);
2022 VerifyNoLimitation(source.sink_wants());
2023 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2024 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2025
2026 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002027 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002028 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
2029 sink_.WaitForEncodedFrame(4);
2030 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2031 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2032 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2033
2034 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002035 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002036 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
2037 sink_.WaitForEncodedFrame(kWidth, kHeight);
2038 VerifyNoLimitation(source.sink_wants());
2039 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2040 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2041
mflodmancc3d4422017-08-03 08:27:51 -07002042 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002043}
2044
mflodmancc3d4422017-08-03 08:27:51 -07002045TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002046 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
2047 const int kWidth = 1280;
2048 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07002049 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002050
2051 // Enable kMaintainFramerate preference, no initial limitation.
2052 AdaptingFrameForwarder source;
2053 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002054 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07002055 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
2056
2057 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002058 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002059 VerifyNoLimitation(source.sink_wants());
2060 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2061 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2062 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2063 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2064
2065 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002066 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002067 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002068 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07002069 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002070 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2071 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2072 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2073 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2074
2075 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07002076 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002077 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002078 WaitForEncodedFrame(3);
asapersson09f05612017-05-15 23:40:18 -07002079 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002080 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2081 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2082 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2083 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2084
Jonathan Yubc771b72017-12-08 17:04:29 -08002085 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002086 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002087 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002088 WaitForEncodedFrame(4);
Jonathan Yubc771b72017-12-08 17:04:29 -08002089 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002090 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2091 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002092 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002093 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2094
Jonathan Yubc771b72017-12-08 17:04:29 -08002095 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07002096 video_stream_encoder_->TriggerQualityLow();
asaperssond0de2952017-04-21 01:47:31 -07002097 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002098 WaitForEncodedFrame(5);
asapersson09f05612017-05-15 23:40:18 -07002099 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002100 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07002101 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2102 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2103 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2104 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2105
Jonathan Yubc771b72017-12-08 17:04:29 -08002106 // Trigger quality adapt down, expect no change (min resolution reached).
2107 video_stream_encoder_->TriggerQualityLow();
2108 source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
2109 WaitForEncodedFrame(6);
2110 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
2111 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2112 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2113 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2114 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2115
2116 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002117 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07002118 source.IncomingCapturedFrame(CreateFrame(7, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002119 WaitForEncodedFrame(7);
asapersson09f05612017-05-15 23:40:18 -07002120 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002121 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2122 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2123 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2124 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2125
2126 // Trigger cpu adapt up, expect upscaled resolution (640x360).
2127 video_stream_encoder_->TriggerCpuNormalUsage();
2128 source.IncomingCapturedFrame(CreateFrame(8, kWidth, kHeight));
2129 WaitForEncodedFrame(8);
2130 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2131 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2132 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2133 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2134 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2135
2136 // Trigger cpu adapt up, expect upscaled resolution (960x540).
2137 video_stream_encoder_->TriggerCpuNormalUsage();
2138 source.IncomingCapturedFrame(CreateFrame(9, kWidth, kHeight));
2139 WaitForEncodedFrame(9);
2140 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002141 last_wants = source.sink_wants();
2142 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2143 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002144 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002145 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2146
2147 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002148 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -08002149 source.IncomingCapturedFrame(CreateFrame(10, kWidth, kHeight));
2150 WaitForEncodedFrame(10);
asapersson09f05612017-05-15 23:40:18 -07002151 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002152 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2153 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002154 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002155 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2156
2157 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002158 video_stream_encoder_->TriggerQualityHigh();
Jonathan Yubc771b72017-12-08 17:04:29 -08002159 source.IncomingCapturedFrame(CreateFrame(11, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002160 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002161 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002162 VerifyNoLimitation(source.sink_wants());
2163 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2164 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002165 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002166 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002167
mflodmancc3d4422017-08-03 08:27:51 -07002168 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002169}
2170
mflodmancc3d4422017-08-03 08:27:51 -07002171TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002172 const int kWidth = 640;
2173 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002174
mflodmancc3d4422017-08-03 08:27:51 -07002175 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002176
perkj803d97f2016-11-01 11:45:46 -07002177 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002178 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002179 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002180 }
2181
mflodmancc3d4422017-08-03 08:27:51 -07002182 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002183 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002184 video_source_.IncomingCapturedFrame(CreateFrame(
2185 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002186 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002187 }
2188
mflodmancc3d4422017-08-03 08:27:51 -07002189 video_stream_encoder_->Stop();
2190 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002191 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002192
perkj803d97f2016-11-01 11:45:46 -07002193 EXPECT_EQ(1,
2194 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2195 EXPECT_EQ(
2196 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2197}
2198
mflodmancc3d4422017-08-03 08:27:51 -07002199TEST_F(VideoStreamEncoderTest,
2200 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2201 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002202 const int kWidth = 640;
2203 const int kHeight = 360;
2204
mflodmancc3d4422017-08-03 08:27:51 -07002205 video_stream_encoder_->SetSource(
asaperssonf4e44af2017-04-19 02:01:06 -07002206 &video_source_,
2207 VideoSendStream::DegradationPreference::kDegradationDisabled);
2208
2209 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2210 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002211 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002212 }
2213
mflodmancc3d4422017-08-03 08:27:51 -07002214 video_stream_encoder_->Stop();
2215 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002216 stats_proxy_.reset();
2217
2218 EXPECT_EQ(0,
2219 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2220}
2221
mflodmancc3d4422017-08-03 08:27:51 -07002222TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002223 MockBitrateObserver bitrate_observer;
mflodmancc3d4422017-08-03 08:27:51 -07002224 video_stream_encoder_->SetBitrateObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002225
2226 const int kDefaultFps = 30;
2227 const BitrateAllocation expected_bitrate =
2228 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002229 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002230
2231 // First called on bitrate updated, then again on first frame.
2232 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2233 .Times(2);
mflodmancc3d4422017-08-03 08:27:51 -07002234 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002235
2236 const int64_t kStartTimeMs = 1;
2237 video_source_.IncomingCapturedFrame(
2238 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002239 WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002240
2241 // Not called on second frame.
2242 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2243 .Times(0);
2244 video_source_.IncomingCapturedFrame(
2245 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002246 WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002247
2248 // Called after a process interval.
2249 const int64_t kProcessIntervalMs =
2250 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang4847ae62017-06-27 07:06:52 -07002251 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec *
2252 (kProcessIntervalMs + (1000 / kDefaultFps)));
sprang57c2fff2017-01-16 06:24:02 -08002253 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2254 .Times(1);
2255 video_source_.IncomingCapturedFrame(CreateFrame(
2256 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002257 WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002258
mflodmancc3d4422017-08-03 08:27:51 -07002259 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002260}
2261
Niels Möller7dc26b72017-12-06 10:27:48 +01002262TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2263 const int kFrameWidth = 1280;
2264 const int kFrameHeight = 720;
2265 const int kFramerate = 24;
2266
2267 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2268 test::FrameForwarder source;
2269 video_stream_encoder_->SetSource(
2270 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2271
2272 // Insert a single frame, triggering initial configuration.
2273 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2274 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2275
2276 EXPECT_EQ(
2277 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2278 kDefaultFramerate);
2279
2280 // Trigger reconfigure encoder (without resetting the entire instance).
2281 VideoEncoderConfig video_encoder_config;
2282 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2283 video_encoder_config.number_of_streams = 1;
2284 video_encoder_config.video_stream_factory =
2285 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2286 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2287 kMaxPayloadLength, false);
2288 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2289
2290 // Detector should be updated with fps limit from codec config.
2291 EXPECT_EQ(
2292 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2293 kFramerate);
2294
2295 // Trigger overuse, max framerate should be reduced.
2296 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2297 stats.input_frame_rate = kFramerate;
2298 stats_proxy_->SetMockStats(stats);
2299 video_stream_encoder_->TriggerCpuOveruse();
2300 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2301 int adapted_framerate =
2302 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2303 EXPECT_LT(adapted_framerate, kFramerate);
2304
2305 // Trigger underuse, max framerate should go back to codec configured fps.
2306 // Set extra low fps, to make sure it's actually reset, not just incremented.
2307 stats = stats_proxy_->GetStats();
2308 stats.input_frame_rate = adapted_framerate / 2;
2309 stats_proxy_->SetMockStats(stats);
2310 video_stream_encoder_->TriggerCpuNormalUsage();
2311 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2312 EXPECT_EQ(
2313 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2314 kFramerate);
2315
2316 video_stream_encoder_->Stop();
2317}
2318
2319TEST_F(VideoStreamEncoderTest,
2320 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2321 const int kFrameWidth = 1280;
2322 const int kFrameHeight = 720;
2323 const int kLowFramerate = 15;
2324 const int kHighFramerate = 25;
2325
2326 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2327 test::FrameForwarder source;
2328 video_stream_encoder_->SetSource(
2329 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2330
2331 // Trigger initial configuration.
2332 VideoEncoderConfig video_encoder_config;
2333 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2334 video_encoder_config.number_of_streams = 1;
2335 video_encoder_config.video_stream_factory =
2336 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2337 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2338 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2339 kMaxPayloadLength, false);
2340 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2341
2342 EXPECT_EQ(
2343 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2344 kLowFramerate);
2345
2346 // Trigger overuse, max framerate should be reduced.
2347 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2348 stats.input_frame_rate = kLowFramerate;
2349 stats_proxy_->SetMockStats(stats);
2350 video_stream_encoder_->TriggerCpuOveruse();
2351 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2352 int adapted_framerate =
2353 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2354 EXPECT_LT(adapted_framerate, kLowFramerate);
2355
2356 // Reconfigure the encoder with a new (higher max framerate), max fps should
2357 // still respect the adaptation.
2358 video_encoder_config.video_stream_factory =
2359 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2360 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2361 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2362 kMaxPayloadLength, false);
2363 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2364
2365 EXPECT_EQ(
2366 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2367 adapted_framerate);
2368
2369 // Trigger underuse, max framerate should go back to codec configured fps.
2370 stats = stats_proxy_->GetStats();
2371 stats.input_frame_rate = adapted_framerate;
2372 stats_proxy_->SetMockStats(stats);
2373 video_stream_encoder_->TriggerCpuNormalUsage();
2374 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2375 EXPECT_EQ(
2376 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2377 kHighFramerate);
2378
2379 video_stream_encoder_->Stop();
2380}
2381
mflodmancc3d4422017-08-03 08:27:51 -07002382TEST_F(VideoStreamEncoderTest,
2383 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002384 const int kFrameWidth = 1280;
2385 const int kFrameHeight = 720;
2386 const int kFramerate = 24;
2387
mflodmancc3d4422017-08-03 08:27:51 -07002388 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002389 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002390 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002391 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2392
2393 // Trigger initial configuration.
2394 VideoEncoderConfig video_encoder_config;
2395 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2396 video_encoder_config.number_of_streams = 1;
2397 video_encoder_config.video_stream_factory =
2398 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2399 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002400 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2401 kMaxPayloadLength, false);
2402 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002403
Niels Möller7dc26b72017-12-06 10:27:48 +01002404 EXPECT_EQ(
2405 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2406 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002407
2408 // Trigger overuse, max framerate should be reduced.
2409 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2410 stats.input_frame_rate = kFramerate;
2411 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002412 video_stream_encoder_->TriggerCpuOveruse();
2413 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002414 int adapted_framerate =
2415 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002416 EXPECT_LT(adapted_framerate, kFramerate);
2417
2418 // Change degradation preference to not enable framerate scaling. Target
2419 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002420 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002421 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07002422 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002423 EXPECT_EQ(
2424 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2425 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002426
mflodmancc3d4422017-08-03 08:27:51 -07002427 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002428}
2429
mflodmancc3d4422017-08-03 08:27:51 -07002430TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002431 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002432 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002433 const int kWidth = 640;
2434 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002435
asaperssonfab67072017-04-04 05:51:49 -07002436 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002437
2438 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002439 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002440
2441 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002442 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002443
sprangc5d62e22017-04-02 23:53:04 -07002444 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002445
asaperssonfab67072017-04-04 05:51:49 -07002446 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002447 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002448 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002449
2450 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002451 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002452
sprangc5d62e22017-04-02 23:53:04 -07002453 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002454
mflodmancc3d4422017-08-03 08:27:51 -07002455 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002456}
2457
mflodmancc3d4422017-08-03 08:27:51 -07002458TEST_F(VideoStreamEncoderTest,
2459 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002460 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002461 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002462 const int kWidth = 640;
2463 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002464
2465 // We expect the n initial frames to get dropped.
2466 int i;
2467 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002468 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002469 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002470 }
2471 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002472 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002473 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002474
2475 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002476 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002477
mflodmancc3d4422017-08-03 08:27:51 -07002478 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002479}
2480
mflodmancc3d4422017-08-03 08:27:51 -07002481TEST_F(VideoStreamEncoderTest,
2482 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002483 const int kWidth = 640;
2484 const int kHeight = 360;
mflodmancc3d4422017-08-03 08:27:51 -07002485 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002486
2487 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002488 video_stream_encoder_->SetSource(
kthelgason2bc68642017-02-07 07:02:22 -08002489 &video_source_,
2490 VideoSendStream::DegradationPreference::kMaintainResolution);
2491
asaperssonfab67072017-04-04 05:51:49 -07002492 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002493 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002494 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002495
mflodmancc3d4422017-08-03 08:27:51 -07002496 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002497}
2498
mflodmancc3d4422017-08-03 08:27:51 -07002499TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002500 const int kWidth = 640;
2501 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002502 fake_encoder_.SetQualityScaling(false);
mflodmancc3d4422017-08-03 08:27:51 -07002503 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002504
kthelgasonb83797b2017-02-14 11:57:25 -08002505 // Force quality scaler reconfiguration by resetting the source.
mflodmancc3d4422017-08-03 08:27:51 -07002506 video_stream_encoder_->SetSource(
2507 &video_source_,
2508 VideoSendStream::DegradationPreference::kBalanced);
kthelgasonad9010c2017-02-14 00:46:51 -08002509
asaperssonfab67072017-04-04 05:51:49 -07002510 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002511 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002512 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002513
mflodmancc3d4422017-08-03 08:27:51 -07002514 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002515 fake_encoder_.SetQualityScaling(true);
2516}
2517
mflodmancc3d4422017-08-03 08:27:51 -07002518TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002519 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2520 const int kTooSmallWidth = 10;
2521 const int kTooSmallHeight = 10;
mflodmancc3d4422017-08-03 08:27:51 -07002522 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002523
2524 // Enable kMaintainFramerate preference, no initial limitation.
2525 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002526 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07002527 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
2528 VerifyNoLimitation(source.sink_wants());
2529 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2530
2531 // Trigger adapt down, too small frame, expect no change.
2532 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002533 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002534 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002535 VerifyNoLimitation(source.sink_wants());
2536 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2537 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2538
mflodmancc3d4422017-08-03 08:27:51 -07002539 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002540}
2541
mflodmancc3d4422017-08-03 08:27:51 -07002542TEST_F(VideoStreamEncoderTest,
2543 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002544 const int kTooSmallWidth = 10;
2545 const int kTooSmallHeight = 10;
2546 const int kFpsLimit = 7;
mflodmancc3d4422017-08-03 08:27:51 -07002547 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002548
2549 // Enable kBalanced preference, no initial limitation.
2550 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002551 video_stream_encoder_->SetSource(
2552 &source,
2553 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002554 VerifyNoLimitation(source.sink_wants());
2555 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2556 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2557
2558 // Trigger adapt down, expect limited framerate.
2559 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002560 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002561 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002562 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2563 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2564 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2565 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2566
2567 // Trigger adapt down, too small frame, expect no change.
2568 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002569 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002570 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002571 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2572 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2573 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2574 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2575
mflodmancc3d4422017-08-03 08:27:51 -07002576 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002577}
2578
mflodmancc3d4422017-08-03 08:27:51 -07002579TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002580 fake_encoder_.ForceInitEncodeFailure(true);
mflodmancc3d4422017-08-03 08:27:51 -07002581 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
emircanbbcc3562017-08-18 00:28:40 -07002582 ResetEncoder("VP8", 2, 1, 1, true, false);
asapersson02465b82017-04-10 01:12:52 -07002583 const int kFrameWidth = 1280;
2584 const int kFrameHeight = 720;
2585 video_source_.IncomingCapturedFrame(
2586 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002587 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002588 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002589}
2590
sprangb1ca0732017-02-01 08:38:12 -08002591// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002592TEST_F(VideoStreamEncoderTest,
2593 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
2594 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002595
2596 const int kFrameWidth = 1280;
2597 const int kFrameHeight = 720;
2598 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002599 // requested by
2600 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002601 video_source_.set_adaptation_enabled(true);
2602
2603 video_source_.IncomingCapturedFrame(
2604 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002605 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002606
2607 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002608 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002609 video_source_.IncomingCapturedFrame(
2610 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002611 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002612
asaperssonfab67072017-04-04 05:51:49 -07002613 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002614 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002615 video_source_.IncomingCapturedFrame(
2616 CreateFrame(3, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002617 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002618
mflodmancc3d4422017-08-03 08:27:51 -07002619 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002620}
sprangfe627f32017-03-29 08:24:59 -07002621
mflodmancc3d4422017-08-03 08:27:51 -07002622TEST_F(VideoStreamEncoderTest,
2623 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002624 const int kFrameWidth = 1280;
2625 const int kFrameHeight = 720;
sprang4847ae62017-06-27 07:06:52 -07002626 int kFrameIntervalMs = rtc::kNumMillisecsPerSec / max_framerate_;
sprangc5d62e22017-04-02 23:53:04 -07002627
mflodmancc3d4422017-08-03 08:27:51 -07002628 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2629 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07002630 &video_source_,
2631 VideoSendStream::DegradationPreference::kMaintainResolution);
2632 video_source_.set_adaptation_enabled(true);
2633
sprang4847ae62017-06-27 07:06:52 -07002634 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002635
2636 video_source_.IncomingCapturedFrame(
2637 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002638 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002639
2640 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002641 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002642
2643 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002644 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002645 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002646 video_source_.IncomingCapturedFrame(
2647 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002648 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002649 }
2650
2651 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002652 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002653 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002654 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002655 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002656 video_source_.IncomingCapturedFrame(
2657 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002658 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002659 ++num_frames_dropped;
2660 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002661 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002662 }
2663 }
2664
sprang4847ae62017-06-27 07:06:52 -07002665 // Add some slack to account for frames dropped by the frame dropper.
2666 const int kErrorMargin = 1;
2667 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002668 kErrorMargin);
2669
2670 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002671 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002672 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002673 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002674 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002675 video_source_.IncomingCapturedFrame(
2676 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002677 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002678 ++num_frames_dropped;
2679 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002680 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002681 }
2682 }
sprang4847ae62017-06-27 07:06:52 -07002683 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002684 kErrorMargin);
2685
2686 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002687 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002688 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002689 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002690 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002691 video_source_.IncomingCapturedFrame(
2692 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002693 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002694 ++num_frames_dropped;
2695 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002696 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002697 }
2698 }
sprang4847ae62017-06-27 07:06:52 -07002699 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002700 kErrorMargin);
2701
2702 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002703 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002704 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002705 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002706 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002707 video_source_.IncomingCapturedFrame(
2708 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002709 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002710 ++num_frames_dropped;
2711 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002712 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002713 }
2714 }
2715 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2716
mflodmancc3d4422017-08-03 08:27:51 -07002717 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002718}
2719
mflodmancc3d4422017-08-03 08:27:51 -07002720TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002721 const int kFramerateFps = 5;
2722 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002723 const int kFrameWidth = 1280;
2724 const int kFrameHeight = 720;
2725
sprang4847ae62017-06-27 07:06:52 -07002726 // Reconfigure encoder with two temporal layers and screensharing, which will
2727 // disable frame dropping and make testing easier.
emircanbbcc3562017-08-18 00:28:40 -07002728 ResetEncoder("VP8", 1, 2, 1, true, true);
sprang4847ae62017-06-27 07:06:52 -07002729
mflodmancc3d4422017-08-03 08:27:51 -07002730 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2731 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07002732 &video_source_,
2733 VideoSendStream::DegradationPreference::kMaintainResolution);
2734 video_source_.set_adaptation_enabled(true);
2735
sprang4847ae62017-06-27 07:06:52 -07002736 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002737
2738 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08002739 rtc::VideoSinkWants last_wants;
2740 do {
2741 last_wants = video_source_.sink_wants();
2742
sprangc5d62e22017-04-02 23:53:04 -07002743 // Insert frames to get a new fps estimate...
2744 for (int j = 0; j < kFramerateFps; ++j) {
2745 video_source_.IncomingCapturedFrame(
2746 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08002747 if (video_source_.last_sent_width()) {
2748 sink_.WaitForEncodedFrame(timestamp_ms);
2749 }
sprangc5d62e22017-04-02 23:53:04 -07002750 timestamp_ms += kFrameIntervalMs;
Jonathan Yubc771b72017-12-08 17:04:29 -08002751 fake_clock_.AdvanceTimeMicros(
2752 kFrameIntervalMs * rtc::kNumMicrosecsPerMillisec);
sprangc5d62e22017-04-02 23:53:04 -07002753 }
2754 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002755 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08002756 } while (video_source_.sink_wants().max_framerate_fps <
2757 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07002758
Jonathan Yubc771b72017-12-08 17:04:29 -08002759 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07002760
mflodmancc3d4422017-08-03 08:27:51 -07002761 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002762}
asaperssonf7e294d2017-06-13 23:25:22 -07002763
mflodmancc3d4422017-08-03 08:27:51 -07002764TEST_F(VideoStreamEncoderTest,
2765 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002766 const int kWidth = 1280;
2767 const int kHeight = 720;
2768 const int64_t kFrameIntervalMs = 150;
2769 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002770 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002771
2772 // Enable kBalanced preference, no initial limitation.
2773 AdaptingFrameForwarder source;
2774 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002775 video_stream_encoder_->SetSource(
2776 &source,
2777 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002778 timestamp_ms += kFrameIntervalMs;
2779 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002780 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002781 VerifyNoLimitation(source.sink_wants());
2782 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2783 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2784 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2785
2786 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002787 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002788 timestamp_ms += kFrameIntervalMs;
2789 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002790 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002791 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2792 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2793 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2794 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2795
2796 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002797 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002798 timestamp_ms += kFrameIntervalMs;
2799 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002800 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002801 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2802 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2803 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2804 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2805
2806 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002807 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002808 timestamp_ms += kFrameIntervalMs;
2809 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002810 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002811 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2812 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2813 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2814 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2815
2816 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002817 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002818 timestamp_ms += kFrameIntervalMs;
2819 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002820 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002821 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2822 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2823 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2824 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2825
2826 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002827 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002828 timestamp_ms += kFrameIntervalMs;
2829 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002830 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002831 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2832 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2833 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2834 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2835
2836 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002837 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002838 timestamp_ms += kFrameIntervalMs;
2839 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002840 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002841 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2842 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2843 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2844 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2845
2846 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002847 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002848 timestamp_ms += kFrameIntervalMs;
2849 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002850 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002851 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2852 rtc::VideoSinkWants last_wants = source.sink_wants();
2853 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2854 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2855 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2856
2857 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002858 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002859 timestamp_ms += kFrameIntervalMs;
2860 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002861 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002862 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2863 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2864 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2865 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2866
2867 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002868 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002869 timestamp_ms += kFrameIntervalMs;
2870 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002871 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002872 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2873 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2874 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2875 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2876
2877 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002878 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002879 timestamp_ms += kFrameIntervalMs;
2880 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002881 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002882 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2883 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2884 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2885 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2886
2887 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002888 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002889 timestamp_ms += kFrameIntervalMs;
2890 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002891 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002892 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2893 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2894 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2895 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2896
2897 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002898 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002899 timestamp_ms += kFrameIntervalMs;
2900 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002901 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002902 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2903 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2904 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2905 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2906
2907 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002908 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002909 timestamp_ms += kFrameIntervalMs;
2910 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002911 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002912 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2913 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2914 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2915 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2916
2917 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002918 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002919 timestamp_ms += kFrameIntervalMs;
2920 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002921 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002922 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2923 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2924 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2925 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2926
2927 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002928 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002929 timestamp_ms += kFrameIntervalMs;
2930 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002931 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002932 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2933 VerifyNoLimitation(source.sink_wants());
2934 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2935 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2936 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2937
2938 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002939 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002940 VerifyNoLimitation(source.sink_wants());
2941 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2942
mflodmancc3d4422017-08-03 08:27:51 -07002943 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002944}
2945
mflodmancc3d4422017-08-03 08:27:51 -07002946TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07002947 const int kWidth = 1280;
2948 const int kHeight = 720;
2949 const int64_t kFrameIntervalMs = 150;
2950 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002951 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002952
2953 // Enable kBalanced preference, no initial limitation.
2954 AdaptingFrameForwarder source;
2955 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002956 video_stream_encoder_->SetSource(
2957 &source,
2958 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002959 timestamp_ms += kFrameIntervalMs;
2960 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002961 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002962 VerifyNoLimitation(source.sink_wants());
2963 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2964 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2965 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2966 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2967 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2968 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2969
2970 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002971 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002972 timestamp_ms += kFrameIntervalMs;
2973 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002974 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002975 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2976 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2977 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2978 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2979 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2980 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2981 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2982
2983 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002984 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002985 timestamp_ms += kFrameIntervalMs;
2986 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002987 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002988 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2989 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2990 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2991 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2992 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2993 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2994 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2995
2996 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002997 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002998 timestamp_ms += kFrameIntervalMs;
2999 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003000 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003001 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
3002 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3003 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3004 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3005 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3006 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3007 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3008
3009 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003010 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003011 timestamp_ms += kFrameIntervalMs;
3012 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003013 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003014 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
3015 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3016 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3017 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3018 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3019 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3020 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3021
3022 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003023 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003024 timestamp_ms += kFrameIntervalMs;
3025 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003026 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003027 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3028 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3029 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3030 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3031 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3032 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3033 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3034
3035 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003036 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003037 timestamp_ms += kFrameIntervalMs;
3038 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003039 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003040 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3041 VerifyNoLimitation(source.sink_wants());
3042 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3043 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3044 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3045 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3046 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3047 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3048
3049 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003050 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003051 VerifyNoLimitation(source.sink_wants());
3052 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3053 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3054
mflodmancc3d4422017-08-03 08:27:51 -07003055 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003056}
3057
mflodmancc3d4422017-08-03 08:27:51 -07003058TEST_F(VideoStreamEncoderTest,
3059 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07003060 const int kWidth = 640;
3061 const int kHeight = 360;
3062 const int kFpsLimit = 15;
3063 const int64_t kFrameIntervalMs = 150;
3064 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07003065 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07003066
3067 // Enable kBalanced preference, no initial limitation.
3068 AdaptingFrameForwarder source;
3069 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07003070 video_stream_encoder_->SetSource(
3071 &source,
3072 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07003073 timestamp_ms += kFrameIntervalMs;
3074 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003075 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003076 VerifyNoLimitation(source.sink_wants());
3077 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3078 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3079 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3080 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3081 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3082 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3083
3084 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003085 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003086 timestamp_ms += kFrameIntervalMs;
3087 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003088 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003089 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
3090 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3091 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3092 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3093 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3094 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3095 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3096
3097 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003098 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003099 timestamp_ms += kFrameIntervalMs;
3100 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003101 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003102 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
3103 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3104 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3105 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3106 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3107 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3108 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3109
3110 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003111 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003112 timestamp_ms += kFrameIntervalMs;
3113 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003114 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003115 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3116 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3117 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3118 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3119 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3120 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3121 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3122
3123 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003124 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003125 timestamp_ms += kFrameIntervalMs;
3126 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003127 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003128 VerifyNoLimitation(source.sink_wants());
3129 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3130 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3131 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3132 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3133 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3134 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3135
3136 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003137 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003138 VerifyNoLimitation(source.sink_wants());
3139 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3140 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3141
mflodmancc3d4422017-08-03 08:27:51 -07003142 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003143}
3144
mflodmancc3d4422017-08-03 08:27:51 -07003145TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003146 // Simulates simulcast behavior and makes highest stream resolutions divisible
3147 // by 4.
3148 class CroppingVideoStreamFactory
3149 : public VideoEncoderConfig::VideoStreamFactoryInterface {
3150 public:
3151 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
3152 int framerate)
3153 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
3154 EXPECT_GT(num_temporal_layers, 0u);
3155 EXPECT_GT(framerate, 0);
3156 }
3157
3158 private:
3159 std::vector<VideoStream> CreateEncoderStreams(
3160 int width,
3161 int height,
3162 const VideoEncoderConfig& encoder_config) override {
3163 std::vector<VideoStream> streams =
3164 test::CreateVideoStreams(width - width % 4, height - height % 4,
3165 encoder_config);
3166 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +01003167 stream.num_temporal_layers = num_temporal_layers_;
ilnik6b826ef2017-06-16 06:53:48 -07003168 stream.max_framerate = framerate_;
3169 }
3170 return streams;
3171 }
3172
3173 const size_t num_temporal_layers_;
3174 const int framerate_;
3175 };
3176
3177 const int kFrameWidth = 1920;
3178 const int kFrameHeight = 1080;
3179 // 3/4 of 1920.
3180 const int kAdaptedFrameWidth = 1440;
3181 // 3/4 of 1080 rounded down to multiple of 4.
3182 const int kAdaptedFrameHeight = 808;
3183 const int kFramerate = 24;
3184
mflodmancc3d4422017-08-03 08:27:51 -07003185 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003186 // Trigger reconfigure encoder (without resetting the entire instance).
3187 VideoEncoderConfig video_encoder_config;
3188 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3189 video_encoder_config.number_of_streams = 1;
3190 video_encoder_config.video_stream_factory =
3191 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003192 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
3193 kMaxPayloadLength, false);
3194 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003195
3196 video_source_.set_adaptation_enabled(true);
3197
3198 video_source_.IncomingCapturedFrame(
3199 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003200 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003201
3202 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003203 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003204 video_source_.IncomingCapturedFrame(
3205 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003206 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003207
mflodmancc3d4422017-08-03 08:27:51 -07003208 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003209}
3210
mflodmancc3d4422017-08-03 08:27:51 -07003211TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003212 const int kFrameWidth = 1280;
3213 const int kFrameHeight = 720;
3214 const int kLowFps = 2;
3215 const int kHighFps = 30;
3216
mflodmancc3d4422017-08-03 08:27:51 -07003217 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003218
3219 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3220 max_framerate_ = kLowFps;
3221
3222 // Insert 2 seconds of 2fps video.
3223 for (int i = 0; i < kLowFps * 2; ++i) {
3224 video_source_.IncomingCapturedFrame(
3225 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3226 WaitForEncodedFrame(timestamp_ms);
3227 timestamp_ms += 1000 / kLowFps;
3228 }
3229
3230 // Make sure encoder is updated with new target.
mflodmancc3d4422017-08-03 08:27:51 -07003231 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003232 video_source_.IncomingCapturedFrame(
3233 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3234 WaitForEncodedFrame(timestamp_ms);
3235 timestamp_ms += 1000 / kLowFps;
3236
3237 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3238
3239 // Insert 30fps frames for just a little more than the forced update period.
3240 const int kVcmTimerIntervalFrames =
3241 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3242 const int kFrameIntervalMs = 1000 / kHighFps;
3243 max_framerate_ = kHighFps;
3244 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3245 video_source_.IncomingCapturedFrame(
3246 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3247 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3248 // be dropped if the encoder hans't been updated with the new higher target
3249 // framerate yet, causing it to overshoot the target bitrate and then
3250 // suffering the wrath of the media optimizer.
3251 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3252 timestamp_ms += kFrameIntervalMs;
3253 }
3254
3255 // Don expect correct measurement just yet, but it should be higher than
3256 // before.
3257 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3258
mflodmancc3d4422017-08-03 08:27:51 -07003259 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003260}
3261
mflodmancc3d4422017-08-03 08:27:51 -07003262TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003263 const int kFrameWidth = 1280;
3264 const int kFrameHeight = 720;
3265 const int kTargetBitrateBps = 1000000;
3266
3267 MockBitrateObserver bitrate_observer;
mflodmancc3d4422017-08-03 08:27:51 -07003268 video_stream_encoder_->SetBitrateObserver(&bitrate_observer);
sprang4847ae62017-06-27 07:06:52 -07003269
3270 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3271 // Initial bitrate update.
mflodmancc3d4422017-08-03 08:27:51 -07003272 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3273 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003274
3275 // Insert a first video frame, causes another bitrate update.
3276 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3277 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3278 video_source_.IncomingCapturedFrame(
3279 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3280 WaitForEncodedFrame(timestamp_ms);
3281
3282 // Next, simulate video suspension due to pacer queue overrun.
mflodmancc3d4422017-08-03 08:27:51 -07003283 video_stream_encoder_->OnBitrateUpdated(0, 0, 1);
sprang4847ae62017-06-27 07:06:52 -07003284
3285 // Skip ahead until a new periodic parameter update should have occured.
3286 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3287 fake_clock_.AdvanceTimeMicros(
3288 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3289 rtc::kNumMicrosecsPerMillisec);
3290
3291 // Bitrate observer should not be called.
3292 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3293 video_source_.IncomingCapturedFrame(
3294 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3295 ExpectDroppedFrame();
3296
mflodmancc3d4422017-08-03 08:27:51 -07003297 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003298}
ilnik6b826ef2017-06-16 06:53:48 -07003299
perkj26091b12016-09-01 01:17:40 -07003300} // namespace webrtc