blob: 1bba52e2e88c444a4c8218027e570f00f2d44e78 [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_;
Niels Möller04dd1762018-03-23 16:05:22 +0100287 video_send_config_.rtp.payload_name = "FAKE";
288 video_send_config_.rtp.payload_type = 125;
perkj26091b12016-09-01 01:17:40 -0700289
Per512ecb32016-09-23 15:52:06 +0200290 VideoEncoderConfig video_encoder_config;
Niels Möller04dd1762018-03-23 16:05:22 +0100291 test::FillEncoderConfiguration(kVideoCodecVP8, 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) {
Niels Möller04dd1762018-03-23 16:05:22 +0100328 video_send_config_.rtp.payload_name = payload_name;
asapersson5f7226f2016-11-25 04:37:00 -0800329
330 VideoEncoderConfig video_encoder_config;
Niels Möller04dd1762018-03-23 16:05:22 +0100331 video_encoder_config.codec_type = PayloadStringToCodecType(payload_name);
asapersson5f7226f2016-11-25 04:37:00 -0800332 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800333 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800334 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700335 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
336 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700337 video_encoder_config.content_type =
338 screenshare ? VideoEncoderConfig::ContentType::kScreen
339 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700340 if (payload_name == "VP9") {
341 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
342 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
343 video_encoder_config.encoder_specific_settings =
344 new rtc::RefCountedObject<
345 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
346 }
asapersson5f7226f2016-11-25 04:37:00 -0800347 ConfigureEncoder(std::move(video_encoder_config), nack_enabled);
perkj26091b12016-09-01 01:17:40 -0700348 }
349
sprang57c2fff2017-01-16 06:24:02 -0800350 VideoFrame CreateFrame(int64_t ntp_time_ms,
351 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200352 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
353 destruction_event, codec_width_, codec_height_),
354 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800355 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700356 return frame;
357 }
358
sprang57c2fff2017-01-16 06:24:02 -0800359 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700360 VideoFrame frame(
361 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
362 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800363 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700364 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700365 return frame;
366 }
367
asapersson02465b82017-04-10 01:12:52 -0700368 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700369 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700370 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
371 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700372 }
373
asapersson09f05612017-05-15 23:40:18 -0700374 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
375 const rtc::VideoSinkWants& wants2) {
376 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
377 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
378 }
379
380 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
381 const rtc::VideoSinkWants& wants2) {
382 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
383 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
384 EXPECT_GT(wants1.max_pixel_count, 0);
385 }
386
387 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
388 const rtc::VideoSinkWants& wants2) {
389 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
390 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
391 }
392
asaperssonf7e294d2017-06-13 23:25:22 -0700393 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
394 const rtc::VideoSinkWants& wants2) {
395 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
396 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
397 }
398
399 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
400 const rtc::VideoSinkWants& wants2) {
401 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
402 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
403 }
404
405 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
406 const rtc::VideoSinkWants& wants2) {
407 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
408 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
409 }
410
411 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
412 const rtc::VideoSinkWants& wants2) {
413 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
414 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
415 EXPECT_GT(wants1.max_pixel_count, 0);
416 }
417
418 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
419 const rtc::VideoSinkWants& wants2) {
420 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
421 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
422 }
423
asapersson09f05612017-05-15 23:40:18 -0700424 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
425 int pixel_count) {
426 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700427 EXPECT_LT(wants.max_pixel_count, pixel_count);
428 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700429 }
430
431 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
432 EXPECT_LT(wants.max_framerate_fps, fps);
433 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
434 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700435 }
436
asaperssonf7e294d2017-06-13 23:25:22 -0700437 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
438 int expected_fps) {
439 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
440 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
441 EXPECT_FALSE(wants.target_pixel_count);
442 }
443
Jonathan Yubc771b72017-12-08 17:04:29 -0800444 void VerifyBalancedModeFpsRange(const rtc::VideoSinkWants& wants,
445 int last_frame_pixels) {
446 // Balanced mode should always scale FPS to the desired range before
447 // attempting to scale resolution.
448 int fps_limit = wants.max_framerate_fps;
449 if (last_frame_pixels <= 320 * 240) {
450 EXPECT_TRUE(7 <= fps_limit && fps_limit <= 10);
451 } else if (last_frame_pixels <= 480 * 270) {
452 EXPECT_TRUE(10 <= fps_limit && fps_limit <= 15);
453 } else if (last_frame_pixels <= 640 * 480) {
454 EXPECT_LE(15, fps_limit);
455 } else {
456 EXPECT_EQ(std::numeric_limits<int>::max(), fps_limit);
457 }
458 }
459
sprang4847ae62017-06-27 07:06:52 -0700460 void WaitForEncodedFrame(int64_t expected_ntp_time) {
461 sink_.WaitForEncodedFrame(expected_ntp_time);
462 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
463 }
464
465 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
466 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
467 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
468 return ok;
469 }
470
471 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
472 sink_.WaitForEncodedFrame(expected_width, expected_height);
473 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
474 }
475
476 void ExpectDroppedFrame() {
477 sink_.ExpectDroppedFrame();
478 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
479 }
480
481 bool WaitForFrame(int64_t timeout_ms) {
482 bool ok = sink_.WaitForFrame(timeout_ms);
483 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
484 return ok;
485 }
486
perkj26091b12016-09-01 01:17:40 -0700487 class TestEncoder : public test::FakeEncoder {
488 public:
489 TestEncoder()
490 : FakeEncoder(Clock::GetRealTimeClock()),
491 continue_encode_event_(false, false) {}
492
asaperssonfab67072017-04-04 05:51:49 -0700493 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800494 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700495 return config_;
496 }
497
498 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800499 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700500 block_next_encode_ = true;
501 }
502
kthelgason876222f2016-11-29 01:44:11 -0800503 VideoEncoder::ScalingSettings GetScalingSettings() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800504 rtc::CritScope lock(&local_crit_sect_);
kthelgasonad9010c2017-02-14 00:46:51 -0800505 if (quality_scaling_)
Niels Möller225c7872018-02-22 15:03:53 +0100506 return VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
507 return VideoEncoder::ScalingSettings::kOff;
kthelgason876222f2016-11-29 01:44:11 -0800508 }
509
perkjfa10b552016-10-02 23:45:26 -0700510 void ContinueEncode() { continue_encode_event_.Set(); }
511
512 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
513 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800514 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700515 EXPECT_EQ(timestamp_, timestamp);
516 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
517 }
518
kthelgason2fc52542017-03-03 00:24:41 -0800519 void SetQualityScaling(bool b) {
520 rtc::CritScope lock(&local_crit_sect_);
521 quality_scaling_ = b;
522 }
kthelgasonad9010c2017-02-14 00:46:51 -0800523
sprangfe627f32017-03-29 08:24:59 -0700524 void ForceInitEncodeFailure(bool force_failure) {
525 rtc::CritScope lock(&local_crit_sect_);
526 force_init_encode_failed_ = force_failure;
527 }
528
perkjfa10b552016-10-02 23:45:26 -0700529 private:
perkj26091b12016-09-01 01:17:40 -0700530 int32_t Encode(const VideoFrame& input_image,
531 const CodecSpecificInfo* codec_specific_info,
532 const std::vector<FrameType>* frame_types) override {
533 bool block_encode;
534 {
brandtre78d2662017-01-16 05:57:16 -0800535 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700536 EXPECT_GT(input_image.timestamp(), timestamp_);
537 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
538 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
539
540 timestamp_ = input_image.timestamp();
541 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700542 last_input_width_ = input_image.width();
543 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700544 block_encode = block_next_encode_;
545 block_next_encode_ = false;
546 }
547 int32_t result =
548 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
549 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700550 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700551 return result;
552 }
553
sprangfe627f32017-03-29 08:24:59 -0700554 int32_t InitEncode(const VideoCodec* config,
555 int32_t number_of_cores,
556 size_t max_payload_size) override {
557 int res =
558 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
559 rtc::CritScope lock(&local_crit_sect_);
Erik Språng82fad3d2018-03-21 09:57:23 +0100560 if (config->codecType == kVideoCodecVP8) {
sprangfe627f32017-03-29 08:24:59 -0700561 // Simulate setting up temporal layers, in order to validate the life
562 // cycle of these objects.
563 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
sprangfe627f32017-03-29 08:24:59 -0700564 for (int i = 0; i < num_streams; ++i) {
565 allocated_temporal_layers_.emplace_back(
Niels Möller150dcb02018-03-27 14:16:55 +0200566 TemporalLayers::CreateTemporalLayers(*config, i));
sprangfe627f32017-03-29 08:24:59 -0700567 }
568 }
569 if (force_init_encode_failed_)
570 return -1;
571 return res;
572 }
573
brandtre78d2662017-01-16 05:57:16 -0800574 rtc::CriticalSection local_crit_sect_;
danilchapa37de392017-09-09 04:17:22 -0700575 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700576 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700577 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
578 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
579 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
580 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
581 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
sprangfe627f32017-03-29 08:24:59 -0700582 std::vector<std::unique_ptr<TemporalLayers>> allocated_temporal_layers_
danilchapa37de392017-09-09 04:17:22 -0700583 RTC_GUARDED_BY(local_crit_sect_);
584 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700585 };
586
mflodmancc3d4422017-08-03 08:27:51 -0700587 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700588 public:
589 explicit TestSink(TestEncoder* test_encoder)
590 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
591
perkj26091b12016-09-01 01:17:40 -0700592 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700593 EXPECT_TRUE(
594 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
595 }
596
597 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
598 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700599 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700600 if (!encoded_frame_event_.Wait(timeout_ms))
601 return false;
perkj26091b12016-09-01 01:17:40 -0700602 {
603 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800604 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700605 }
606 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700607 return true;
perkj26091b12016-09-01 01:17:40 -0700608 }
609
sprangb1ca0732017-02-01 08:38:12 -0800610 void WaitForEncodedFrame(uint32_t expected_width,
611 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700612 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100613 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700614 }
615
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100616 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700617 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800618 uint32_t width = 0;
619 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800620 {
621 rtc::CritScope lock(&crit_);
622 width = last_width_;
623 height = last_height_;
624 }
625 EXPECT_EQ(expected_height, height);
626 EXPECT_EQ(expected_width, width);
627 }
628
kthelgason2fc52542017-03-03 00:24:41 -0800629 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800630
sprangc5d62e22017-04-02 23:53:04 -0700631 bool WaitForFrame(int64_t timeout_ms) {
632 return encoded_frame_event_.Wait(timeout_ms);
633 }
634
perkj26091b12016-09-01 01:17:40 -0700635 void SetExpectNoFrames() {
636 rtc::CritScope lock(&crit_);
637 expect_frames_ = false;
638 }
639
asaperssonfab67072017-04-04 05:51:49 -0700640 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200641 rtc::CritScope lock(&crit_);
642 return number_of_reconfigurations_;
643 }
644
asaperssonfab67072017-04-04 05:51:49 -0700645 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200646 rtc::CritScope lock(&crit_);
647 return min_transmit_bitrate_bps_;
648 }
649
perkj26091b12016-09-01 01:17:40 -0700650 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700651 Result OnEncodedImage(
652 const EncodedImage& encoded_image,
653 const CodecSpecificInfo* codec_specific_info,
654 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200655 rtc::CritScope lock(&crit_);
656 EXPECT_TRUE(expect_frames_);
sprangb1ca0732017-02-01 08:38:12 -0800657 last_timestamp_ = encoded_image._timeStamp;
658 last_width_ = encoded_image._encodedWidth;
659 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200660 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800661 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200662 }
663
664 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
665 int min_transmit_bitrate_bps) override {
666 rtc::CriticalSection crit_;
667 ++number_of_reconfigurations_;
668 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
669 }
670
perkj26091b12016-09-01 01:17:40 -0700671 rtc::CriticalSection crit_;
672 TestEncoder* test_encoder_;
673 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800674 uint32_t last_timestamp_ = 0;
675 uint32_t last_height_ = 0;
676 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700677 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200678 int number_of_reconfigurations_ = 0;
679 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700680 };
681
682 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100683 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200684 int codec_width_;
685 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700686 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700687 TestEncoder fake_encoder_;
sprangc5d62e22017-04-02 23:53:04 -0700688 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700689 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800690 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700691 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700692 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700693};
694
mflodmancc3d4422017-08-03 08:27:51 -0700695TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
696 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700697 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700698 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700699 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700700 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700701 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700702}
703
mflodmancc3d4422017-08-03 08:27:51 -0700704TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700705 // Dropped since no target bitrate has been set.
706 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700707 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
708 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700709
mflodmancc3d4422017-08-03 08:27:51 -0700710 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700711
perkja49cbd32016-09-16 07:53:41 -0700712 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700713 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700714 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700715}
716
mflodmancc3d4422017-08-03 08:27:51 -0700717TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
718 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700719 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700720 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700721
mflodmancc3d4422017-08-03 08:27:51 -0700722 video_stream_encoder_->OnBitrateUpdated(0, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700723 // Dropped since bitrate is zero.
perkja49cbd32016-09-16 07:53:41 -0700724 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkj26091b12016-09-01 01:17:40 -0700725
mflodmancc3d4422017-08-03 08:27:51 -0700726 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700727 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700728 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700729 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700730}
731
mflodmancc3d4422017-08-03 08:27:51 -0700732TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
733 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700734 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700735 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700736
737 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700738 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700739
perkja49cbd32016-09-16 07:53:41 -0700740 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700741 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700742 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700743}
744
mflodmancc3d4422017-08-03 08:27:51 -0700745TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
746 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700747
perkja49cbd32016-09-16 07:53:41 -0700748 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700749 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700750
mflodmancc3d4422017-08-03 08:27:51 -0700751 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700752 sink_.SetExpectNoFrames();
753 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700754 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
755 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700756}
757
mflodmancc3d4422017-08-03 08:27:51 -0700758TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
759 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700760
761 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700762 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700763 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700764 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
765 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700766 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
767 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700768 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700769 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700770
mflodmancc3d4422017-08-03 08:27:51 -0700771 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700772}
773
mflodmancc3d4422017-08-03 08:27:51 -0700774TEST_F(VideoStreamEncoderTest,
775 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
776 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100777 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200778
779 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200780 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700781 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100782 // The encoder will have been configured once when the first frame is
783 // received.
784 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200785
786 VideoEncoderConfig video_encoder_config;
Niels Möller04dd1762018-03-23 16:05:22 +0100787 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200788 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -0700789 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
790 kMaxPayloadLength,
791 true /* nack_enabled */);
Per512ecb32016-09-23 15:52:06 +0200792
793 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200794 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700795 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100796 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700797 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700798
mflodmancc3d4422017-08-03 08:27:51 -0700799 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -0700800}
801
mflodmancc3d4422017-08-03 08:27:51 -0700802TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
803 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkjfa10b552016-10-02 23:45:26 -0700804
805 // Capture a frame and wait for it to synchronize with the encoder thread.
806 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700807 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100808 // The encoder will have been configured once.
809 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700810 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
811 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
812
813 codec_width_ *= 2;
814 codec_height_ *= 2;
815 // Capture a frame with a higher resolution and wait for it to synchronize
816 // with the encoder thread.
817 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700818 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700819 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
820 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100821 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700822
mflodmancc3d4422017-08-03 08:27:51 -0700823 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -0700824}
825
mflodmancc3d4422017-08-03 08:27:51 -0700826TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOffFor1S1TLWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800827 const bool kNackEnabled = true;
828 const size_t kNumStreams = 1;
829 const size_t kNumTl = 1;
emircanbbcc3562017-08-18 00:28:40 -0700830 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700831 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800832
833 // Capture a frame and wait for it to synchronize with the encoder thread.
834 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700835 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800836 // The encoder have been configured once when the first frame is received.
837 EXPECT_EQ(1, sink_.number_of_reconfigurations());
838 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
839 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
840 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
841 // Resilience is off for no temporal layers with nack on.
842 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700843 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800844}
845
mflodmancc3d4422017-08-03 08:27:51 -0700846TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOffFor2S1TlWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800847 const bool kNackEnabled = true;
848 const size_t kNumStreams = 2;
849 const size_t kNumTl = 1;
emircanbbcc3562017-08-18 00:28:40 -0700850 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700851 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800852
853 // Capture a frame and wait for it to synchronize with the encoder thread.
854 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700855 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800856 // The encoder have been configured once when the first frame is received.
857 EXPECT_EQ(1, sink_.number_of_reconfigurations());
858 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
859 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
860 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
861 // Resilience is off for no temporal layers and >1 streams with nack on.
862 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700863 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800864}
865
mflodmancc3d4422017-08-03 08:27:51 -0700866TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOnFor1S1TLWithNackDisabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800867 const bool kNackEnabled = false;
868 const size_t kNumStreams = 1;
869 const size_t kNumTl = 1;
emircanbbcc3562017-08-18 00:28:40 -0700870 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700871 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800872
873 // Capture a frame and wait for it to synchronize with the encoder thread.
874 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700875 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800876 // The encoder have been configured once when the first frame is received.
877 EXPECT_EQ(1, sink_.number_of_reconfigurations());
878 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
879 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
880 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
881 // Resilience is on for no temporal layers with nack off.
882 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700883 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800884}
885
mflodmancc3d4422017-08-03 08:27:51 -0700886TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOnFor1S2TlWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800887 const bool kNackEnabled = true;
888 const size_t kNumStreams = 1;
889 const size_t kNumTl = 2;
emircanbbcc3562017-08-18 00:28:40 -0700890 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700891 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800892
893 // Capture a frame and wait for it to synchronize with the encoder thread.
894 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700895 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800896 // The encoder have been configured once when the first frame is received.
897 EXPECT_EQ(1, sink_.number_of_reconfigurations());
898 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
899 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
900 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
901 // Resilience is on for temporal layers.
902 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700903 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800904}
905
emircanbbcc3562017-08-18 00:28:40 -0700906TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOffFor1SL1TLWithNackEnabled) {
907 const bool kNackEnabled = true;
908 const size_t kNumStreams = 1;
909 const size_t kNumTl = 1;
910 const unsigned char kNumSl = 1;
911 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
912 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
913
914 // Capture a frame and wait for it to synchronize with the encoder thread.
915 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
916 sink_.WaitForEncodedFrame(1);
917 // The encoder have been configured once when the first frame is received.
918 EXPECT_EQ(1, sink_.number_of_reconfigurations());
919 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
920 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
921 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
922 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
923 // Resilience is off for no spatial and temporal layers with nack on.
924 EXPECT_FALSE(fake_encoder_.codec_config().VP9()->resilienceOn);
925 video_stream_encoder_->Stop();
926}
927
928TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOnFor1SL1TLWithNackDisabled) {
929 const bool kNackEnabled = false;
930 const size_t kNumStreams = 1;
931 const size_t kNumTl = 1;
932 const unsigned char kNumSl = 1;
933 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
934 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
935
936 // Capture a frame and wait for it to synchronize with the encoder thread.
937 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
938 sink_.WaitForEncodedFrame(1);
939 // The encoder have been configured once when the first frame is received.
940 EXPECT_EQ(1, sink_.number_of_reconfigurations());
941 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
942 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
943 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
944 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
945 // Resilience is on if nack is off.
946 EXPECT_TRUE(fake_encoder_.codec_config().VP9()->resilienceOn);
947 video_stream_encoder_->Stop();
948}
949
950TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOnFor2SL1TLWithNackEnabled) {
951 const bool kNackEnabled = true;
952 const size_t kNumStreams = 1;
953 const size_t kNumTl = 1;
954 const unsigned char kNumSl = 2;
955 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
956 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
957
958 // Capture a frame and wait for it to synchronize with the encoder thread.
959 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
960 sink_.WaitForEncodedFrame(1);
961 // The encoder have been configured once when the first frame is received.
962 EXPECT_EQ(1, sink_.number_of_reconfigurations());
963 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
964 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
965 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
966 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
967 // Resilience is on for spatial layers.
968 EXPECT_TRUE(fake_encoder_.codec_config().VP9()->resilienceOn);
969 video_stream_encoder_->Stop();
970}
971
972TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOnFor1SL2TLWithNackEnabled) {
973 const bool kNackEnabled = true;
974 const size_t kNumStreams = 1;
975 const size_t kNumTl = 2;
976 const unsigned char kNumSl = 1;
977 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
978 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
979
980 // Capture a frame and wait for it to synchronize with the encoder thread.
981 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
982 sink_.WaitForEncodedFrame(1);
983 // The encoder have been configured once when the first frame is received.
984 EXPECT_EQ(1, sink_.number_of_reconfigurations());
985 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
986 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
987 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
988 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
989 // Resilience is on for temporal layers.
990 EXPECT_TRUE(fake_encoder_.codec_config().VP9()->resilienceOn);
991 video_stream_encoder_->Stop();
992}
993
mflodmancc3d4422017-08-03 08:27:51 -0700994TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -0700995 EXPECT_TRUE(video_source_.has_sinks());
996 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700997 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -0700998 &new_video_source,
999 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001000 EXPECT_FALSE(video_source_.has_sinks());
1001 EXPECT_TRUE(new_video_source.has_sinks());
1002
mflodmancc3d4422017-08-03 08:27:51 -07001003 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001004}
1005
mflodmancc3d4422017-08-03 08:27:51 -07001006TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -07001007 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -07001008 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -07001009 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -07001010 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001011}
1012
Jonathan Yubc771b72017-12-08 17:04:29 -08001013TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
1014 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -07001015 const int kWidth = 1280;
1016 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -08001017
1018 // We rely on the automatic resolution adaptation, but we handle framerate
1019 // adaptation manually by mocking the stats proxy.
1020 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -07001021
1022 // Enable kBalanced preference, no initial limitation.
Jonathan Yubc771b72017-12-08 17:04:29 -08001023 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -07001024 video_stream_encoder_->SetSource(
Jonathan Yubc771b72017-12-08 17:04:29 -08001025 &video_source_,
mflodmancc3d4422017-08-03 08:27:51 -07001026 VideoSendStream::DegradationPreference::kBalanced);
Jonathan Yubc771b72017-12-08 17:04:29 -08001027 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001028 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001029 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -07001030 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1031
Jonathan Yubc771b72017-12-08 17:04:29 -08001032 // Adapt down as far as possible.
1033 rtc::VideoSinkWants last_wants;
1034 int64_t t = 1;
1035 int loop_count = 0;
1036 do {
1037 ++loop_count;
1038 last_wants = video_source_.sink_wants();
1039
1040 // Simulate the framerate we've been asked to adapt to.
1041 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
1042 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
1043 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1044 mock_stats.input_frame_rate = fps;
1045 stats_proxy_->SetMockStats(mock_stats);
1046
1047 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1048 sink_.WaitForEncodedFrame(t);
1049 t += frame_interval_ms;
1050
mflodmancc3d4422017-08-03 08:27:51 -07001051 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08001052 VerifyBalancedModeFpsRange(
1053 video_source_.sink_wants(),
1054 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1055 } while (video_source_.sink_wants().max_pixel_count <
1056 last_wants.max_pixel_count ||
1057 video_source_.sink_wants().max_framerate_fps <
1058 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001059
Jonathan Yubc771b72017-12-08 17:04:29 -08001060 // Verify that we've adapted all the way down.
1061 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001062 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001063 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
1064 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -07001065 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -08001066 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
1067 *video_source_.last_sent_height());
1068 EXPECT_EQ(kMinBalancedFramerateFps,
1069 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001070
Jonathan Yubc771b72017-12-08 17:04:29 -08001071 // Adapt back up the same number of times we adapted down.
1072 for (int i = 0; i < loop_count - 1; ++i) {
1073 last_wants = video_source_.sink_wants();
1074
1075 // Simulate the framerate we've been asked to adapt to.
1076 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
1077 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
1078 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1079 mock_stats.input_frame_rate = fps;
1080 stats_proxy_->SetMockStats(mock_stats);
1081
1082 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1083 sink_.WaitForEncodedFrame(t);
1084 t += frame_interval_ms;
1085
mflodmancc3d4422017-08-03 08:27:51 -07001086 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -08001087 VerifyBalancedModeFpsRange(
1088 video_source_.sink_wants(),
1089 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1090 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
1091 last_wants.max_pixel_count ||
1092 video_source_.sink_wants().max_framerate_fps >
1093 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001094 }
1095
Jonathan Yubc771b72017-12-08 17:04:29 -08001096 VerifyNoLimitation(video_source_.sink_wants());
1097 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001098 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001099 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1100 EXPECT_EQ((loop_count - 1) * 2,
1101 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -07001102
mflodmancc3d4422017-08-03 08:27:51 -07001103 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001104}
mflodmancc3d4422017-08-03 08:27:51 -07001105TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
1106 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001107 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001108
sprangc5d62e22017-04-02 23:53:04 -07001109 const int kFrameWidth = 1280;
1110 const int kFrameHeight = 720;
1111 const int kFrameIntervalMs = 1000 / 30;
1112
1113 int frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -07001114
kthelgason5e13d412016-12-01 03:59:51 -08001115 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001116 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001117 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001118 frame_timestamp += kFrameIntervalMs;
1119
perkj803d97f2016-11-01 11:45:46 -07001120 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001121 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001122 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001123 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001124 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001125 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -07001126
asapersson0944a802017-04-07 00:57:58 -07001127 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -07001128 // wanted resolution.
1129 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
1130 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
1131 kFrameWidth * kFrameHeight);
1132 EXPECT_EQ(std::numeric_limits<int>::max(),
1133 video_source_.sink_wants().max_framerate_fps);
1134
1135 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -07001136 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001137 video_stream_encoder_->SetSource(
perkj803d97f2016-11-01 11:45:46 -07001138 &new_video_source,
1139 VideoSendStream::DegradationPreference::kMaintainResolution);
1140
sprangc5d62e22017-04-02 23:53:04 -07001141 // Initially no degradation registered.
asapersson02465b82017-04-10 01:12:52 -07001142 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001143
sprangc5d62e22017-04-02 23:53:04 -07001144 // Force an input frame rate to be available, or the adaptation call won't
1145 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -07001146 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -07001147 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -07001148 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -07001149 stats_proxy_->SetMockStats(stats);
1150
mflodmancc3d4422017-08-03 08:27:51 -07001151 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001152 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001153 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001154 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001155 frame_timestamp += kFrameIntervalMs;
1156
1157 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001158 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001159 EXPECT_EQ(std::numeric_limits<int>::max(),
1160 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001161 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001162
asapersson02465b82017-04-10 01:12:52 -07001163 // Turn off degradation completely.
mflodmancc3d4422017-08-03 08:27:51 -07001164 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001165 &new_video_source,
1166 VideoSendStream::DegradationPreference::kDegradationDisabled);
asapersson02465b82017-04-10 01:12:52 -07001167 VerifyNoLimitation(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001168
mflodmancc3d4422017-08-03 08:27:51 -07001169 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001170 new_video_source.IncomingCapturedFrame(
1171 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001172 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001173 frame_timestamp += kFrameIntervalMs;
1174
1175 // Still no degradation.
asapersson02465b82017-04-10 01:12:52 -07001176 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001177
1178 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001179 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001180 &new_video_source,
1181 VideoSendStream::DegradationPreference::kMaintainFramerate);
1182 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1183 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001184 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001185 EXPECT_EQ(std::numeric_limits<int>::max(),
1186 new_video_source.sink_wants().max_framerate_fps);
1187
1188 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001189 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001190 &new_video_source,
1191 VideoSendStream::DegradationPreference::kMaintainResolution);
1192 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1193 EXPECT_EQ(std::numeric_limits<int>::max(),
1194 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001195 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001196
mflodmancc3d4422017-08-03 08:27:51 -07001197 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001198}
1199
mflodmancc3d4422017-08-03 08:27:51 -07001200TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
1201 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001202
asaperssonfab67072017-04-04 05:51:49 -07001203 const int kWidth = 1280;
1204 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001205 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001206 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001207 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1208 EXPECT_FALSE(stats.bw_limited_resolution);
1209 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1210
1211 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001212 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001213 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001214 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001215
1216 stats = stats_proxy_->GetStats();
1217 EXPECT_TRUE(stats.bw_limited_resolution);
1218 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1219
1220 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001221 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001222 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001223 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001224
1225 stats = stats_proxy_->GetStats();
1226 EXPECT_FALSE(stats.bw_limited_resolution);
1227 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1228 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1229
mflodmancc3d4422017-08-03 08:27:51 -07001230 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001231}
1232
mflodmancc3d4422017-08-03 08:27:51 -07001233TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
1234 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001235
1236 const int kWidth = 1280;
1237 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001238 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001239 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001240 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1241 EXPECT_FALSE(stats.cpu_limited_resolution);
1242 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1243
1244 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001245 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001246 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001247 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001248
1249 stats = stats_proxy_->GetStats();
1250 EXPECT_TRUE(stats.cpu_limited_resolution);
1251 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1252
1253 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001254 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001255 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001256 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001257
1258 stats = stats_proxy_->GetStats();
1259 EXPECT_FALSE(stats.cpu_limited_resolution);
1260 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001261 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001262
mflodmancc3d4422017-08-03 08:27:51 -07001263 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001264}
1265
mflodmancc3d4422017-08-03 08:27:51 -07001266TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
1267 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001268
asaperssonfab67072017-04-04 05:51:49 -07001269 const int kWidth = 1280;
1270 const int kHeight = 720;
1271 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001272 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001273 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001274 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001275 EXPECT_FALSE(stats.cpu_limited_resolution);
1276 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1277
asaperssonfab67072017-04-04 05:51:49 -07001278 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001279 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001280 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001281 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001282 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001283 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001284 EXPECT_TRUE(stats.cpu_limited_resolution);
1285 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1286
1287 // Set new source with adaptation still enabled.
1288 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001289 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001290 &new_video_source,
1291 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001292
asaperssonfab67072017-04-04 05:51:49 -07001293 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001294 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001295 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001296 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001297 EXPECT_TRUE(stats.cpu_limited_resolution);
1298 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1299
1300 // Set adaptation disabled.
mflodmancc3d4422017-08-03 08:27:51 -07001301 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001302 &new_video_source,
sprangc5d62e22017-04-02 23:53:04 -07001303 VideoSendStream::DegradationPreference::kDegradationDisabled);
kthelgason876222f2016-11-29 01:44:11 -08001304
asaperssonfab67072017-04-04 05:51:49 -07001305 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001306 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001307 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001308 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001309 EXPECT_FALSE(stats.cpu_limited_resolution);
1310 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1311
1312 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001313 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001314 &new_video_source,
1315 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001316
asaperssonfab67072017-04-04 05:51:49 -07001317 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001318 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001319 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001320 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001321 EXPECT_TRUE(stats.cpu_limited_resolution);
1322 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1323
asaperssonfab67072017-04-04 05:51:49 -07001324 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001325 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001326 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001327 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001328 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001329 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001330 EXPECT_FALSE(stats.cpu_limited_resolution);
1331 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001332 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001333
mflodmancc3d4422017-08-03 08:27:51 -07001334 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001335}
1336
mflodmancc3d4422017-08-03 08:27:51 -07001337TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
1338 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001339
asaperssonfab67072017-04-04 05:51:49 -07001340 const int kWidth = 1280;
1341 const int kHeight = 720;
1342 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001343 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001344 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001345 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001346 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001347 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001348
1349 // Set new source with adaptation still enabled.
1350 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001351 video_stream_encoder_->SetSource(
1352 &new_video_source,
1353 VideoSendStream::DegradationPreference::kBalanced);
kthelgason876222f2016-11-29 01:44:11 -08001354
asaperssonfab67072017-04-04 05:51:49 -07001355 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001356 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001357 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001358 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001359 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001360 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001361
asaperssonfab67072017-04-04 05:51:49 -07001362 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001363 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001364 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001365 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001366 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001367 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001368 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001369 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001370
asaperssonfab67072017-04-04 05:51:49 -07001371 // Set new source with adaptation still enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001372 video_stream_encoder_->SetSource(
1373 &new_video_source,
1374 VideoSendStream::DegradationPreference::kBalanced);
kthelgason876222f2016-11-29 01:44:11 -08001375
asaperssonfab67072017-04-04 05:51:49 -07001376 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001377 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001378 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001379 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001380 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001381 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001382
asapersson02465b82017-04-10 01:12:52 -07001383 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001384 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001385 &new_video_source,
1386 VideoSendStream::DegradationPreference::kMaintainResolution);
1387
asaperssonfab67072017-04-04 05:51:49 -07001388 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001389 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001390 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001391 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001392 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001393 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1394 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001395
mflodmancc3d4422017-08-03 08:27:51 -07001396 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001397}
1398
mflodmancc3d4422017-08-03 08:27:51 -07001399TEST_F(VideoStreamEncoderTest,
1400 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1401 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001402
1403 const int kWidth = 1280;
1404 const int kHeight = 720;
1405 video_source_.set_adaptation_enabled(true);
1406 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001407 WaitForEncodedFrame(1);
asapersson36e9eb42017-03-31 05:29:12 -07001408 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1409 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1410 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1411
1412 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001413 video_stream_encoder_->TriggerQualityLow();
asapersson36e9eb42017-03-31 05:29:12 -07001414 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001415 WaitForEncodedFrame(2);
asapersson36e9eb42017-03-31 05:29:12 -07001416 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1417 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1418 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1419
1420 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001421 video_stream_encoder_->TriggerCpuOveruse();
asapersson36e9eb42017-03-31 05:29:12 -07001422 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001423 WaitForEncodedFrame(3);
asapersson36e9eb42017-03-31 05:29:12 -07001424 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1425 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1426 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1427
1428 // Set source with adaptation still enabled but quality scaler is off.
1429 fake_encoder_.SetQualityScaling(false);
mflodmancc3d4422017-08-03 08:27:51 -07001430 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001431 &video_source_,
1432 VideoSendStream::DegradationPreference::kMaintainFramerate);
asapersson36e9eb42017-03-31 05:29:12 -07001433
1434 video_source_.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001435 WaitForEncodedFrame(4);
asapersson36e9eb42017-03-31 05:29:12 -07001436 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1437 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1438 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1439
mflodmancc3d4422017-08-03 08:27:51 -07001440 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001441}
1442
mflodmancc3d4422017-08-03 08:27:51 -07001443TEST_F(VideoStreamEncoderTest,
1444 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
1445 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001446
asapersson0944a802017-04-07 00:57:58 -07001447 const int kWidth = 1280;
1448 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001449 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001450
asaperssonfab67072017-04-04 05:51:49 -07001451 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001452 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001453 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001454 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001455 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001456 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1457
asapersson02465b82017-04-10 01:12:52 -07001458 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001459 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001460 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001461 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001462 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001463 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001464 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001465 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1466
1467 // Set new source with adaptation still enabled.
1468 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001469 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001470 &new_video_source,
1471 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001472
1473 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001474 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001475 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001476 stats = stats_proxy_->GetStats();
1477 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001478 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001479 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1480
sprangc5d62e22017-04-02 23:53:04 -07001481 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001482 video_stream_encoder_->SetSource(
perkj803d97f2016-11-01 11:45:46 -07001483 &new_video_source,
1484 VideoSendStream::DegradationPreference::kMaintainResolution);
1485 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001486 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001487 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001488 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001489 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001490 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001491 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001492 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1493
sprangc5d62e22017-04-02 23:53:04 -07001494 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001495 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001496 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1497 mock_stats.input_frame_rate = 30;
1498 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001499 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001500 stats_proxy_->ResetMockStats();
1501
1502 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001503 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001504 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001505
1506 // Framerate now adapted.
1507 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001508 EXPECT_FALSE(stats.cpu_limited_resolution);
1509 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001510 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1511
1512 // Disable CPU adaptation.
mflodmancc3d4422017-08-03 08:27:51 -07001513 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001514 &new_video_source,
1515 VideoSendStream::DegradationPreference::kDegradationDisabled);
1516 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001517 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001518 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001519
1520 stats = stats_proxy_->GetStats();
1521 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001522 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001523 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1524
1525 // Try to trigger overuse. Should not succeed.
1526 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001527 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001528 stats_proxy_->ResetMockStats();
1529
1530 stats = stats_proxy_->GetStats();
1531 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001532 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001533 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1534
1535 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001536 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001537 &video_source_,
1538 VideoSendStream::DegradationPreference::kMaintainFramerate);
asaperssonfab67072017-04-04 05:51:49 -07001539 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001540 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001541 stats = stats_proxy_->GetStats();
1542 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001543 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001544 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001545
1546 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001547 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001548 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001549 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001550 stats = stats_proxy_->GetStats();
1551 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001552 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001553 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1554
1555 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001556 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001557 &new_video_source,
1558 VideoSendStream::DegradationPreference::kMaintainResolution);
1559 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001560 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001561 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001562 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001563 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001564 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001565 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001566 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1567
1568 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001569 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001570 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001571 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001572 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001573 stats = stats_proxy_->GetStats();
1574 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001575 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001576 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001577 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001578
mflodmancc3d4422017-08-03 08:27:51 -07001579 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001580}
1581
mflodmancc3d4422017-08-03 08:27:51 -07001582TEST_F(VideoStreamEncoderTest, StatsTracksPreferredBitrate) {
1583 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Erik Språng08127a92016-11-16 16:41:30 +01001584
asaperssonfab67072017-04-04 05:51:49 -07001585 const int kWidth = 1280;
1586 const int kHeight = 720;
1587 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001588 WaitForEncodedFrame(1);
Erik Språng08127a92016-11-16 16:41:30 +01001589
1590 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1591 EXPECT_EQ(video_encoder_config_.max_bitrate_bps,
1592 stats.preferred_media_bitrate_bps);
1593
mflodmancc3d4422017-08-03 08:27:51 -07001594 video_stream_encoder_->Stop();
Erik Språng08127a92016-11-16 16:41:30 +01001595}
1596
mflodmancc3d4422017-08-03 08:27:51 -07001597TEST_F(VideoStreamEncoderTest,
1598 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001599 const int kWidth = 1280;
1600 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001601 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001602
asaperssonfab67072017-04-04 05:51:49 -07001603 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001604 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001605
asaperssonfab67072017-04-04 05:51:49 -07001606 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001607 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001608
asaperssonfab67072017-04-04 05:51:49 -07001609 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001610 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001611
asaperssonfab67072017-04-04 05:51:49 -07001612 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001613 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001614
kthelgason876222f2016-11-29 01:44:11 -08001615 // Expect a scale down.
1616 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001617 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001618
asapersson02465b82017-04-10 01:12:52 -07001619 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001620 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001621 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001622 &new_video_source,
1623 VideoSendStream::DegradationPreference::kMaintainResolution);
1624
asaperssonfab67072017-04-04 05:51:49 -07001625 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001626 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001627 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001628 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001629
asaperssonfab67072017-04-04 05:51:49 -07001630 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001631 EXPECT_EQ(std::numeric_limits<int>::max(),
1632 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001633
asaperssonfab67072017-04-04 05:51:49 -07001634 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001635 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001636 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001637 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001638
asapersson02465b82017-04-10 01:12:52 -07001639 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001640 EXPECT_EQ(std::numeric_limits<int>::max(),
1641 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001642
mflodmancc3d4422017-08-03 08:27:51 -07001643 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001644}
1645
mflodmancc3d4422017-08-03 08:27:51 -07001646TEST_F(VideoStreamEncoderTest,
1647 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001648 const int kWidth = 1280;
1649 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001650 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001651
1652 // Enable kMaintainFramerate preference, no initial limitation.
1653 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001654 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001655 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1656
1657 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001658 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001659 VerifyNoLimitation(source.sink_wants());
1660 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1661 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1662
1663 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001664 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001665 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001666 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1667 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1668 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1669
1670 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001671 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001672 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1673 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1674 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1675
mflodmancc3d4422017-08-03 08:27:51 -07001676 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001677}
1678
mflodmancc3d4422017-08-03 08:27:51 -07001679TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001680 const int kWidth = 1280;
1681 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001682 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001683
1684 // Enable kBalanced preference, no initial limitation.
1685 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001686 video_stream_encoder_->SetSource(
1687 &source,
1688 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001689 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1690 sink_.WaitForEncodedFrame(1);
1691 VerifyNoLimitation(source.sink_wants());
1692
1693 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001694 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001695 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1696 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1697 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1698 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1699
1700 // Trigger adapt down for same input resolution, expect no change.
1701 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1702 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001703 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001704 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1705 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1706 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1707
1708 // Trigger adapt down for larger input resolution, expect no change.
1709 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1710 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001711 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001712 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1713 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1714 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1715
mflodmancc3d4422017-08-03 08:27:51 -07001716 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001717}
1718
mflodmancc3d4422017-08-03 08:27:51 -07001719TEST_F(VideoStreamEncoderTest,
1720 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001721 const int kWidth = 1280;
1722 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001723 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001724
1725 // Enable kMaintainFramerate preference, no initial limitation.
1726 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001727 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001728 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1729
1730 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001731 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001732 VerifyNoLimitation(source.sink_wants());
1733 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1734 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1735
1736 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001737 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001738 VerifyNoLimitation(source.sink_wants());
1739 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1740 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1741
mflodmancc3d4422017-08-03 08:27:51 -07001742 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001743}
1744
mflodmancc3d4422017-08-03 08:27:51 -07001745TEST_F(VideoStreamEncoderTest,
1746 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001747 const int kWidth = 1280;
1748 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001749 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001750
1751 // Enable kMaintainResolution preference, no initial limitation.
1752 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001753 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001754 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
1755
1756 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001757 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001758 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001759 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001760 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1761
1762 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001763 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001764 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001765 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001766 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1767
mflodmancc3d4422017-08-03 08:27:51 -07001768 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001769}
1770
mflodmancc3d4422017-08-03 08:27:51 -07001771TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001772 const int kWidth = 1280;
1773 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001774 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001775
1776 // Enable kBalanced preference, no initial limitation.
1777 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001778 video_stream_encoder_->SetSource(
1779 &source,
1780 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001781
1782 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1783 sink_.WaitForEncodedFrame(kWidth, kHeight);
1784 VerifyNoLimitation(source.sink_wants());
1785 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1786 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1787 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1788
1789 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001790 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001791 VerifyNoLimitation(source.sink_wants());
1792 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1793 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1794 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1795
mflodmancc3d4422017-08-03 08:27:51 -07001796 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001797}
1798
mflodmancc3d4422017-08-03 08:27:51 -07001799TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001800 const int kWidth = 1280;
1801 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001802 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001803
1804 // Enable kDegradationDisabled preference, no initial limitation.
1805 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001806 video_stream_encoder_->SetSource(
asapersson09f05612017-05-15 23:40:18 -07001807 &source, VideoSendStream::DegradationPreference::kDegradationDisabled);
1808
1809 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1810 sink_.WaitForEncodedFrame(kWidth, kHeight);
1811 VerifyNoLimitation(source.sink_wants());
1812 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1813 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1814 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1815
1816 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001817 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001818 VerifyNoLimitation(source.sink_wants());
1819 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1820 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1821 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1822
mflodmancc3d4422017-08-03 08:27:51 -07001823 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001824}
1825
mflodmancc3d4422017-08-03 08:27:51 -07001826TEST_F(VideoStreamEncoderTest,
1827 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001828 const int kWidth = 1280;
1829 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001830 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001831
1832 // Enable kMaintainFramerate preference, no initial limitation.
1833 AdaptingFrameForwarder source;
1834 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001835 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001836 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1837
1838 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001839 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001840 VerifyNoLimitation(source.sink_wants());
1841 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1842 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1843
1844 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001845 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001846 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001847 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001848 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001849 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1850 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1851
1852 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001853 video_stream_encoder_->TriggerQualityHigh();
asapersson02465b82017-04-10 01:12:52 -07001854 VerifyNoLimitation(source.sink_wants());
1855 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1856 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1857 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1858
mflodmancc3d4422017-08-03 08:27:51 -07001859 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001860}
1861
mflodmancc3d4422017-08-03 08:27:51 -07001862TEST_F(VideoStreamEncoderTest,
1863 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001864 const int kWidth = 1280;
1865 const int kHeight = 720;
1866 const int kInputFps = 30;
mflodmancc3d4422017-08-03 08:27:51 -07001867 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001868
1869 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1870 stats.input_frame_rate = kInputFps;
1871 stats_proxy_->SetMockStats(stats);
1872
1873 // Expect no scaling to begin with (preference: kMaintainFramerate).
1874 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1875 sink_.WaitForEncodedFrame(1);
1876 VerifyNoLimitation(video_source_.sink_wants());
1877
1878 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001879 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001880 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1881 sink_.WaitForEncodedFrame(2);
1882 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1883
1884 // Enable kMaintainResolution preference.
1885 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001886 video_stream_encoder_->SetSource(
asapersson09f05612017-05-15 23:40:18 -07001887 &new_video_source,
1888 VideoSendStream::DegradationPreference::kMaintainResolution);
1889 VerifyNoLimitation(new_video_source.sink_wants());
1890
1891 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001892 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001893 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1894 sink_.WaitForEncodedFrame(3);
1895 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1896
1897 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001898 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001899 VerifyNoLimitation(new_video_source.sink_wants());
1900
mflodmancc3d4422017-08-03 08:27:51 -07001901 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001902}
1903
mflodmancc3d4422017-08-03 08:27:51 -07001904TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001905 const int kWidth = 1280;
1906 const int kHeight = 720;
1907 const size_t kNumFrames = 10;
1908
mflodmancc3d4422017-08-03 08:27:51 -07001909 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001910
asaperssond0de2952017-04-21 01:47:31 -07001911 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001912 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001913 video_source_.set_adaptation_enabled(true);
1914
1915 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1916 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1917
1918 int downscales = 0;
1919 for (size_t i = 1; i <= kNumFrames; i++) {
1920 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001921 WaitForEncodedFrame(i);
asaperssond0de2952017-04-21 01:47:31 -07001922
asaperssonfab67072017-04-04 05:51:49 -07001923 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001924 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001925 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001926 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001927
1928 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1929 ++downscales;
1930
1931 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1932 EXPECT_EQ(downscales,
1933 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1934 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001935 }
mflodmancc3d4422017-08-03 08:27:51 -07001936 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001937}
1938
mflodmancc3d4422017-08-03 08:27:51 -07001939TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001940 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1941 const int kWidth = 1280;
1942 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001943 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001944
1945 // Enable kMaintainFramerate preference, no initial limitation.
1946 AdaptingFrameForwarder source;
1947 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001948 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07001949 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1950
1951 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001952 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001953 VerifyNoLimitation(source.sink_wants());
1954 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1955 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1956
1957 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001958 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001959 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001960 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001961 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001962 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1963 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1964
1965 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001966 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07001967 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001968 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001969 VerifyNoLimitation(source.sink_wants());
1970 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1971 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1972
1973 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001974 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001975 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001976 WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07001977 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001978 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1979 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1980
1981 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001982 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson09f05612017-05-15 23:40:18 -07001983 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1984 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001985 VerifyNoLimitation(source.sink_wants());
1986 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1987 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1988
mflodmancc3d4422017-08-03 08:27:51 -07001989 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001990}
1991
mflodmancc3d4422017-08-03 08:27:51 -07001992TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07001993 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
1994 const int kWidth = 1280;
1995 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001996 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001997
1998 // Enable kBalanced preference, no initial limitation.
1999 AdaptingFrameForwarder source;
2000 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002001 video_stream_encoder_->SetSource(
2002 &source,
2003 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002004
2005 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2006 sink_.WaitForEncodedFrame(kWidth, kHeight);
2007 VerifyNoLimitation(source.sink_wants());
2008 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2009 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2010
2011 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002012 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002013 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
2014 sink_.WaitForEncodedFrame(2);
2015 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2016 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2017 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2018
2019 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002020 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002021 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
2022 sink_.WaitForEncodedFrame(kWidth, kHeight);
2023 VerifyNoLimitation(source.sink_wants());
2024 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2025 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2026
2027 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002028 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002029 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
2030 sink_.WaitForEncodedFrame(4);
2031 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2032 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2033 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2034
2035 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002036 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002037 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
2038 sink_.WaitForEncodedFrame(kWidth, kHeight);
2039 VerifyNoLimitation(source.sink_wants());
2040 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2041 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2042
mflodmancc3d4422017-08-03 08:27:51 -07002043 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002044}
2045
mflodmancc3d4422017-08-03 08:27:51 -07002046TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002047 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
2048 const int kWidth = 1280;
2049 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07002050 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002051
2052 // Enable kMaintainFramerate preference, no initial limitation.
2053 AdaptingFrameForwarder source;
2054 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002055 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07002056 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
2057
2058 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002059 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002060 VerifyNoLimitation(source.sink_wants());
2061 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2062 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2063 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2064 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2065
2066 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002067 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002068 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002069 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07002070 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002071 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2072 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2073 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2074 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2075
2076 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07002077 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002078 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002079 WaitForEncodedFrame(3);
asapersson09f05612017-05-15 23:40:18 -07002080 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002081 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2082 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2083 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2084 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2085
Jonathan Yubc771b72017-12-08 17:04:29 -08002086 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002087 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002088 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002089 WaitForEncodedFrame(4);
Jonathan Yubc771b72017-12-08 17:04:29 -08002090 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002091 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2092 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002093 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002094 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2095
Jonathan Yubc771b72017-12-08 17:04:29 -08002096 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07002097 video_stream_encoder_->TriggerQualityLow();
asaperssond0de2952017-04-21 01:47:31 -07002098 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002099 WaitForEncodedFrame(5);
asapersson09f05612017-05-15 23:40:18 -07002100 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002101 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07002102 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2103 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2104 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2105 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2106
Jonathan Yubc771b72017-12-08 17:04:29 -08002107 // Trigger quality adapt down, expect no change (min resolution reached).
2108 video_stream_encoder_->TriggerQualityLow();
2109 source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
2110 WaitForEncodedFrame(6);
2111 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
2112 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2113 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2114 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2115 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2116
2117 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002118 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07002119 source.IncomingCapturedFrame(CreateFrame(7, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002120 WaitForEncodedFrame(7);
asapersson09f05612017-05-15 23:40:18 -07002121 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002122 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2123 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2124 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2125 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2126
2127 // Trigger cpu adapt up, expect upscaled resolution (640x360).
2128 video_stream_encoder_->TriggerCpuNormalUsage();
2129 source.IncomingCapturedFrame(CreateFrame(8, kWidth, kHeight));
2130 WaitForEncodedFrame(8);
2131 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2132 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2133 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2134 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2135 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2136
2137 // Trigger cpu adapt up, expect upscaled resolution (960x540).
2138 video_stream_encoder_->TriggerCpuNormalUsage();
2139 source.IncomingCapturedFrame(CreateFrame(9, kWidth, kHeight));
2140 WaitForEncodedFrame(9);
2141 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002142 last_wants = source.sink_wants();
2143 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2144 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002145 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002146 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2147
2148 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002149 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -08002150 source.IncomingCapturedFrame(CreateFrame(10, kWidth, kHeight));
2151 WaitForEncodedFrame(10);
asapersson09f05612017-05-15 23:40:18 -07002152 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002153 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2154 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002155 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002156 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2157
2158 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002159 video_stream_encoder_->TriggerQualityHigh();
Jonathan Yubc771b72017-12-08 17:04:29 -08002160 source.IncomingCapturedFrame(CreateFrame(11, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002161 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002162 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002163 VerifyNoLimitation(source.sink_wants());
2164 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2165 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002166 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002167 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002168
mflodmancc3d4422017-08-03 08:27:51 -07002169 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002170}
2171
mflodmancc3d4422017-08-03 08:27:51 -07002172TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002173 const int kWidth = 640;
2174 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002175
mflodmancc3d4422017-08-03 08:27:51 -07002176 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002177
perkj803d97f2016-11-01 11:45:46 -07002178 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002179 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002180 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002181 }
2182
mflodmancc3d4422017-08-03 08:27:51 -07002183 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002184 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002185 video_source_.IncomingCapturedFrame(CreateFrame(
2186 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002187 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002188 }
2189
mflodmancc3d4422017-08-03 08:27:51 -07002190 video_stream_encoder_->Stop();
2191 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002192 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002193
perkj803d97f2016-11-01 11:45:46 -07002194 EXPECT_EQ(1,
2195 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2196 EXPECT_EQ(
2197 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2198}
2199
mflodmancc3d4422017-08-03 08:27:51 -07002200TEST_F(VideoStreamEncoderTest,
2201 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2202 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002203 const int kWidth = 640;
2204 const int kHeight = 360;
2205
mflodmancc3d4422017-08-03 08:27:51 -07002206 video_stream_encoder_->SetSource(
asaperssonf4e44af2017-04-19 02:01:06 -07002207 &video_source_,
2208 VideoSendStream::DegradationPreference::kDegradationDisabled);
2209
2210 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2211 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002212 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002213 }
2214
mflodmancc3d4422017-08-03 08:27:51 -07002215 video_stream_encoder_->Stop();
2216 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002217 stats_proxy_.reset();
2218
2219 EXPECT_EQ(0,
2220 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2221}
2222
mflodmancc3d4422017-08-03 08:27:51 -07002223TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002224 MockBitrateObserver bitrate_observer;
mflodmancc3d4422017-08-03 08:27:51 -07002225 video_stream_encoder_->SetBitrateObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002226
2227 const int kDefaultFps = 30;
2228 const BitrateAllocation expected_bitrate =
2229 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002230 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002231
2232 // First called on bitrate updated, then again on first frame.
2233 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2234 .Times(2);
mflodmancc3d4422017-08-03 08:27:51 -07002235 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002236
2237 const int64_t kStartTimeMs = 1;
2238 video_source_.IncomingCapturedFrame(
2239 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002240 WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002241
2242 // Not called on second frame.
2243 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2244 .Times(0);
2245 video_source_.IncomingCapturedFrame(
2246 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002247 WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002248
2249 // Called after a process interval.
2250 const int64_t kProcessIntervalMs =
2251 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang4847ae62017-06-27 07:06:52 -07002252 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec *
2253 (kProcessIntervalMs + (1000 / kDefaultFps)));
sprang57c2fff2017-01-16 06:24:02 -08002254 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2255 .Times(1);
2256 video_source_.IncomingCapturedFrame(CreateFrame(
2257 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002258 WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002259
mflodmancc3d4422017-08-03 08:27:51 -07002260 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002261}
2262
Niels Möller7dc26b72017-12-06 10:27:48 +01002263TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2264 const int kFrameWidth = 1280;
2265 const int kFrameHeight = 720;
2266 const int kFramerate = 24;
2267
2268 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2269 test::FrameForwarder source;
2270 video_stream_encoder_->SetSource(
2271 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2272
2273 // Insert a single frame, triggering initial configuration.
2274 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2275 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2276
2277 EXPECT_EQ(
2278 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2279 kDefaultFramerate);
2280
2281 // Trigger reconfigure encoder (without resetting the entire instance).
2282 VideoEncoderConfig video_encoder_config;
Niels Möller04dd1762018-03-23 16:05:22 +01002283 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002284 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2285 video_encoder_config.number_of_streams = 1;
2286 video_encoder_config.video_stream_factory =
2287 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2288 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2289 kMaxPayloadLength, false);
2290 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2291
2292 // Detector should be updated with fps limit from codec config.
2293 EXPECT_EQ(
2294 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2295 kFramerate);
2296
2297 // Trigger overuse, max framerate should be reduced.
2298 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2299 stats.input_frame_rate = kFramerate;
2300 stats_proxy_->SetMockStats(stats);
2301 video_stream_encoder_->TriggerCpuOveruse();
2302 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2303 int adapted_framerate =
2304 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2305 EXPECT_LT(adapted_framerate, kFramerate);
2306
2307 // Trigger underuse, max framerate should go back to codec configured fps.
2308 // Set extra low fps, to make sure it's actually reset, not just incremented.
2309 stats = stats_proxy_->GetStats();
2310 stats.input_frame_rate = adapted_framerate / 2;
2311 stats_proxy_->SetMockStats(stats);
2312 video_stream_encoder_->TriggerCpuNormalUsage();
2313 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2314 EXPECT_EQ(
2315 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2316 kFramerate);
2317
2318 video_stream_encoder_->Stop();
2319}
2320
2321TEST_F(VideoStreamEncoderTest,
2322 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2323 const int kFrameWidth = 1280;
2324 const int kFrameHeight = 720;
2325 const int kLowFramerate = 15;
2326 const int kHighFramerate = 25;
2327
2328 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2329 test::FrameForwarder source;
2330 video_stream_encoder_->SetSource(
2331 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2332
2333 // Trigger initial configuration.
2334 VideoEncoderConfig video_encoder_config;
Niels Möller04dd1762018-03-23 16:05:22 +01002335 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002336 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2337 video_encoder_config.number_of_streams = 1;
2338 video_encoder_config.video_stream_factory =
2339 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2340 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2341 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2342 kMaxPayloadLength, false);
2343 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2344
2345 EXPECT_EQ(
2346 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2347 kLowFramerate);
2348
2349 // Trigger overuse, max framerate should be reduced.
2350 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2351 stats.input_frame_rate = kLowFramerate;
2352 stats_proxy_->SetMockStats(stats);
2353 video_stream_encoder_->TriggerCpuOveruse();
2354 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2355 int adapted_framerate =
2356 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2357 EXPECT_LT(adapted_framerate, kLowFramerate);
2358
2359 // Reconfigure the encoder with a new (higher max framerate), max fps should
2360 // still respect the adaptation.
2361 video_encoder_config.video_stream_factory =
2362 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2363 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2364 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2365 kMaxPayloadLength, false);
2366 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2367
2368 EXPECT_EQ(
2369 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2370 adapted_framerate);
2371
2372 // Trigger underuse, max framerate should go back to codec configured fps.
2373 stats = stats_proxy_->GetStats();
2374 stats.input_frame_rate = adapted_framerate;
2375 stats_proxy_->SetMockStats(stats);
2376 video_stream_encoder_->TriggerCpuNormalUsage();
2377 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2378 EXPECT_EQ(
2379 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2380 kHighFramerate);
2381
2382 video_stream_encoder_->Stop();
2383}
2384
mflodmancc3d4422017-08-03 08:27:51 -07002385TEST_F(VideoStreamEncoderTest,
2386 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002387 const int kFrameWidth = 1280;
2388 const int kFrameHeight = 720;
2389 const int kFramerate = 24;
2390
mflodmancc3d4422017-08-03 08:27:51 -07002391 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002392 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002393 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002394 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2395
2396 // Trigger initial configuration.
2397 VideoEncoderConfig video_encoder_config;
Niels Möller04dd1762018-03-23 16:05:22 +01002398 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002399 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2400 video_encoder_config.number_of_streams = 1;
2401 video_encoder_config.video_stream_factory =
2402 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2403 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002404 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2405 kMaxPayloadLength, false);
2406 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002407
Niels Möller7dc26b72017-12-06 10:27:48 +01002408 EXPECT_EQ(
2409 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2410 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002411
2412 // Trigger overuse, max framerate should be reduced.
2413 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2414 stats.input_frame_rate = kFramerate;
2415 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002416 video_stream_encoder_->TriggerCpuOveruse();
2417 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002418 int adapted_framerate =
2419 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002420 EXPECT_LT(adapted_framerate, kFramerate);
2421
2422 // Change degradation preference to not enable framerate scaling. Target
2423 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002424 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002425 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07002426 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002427 EXPECT_EQ(
2428 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2429 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002430
mflodmancc3d4422017-08-03 08:27:51 -07002431 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002432}
2433
mflodmancc3d4422017-08-03 08:27:51 -07002434TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002435 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002436 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002437 const int kWidth = 640;
2438 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002439
asaperssonfab67072017-04-04 05:51:49 -07002440 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002441
2442 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002443 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002444
2445 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002446 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002447
sprangc5d62e22017-04-02 23:53:04 -07002448 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002449
asaperssonfab67072017-04-04 05:51:49 -07002450 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002451 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002452 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002453
2454 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002455 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002456
sprangc5d62e22017-04-02 23:53:04 -07002457 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002458
mflodmancc3d4422017-08-03 08:27:51 -07002459 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002460}
2461
mflodmancc3d4422017-08-03 08:27:51 -07002462TEST_F(VideoStreamEncoderTest,
2463 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002464 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002465 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002466 const int kWidth = 640;
2467 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002468
2469 // We expect the n initial frames to get dropped.
2470 int i;
2471 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002472 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002473 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002474 }
2475 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002476 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002477 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002478
2479 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002480 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002481
mflodmancc3d4422017-08-03 08:27:51 -07002482 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002483}
2484
mflodmancc3d4422017-08-03 08:27:51 -07002485TEST_F(VideoStreamEncoderTest,
2486 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002487 const int kWidth = 640;
2488 const int kHeight = 360;
mflodmancc3d4422017-08-03 08:27:51 -07002489 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002490
2491 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002492 video_stream_encoder_->SetSource(
kthelgason2bc68642017-02-07 07:02:22 -08002493 &video_source_,
2494 VideoSendStream::DegradationPreference::kMaintainResolution);
2495
asaperssonfab67072017-04-04 05:51:49 -07002496 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002497 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002498 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002499
mflodmancc3d4422017-08-03 08:27:51 -07002500 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002501}
2502
mflodmancc3d4422017-08-03 08:27:51 -07002503TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002504 const int kWidth = 640;
2505 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002506 fake_encoder_.SetQualityScaling(false);
mflodmancc3d4422017-08-03 08:27:51 -07002507 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002508
kthelgasonb83797b2017-02-14 11:57:25 -08002509 // Force quality scaler reconfiguration by resetting the source.
mflodmancc3d4422017-08-03 08:27:51 -07002510 video_stream_encoder_->SetSource(
2511 &video_source_,
2512 VideoSendStream::DegradationPreference::kBalanced);
kthelgasonad9010c2017-02-14 00:46:51 -08002513
asaperssonfab67072017-04-04 05:51:49 -07002514 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002515 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002516 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002517
mflodmancc3d4422017-08-03 08:27:51 -07002518 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002519 fake_encoder_.SetQualityScaling(true);
2520}
2521
mflodmancc3d4422017-08-03 08:27:51 -07002522TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002523 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2524 const int kTooSmallWidth = 10;
2525 const int kTooSmallHeight = 10;
mflodmancc3d4422017-08-03 08:27:51 -07002526 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002527
2528 // Enable kMaintainFramerate preference, no initial limitation.
2529 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002530 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07002531 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
2532 VerifyNoLimitation(source.sink_wants());
2533 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2534
2535 // Trigger adapt down, too small frame, expect no change.
2536 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002537 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002538 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002539 VerifyNoLimitation(source.sink_wants());
2540 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2541 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2542
mflodmancc3d4422017-08-03 08:27:51 -07002543 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002544}
2545
mflodmancc3d4422017-08-03 08:27:51 -07002546TEST_F(VideoStreamEncoderTest,
2547 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002548 const int kTooSmallWidth = 10;
2549 const int kTooSmallHeight = 10;
2550 const int kFpsLimit = 7;
mflodmancc3d4422017-08-03 08:27:51 -07002551 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002552
2553 // Enable kBalanced preference, no initial limitation.
2554 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002555 video_stream_encoder_->SetSource(
2556 &source,
2557 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002558 VerifyNoLimitation(source.sink_wants());
2559 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2560 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2561
2562 // Trigger adapt down, expect limited framerate.
2563 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002564 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002565 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002566 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2567 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2568 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2569 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2570
2571 // Trigger adapt down, too small frame, expect no change.
2572 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002573 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002574 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002575 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2576 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2577 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2578 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2579
mflodmancc3d4422017-08-03 08:27:51 -07002580 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002581}
2582
mflodmancc3d4422017-08-03 08:27:51 -07002583TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002584 fake_encoder_.ForceInitEncodeFailure(true);
mflodmancc3d4422017-08-03 08:27:51 -07002585 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
emircanbbcc3562017-08-18 00:28:40 -07002586 ResetEncoder("VP8", 2, 1, 1, true, false);
asapersson02465b82017-04-10 01:12:52 -07002587 const int kFrameWidth = 1280;
2588 const int kFrameHeight = 720;
2589 video_source_.IncomingCapturedFrame(
2590 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002591 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002592 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002593}
2594
sprangb1ca0732017-02-01 08:38:12 -08002595// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002596TEST_F(VideoStreamEncoderTest,
2597 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
2598 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002599
2600 const int kFrameWidth = 1280;
2601 const int kFrameHeight = 720;
2602 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002603 // requested by
2604 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002605 video_source_.set_adaptation_enabled(true);
2606
2607 video_source_.IncomingCapturedFrame(
2608 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002609 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002610
2611 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002612 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002613 video_source_.IncomingCapturedFrame(
2614 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002615 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002616
asaperssonfab67072017-04-04 05:51:49 -07002617 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002618 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002619 video_source_.IncomingCapturedFrame(
2620 CreateFrame(3, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002621 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002622
mflodmancc3d4422017-08-03 08:27:51 -07002623 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002624}
sprangfe627f32017-03-29 08:24:59 -07002625
mflodmancc3d4422017-08-03 08:27:51 -07002626TEST_F(VideoStreamEncoderTest,
2627 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002628 const int kFrameWidth = 1280;
2629 const int kFrameHeight = 720;
sprang4847ae62017-06-27 07:06:52 -07002630 int kFrameIntervalMs = rtc::kNumMillisecsPerSec / max_framerate_;
sprangc5d62e22017-04-02 23:53:04 -07002631
mflodmancc3d4422017-08-03 08:27:51 -07002632 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2633 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07002634 &video_source_,
2635 VideoSendStream::DegradationPreference::kMaintainResolution);
2636 video_source_.set_adaptation_enabled(true);
2637
sprang4847ae62017-06-27 07:06:52 -07002638 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002639
2640 video_source_.IncomingCapturedFrame(
2641 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002642 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002643
2644 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002645 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002646
2647 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002648 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002649 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002650 video_source_.IncomingCapturedFrame(
2651 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002652 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002653 }
2654
2655 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002656 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002657 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002658 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002659 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002660 video_source_.IncomingCapturedFrame(
2661 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002662 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002663 ++num_frames_dropped;
2664 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002665 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002666 }
2667 }
2668
sprang4847ae62017-06-27 07:06:52 -07002669 // Add some slack to account for frames dropped by the frame dropper.
2670 const int kErrorMargin = 1;
2671 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002672 kErrorMargin);
2673
2674 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002675 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002676 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002677 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002678 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002679 video_source_.IncomingCapturedFrame(
2680 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002681 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002682 ++num_frames_dropped;
2683 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002684 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002685 }
2686 }
sprang4847ae62017-06-27 07:06:52 -07002687 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002688 kErrorMargin);
2689
2690 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002691 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002692 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002693 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002694 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002695 video_source_.IncomingCapturedFrame(
2696 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002697 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002698 ++num_frames_dropped;
2699 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002700 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002701 }
2702 }
sprang4847ae62017-06-27 07:06:52 -07002703 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002704 kErrorMargin);
2705
2706 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002707 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002708 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002709 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002710 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002711 video_source_.IncomingCapturedFrame(
2712 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002713 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002714 ++num_frames_dropped;
2715 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002716 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002717 }
2718 }
2719 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2720
mflodmancc3d4422017-08-03 08:27:51 -07002721 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002722}
2723
mflodmancc3d4422017-08-03 08:27:51 -07002724TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002725 const int kFramerateFps = 5;
2726 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002727 const int kFrameWidth = 1280;
2728 const int kFrameHeight = 720;
2729
sprang4847ae62017-06-27 07:06:52 -07002730 // Reconfigure encoder with two temporal layers and screensharing, which will
2731 // disable frame dropping and make testing easier.
emircanbbcc3562017-08-18 00:28:40 -07002732 ResetEncoder("VP8", 1, 2, 1, true, true);
sprang4847ae62017-06-27 07:06:52 -07002733
mflodmancc3d4422017-08-03 08:27:51 -07002734 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2735 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07002736 &video_source_,
2737 VideoSendStream::DegradationPreference::kMaintainResolution);
2738 video_source_.set_adaptation_enabled(true);
2739
sprang4847ae62017-06-27 07:06:52 -07002740 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002741
2742 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08002743 rtc::VideoSinkWants last_wants;
2744 do {
2745 last_wants = video_source_.sink_wants();
2746
sprangc5d62e22017-04-02 23:53:04 -07002747 // Insert frames to get a new fps estimate...
2748 for (int j = 0; j < kFramerateFps; ++j) {
2749 video_source_.IncomingCapturedFrame(
2750 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08002751 if (video_source_.last_sent_width()) {
2752 sink_.WaitForEncodedFrame(timestamp_ms);
2753 }
sprangc5d62e22017-04-02 23:53:04 -07002754 timestamp_ms += kFrameIntervalMs;
Jonathan Yubc771b72017-12-08 17:04:29 -08002755 fake_clock_.AdvanceTimeMicros(
2756 kFrameIntervalMs * rtc::kNumMicrosecsPerMillisec);
sprangc5d62e22017-04-02 23:53:04 -07002757 }
2758 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002759 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08002760 } while (video_source_.sink_wants().max_framerate_fps <
2761 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07002762
Jonathan Yubc771b72017-12-08 17:04:29 -08002763 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07002764
mflodmancc3d4422017-08-03 08:27:51 -07002765 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002766}
asaperssonf7e294d2017-06-13 23:25:22 -07002767
mflodmancc3d4422017-08-03 08:27:51 -07002768TEST_F(VideoStreamEncoderTest,
2769 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002770 const int kWidth = 1280;
2771 const int kHeight = 720;
2772 const int64_t kFrameIntervalMs = 150;
2773 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002774 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002775
2776 // Enable kBalanced preference, no initial limitation.
2777 AdaptingFrameForwarder source;
2778 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002779 video_stream_encoder_->SetSource(
2780 &source,
2781 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002782 timestamp_ms += kFrameIntervalMs;
2783 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002784 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002785 VerifyNoLimitation(source.sink_wants());
2786 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2787 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2788 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2789
2790 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002791 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002792 timestamp_ms += kFrameIntervalMs;
2793 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002794 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002795 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2796 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2797 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2798 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2799
2800 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002801 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002802 timestamp_ms += kFrameIntervalMs;
2803 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002804 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002805 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2806 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2807 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2808 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2809
2810 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002811 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002812 timestamp_ms += kFrameIntervalMs;
2813 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002814 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002815 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2816 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2817 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2818 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2819
2820 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002821 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002822 timestamp_ms += kFrameIntervalMs;
2823 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002824 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002825 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2826 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2827 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2828 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2829
2830 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002831 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002832 timestamp_ms += kFrameIntervalMs;
2833 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002834 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002835 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2836 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2837 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2838 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2839
2840 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002841 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002842 timestamp_ms += kFrameIntervalMs;
2843 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002844 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002845 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2846 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2847 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2848 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2849
2850 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002851 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002852 timestamp_ms += kFrameIntervalMs;
2853 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002854 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002855 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2856 rtc::VideoSinkWants last_wants = source.sink_wants();
2857 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2858 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2859 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2860
2861 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002862 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002863 timestamp_ms += kFrameIntervalMs;
2864 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002865 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002866 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2867 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2868 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2869 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2870
2871 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002872 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002873 timestamp_ms += kFrameIntervalMs;
2874 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002875 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002876 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2877 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2878 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2879 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2880
2881 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002882 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002883 timestamp_ms += kFrameIntervalMs;
2884 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002885 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002886 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2887 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2888 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2889 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2890
2891 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002892 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002893 timestamp_ms += kFrameIntervalMs;
2894 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002895 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002896 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2897 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2898 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2899 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2900
2901 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002902 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002903 timestamp_ms += kFrameIntervalMs;
2904 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002905 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002906 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2907 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2908 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2909 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2910
2911 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002912 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002913 timestamp_ms += kFrameIntervalMs;
2914 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002915 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002916 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2917 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2918 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2919 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2920
2921 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002922 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002923 timestamp_ms += kFrameIntervalMs;
2924 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002925 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002926 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2927 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2928 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2929 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2930
2931 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002932 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002933 timestamp_ms += kFrameIntervalMs;
2934 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002935 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002936 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2937 VerifyNoLimitation(source.sink_wants());
2938 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2939 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2940 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2941
2942 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002943 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002944 VerifyNoLimitation(source.sink_wants());
2945 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2946
mflodmancc3d4422017-08-03 08:27:51 -07002947 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002948}
2949
mflodmancc3d4422017-08-03 08:27:51 -07002950TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07002951 const int kWidth = 1280;
2952 const int kHeight = 720;
2953 const int64_t kFrameIntervalMs = 150;
2954 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002955 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002956
2957 // Enable kBalanced preference, no initial limitation.
2958 AdaptingFrameForwarder source;
2959 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002960 video_stream_encoder_->SetSource(
2961 &source,
2962 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002963 timestamp_ms += kFrameIntervalMs;
2964 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002965 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002966 VerifyNoLimitation(source.sink_wants());
2967 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2968 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2969 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2970 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2971 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2972 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2973
2974 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002975 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002976 timestamp_ms += kFrameIntervalMs;
2977 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002978 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002979 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2980 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2981 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2982 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2983 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2984 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2985 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2986
2987 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002988 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002989 timestamp_ms += kFrameIntervalMs;
2990 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002991 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002992 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2993 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2994 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2995 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2996 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2997 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2998 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2999
3000 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003001 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003002 timestamp_ms += kFrameIntervalMs;
3003 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003004 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003005 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
3006 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3007 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3008 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3009 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3010 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3011 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3012
3013 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003014 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003015 timestamp_ms += kFrameIntervalMs;
3016 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003017 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003018 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
3019 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3020 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3021 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3022 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3023 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3024 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3025
3026 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003027 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003028 timestamp_ms += kFrameIntervalMs;
3029 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003030 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003031 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3032 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3033 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3034 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3035 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3036 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3037 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3038
3039 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003040 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003041 timestamp_ms += kFrameIntervalMs;
3042 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003043 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003044 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3045 VerifyNoLimitation(source.sink_wants());
3046 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3047 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3048 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3049 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3050 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3051 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3052
3053 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003054 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003055 VerifyNoLimitation(source.sink_wants());
3056 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3057 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3058
mflodmancc3d4422017-08-03 08:27:51 -07003059 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003060}
3061
mflodmancc3d4422017-08-03 08:27:51 -07003062TEST_F(VideoStreamEncoderTest,
3063 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07003064 const int kWidth = 640;
3065 const int kHeight = 360;
3066 const int kFpsLimit = 15;
3067 const int64_t kFrameIntervalMs = 150;
3068 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07003069 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07003070
3071 // Enable kBalanced preference, no initial limitation.
3072 AdaptingFrameForwarder source;
3073 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07003074 video_stream_encoder_->SetSource(
3075 &source,
3076 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07003077 timestamp_ms += kFrameIntervalMs;
3078 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003079 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003080 VerifyNoLimitation(source.sink_wants());
3081 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3082 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3083 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3084 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3085 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3086 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3087
3088 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003089 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003090 timestamp_ms += kFrameIntervalMs;
3091 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003092 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003093 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
3094 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3095 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3096 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3097 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3098 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3099 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3100
3101 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003102 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003103 timestamp_ms += kFrameIntervalMs;
3104 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003105 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003106 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
3107 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3108 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3109 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3110 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3111 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3112 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3113
3114 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003115 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003116 timestamp_ms += kFrameIntervalMs;
3117 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003118 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003119 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3120 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3121 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3122 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3123 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3124 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3125 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3126
3127 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003128 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003129 timestamp_ms += kFrameIntervalMs;
3130 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003131 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003132 VerifyNoLimitation(source.sink_wants());
3133 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3134 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3135 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3136 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3137 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3138 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3139
3140 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003141 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003142 VerifyNoLimitation(source.sink_wants());
3143 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3144 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3145
mflodmancc3d4422017-08-03 08:27:51 -07003146 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003147}
3148
mflodmancc3d4422017-08-03 08:27:51 -07003149TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003150 // Simulates simulcast behavior and makes highest stream resolutions divisible
3151 // by 4.
3152 class CroppingVideoStreamFactory
3153 : public VideoEncoderConfig::VideoStreamFactoryInterface {
3154 public:
3155 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
3156 int framerate)
3157 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
3158 EXPECT_GT(num_temporal_layers, 0u);
3159 EXPECT_GT(framerate, 0);
3160 }
3161
3162 private:
3163 std::vector<VideoStream> CreateEncoderStreams(
3164 int width,
3165 int height,
3166 const VideoEncoderConfig& encoder_config) override {
3167 std::vector<VideoStream> streams =
3168 test::CreateVideoStreams(width - width % 4, height - height % 4,
3169 encoder_config);
3170 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +01003171 stream.num_temporal_layers = num_temporal_layers_;
ilnik6b826ef2017-06-16 06:53:48 -07003172 stream.max_framerate = framerate_;
3173 }
3174 return streams;
3175 }
3176
3177 const size_t num_temporal_layers_;
3178 const int framerate_;
3179 };
3180
3181 const int kFrameWidth = 1920;
3182 const int kFrameHeight = 1080;
3183 // 3/4 of 1920.
3184 const int kAdaptedFrameWidth = 1440;
3185 // 3/4 of 1080 rounded down to multiple of 4.
3186 const int kAdaptedFrameHeight = 808;
3187 const int kFramerate = 24;
3188
mflodmancc3d4422017-08-03 08:27:51 -07003189 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003190 // Trigger reconfigure encoder (without resetting the entire instance).
3191 VideoEncoderConfig video_encoder_config;
Niels Möller04dd1762018-03-23 16:05:22 +01003192 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07003193 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3194 video_encoder_config.number_of_streams = 1;
3195 video_encoder_config.video_stream_factory =
3196 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003197 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
3198 kMaxPayloadLength, false);
3199 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003200
3201 video_source_.set_adaptation_enabled(true);
3202
3203 video_source_.IncomingCapturedFrame(
3204 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003205 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003206
3207 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003208 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003209 video_source_.IncomingCapturedFrame(
3210 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003211 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003212
mflodmancc3d4422017-08-03 08:27:51 -07003213 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003214}
3215
mflodmancc3d4422017-08-03 08:27:51 -07003216TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003217 const int kFrameWidth = 1280;
3218 const int kFrameHeight = 720;
3219 const int kLowFps = 2;
3220 const int kHighFps = 30;
3221
mflodmancc3d4422017-08-03 08:27:51 -07003222 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003223
3224 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3225 max_framerate_ = kLowFps;
3226
3227 // Insert 2 seconds of 2fps video.
3228 for (int i = 0; i < kLowFps * 2; ++i) {
3229 video_source_.IncomingCapturedFrame(
3230 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3231 WaitForEncodedFrame(timestamp_ms);
3232 timestamp_ms += 1000 / kLowFps;
3233 }
3234
3235 // Make sure encoder is updated with new target.
mflodmancc3d4422017-08-03 08:27:51 -07003236 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003237 video_source_.IncomingCapturedFrame(
3238 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3239 WaitForEncodedFrame(timestamp_ms);
3240 timestamp_ms += 1000 / kLowFps;
3241
3242 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3243
3244 // Insert 30fps frames for just a little more than the forced update period.
3245 const int kVcmTimerIntervalFrames =
3246 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3247 const int kFrameIntervalMs = 1000 / kHighFps;
3248 max_framerate_ = kHighFps;
3249 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3250 video_source_.IncomingCapturedFrame(
3251 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3252 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3253 // be dropped if the encoder hans't been updated with the new higher target
3254 // framerate yet, causing it to overshoot the target bitrate and then
3255 // suffering the wrath of the media optimizer.
3256 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3257 timestamp_ms += kFrameIntervalMs;
3258 }
3259
3260 // Don expect correct measurement just yet, but it should be higher than
3261 // before.
3262 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3263
mflodmancc3d4422017-08-03 08:27:51 -07003264 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003265}
3266
mflodmancc3d4422017-08-03 08:27:51 -07003267TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003268 const int kFrameWidth = 1280;
3269 const int kFrameHeight = 720;
3270 const int kTargetBitrateBps = 1000000;
3271
3272 MockBitrateObserver bitrate_observer;
mflodmancc3d4422017-08-03 08:27:51 -07003273 video_stream_encoder_->SetBitrateObserver(&bitrate_observer);
sprang4847ae62017-06-27 07:06:52 -07003274
3275 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3276 // Initial bitrate update.
mflodmancc3d4422017-08-03 08:27:51 -07003277 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3278 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003279
3280 // Insert a first video frame, causes another bitrate update.
3281 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3282 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3283 video_source_.IncomingCapturedFrame(
3284 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3285 WaitForEncodedFrame(timestamp_ms);
3286
3287 // Next, simulate video suspension due to pacer queue overrun.
mflodmancc3d4422017-08-03 08:27:51 -07003288 video_stream_encoder_->OnBitrateUpdated(0, 0, 1);
sprang4847ae62017-06-27 07:06:52 -07003289
3290 // Skip ahead until a new periodic parameter update should have occured.
3291 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3292 fake_clock_.AdvanceTimeMicros(
3293 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3294 rtc::kNumMicrosecsPerMillisec);
3295
3296 // Bitrate observer should not be called.
3297 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3298 video_source_.IncomingCapturedFrame(
3299 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3300 ExpectDroppedFrame();
3301
mflodmancc3d4422017-08-03 08:27:51 -07003302 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003303}
ilnik6b826ef2017-06-16 06:53:48 -07003304
perkj26091b12016-09-01 01:17:40 -07003305} // namespace webrtc