blob: a4f799990bc1b69461a34c2a6ae104cb0e135518 [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;
34const int64_t kFrameTimeoutMs = 100;
emircanbbcc3562017-08-18 00:28:40 -070035const unsigned char kNumSlDummy = 0;
sprangc5d62e22017-04-02 23:53:04 -070036} // namespace
kthelgason33ce8892016-12-09 03:53:59 -080037
perkj26091b12016-09-01 01:17:40 -070038namespace webrtc {
39
kthelgason876222f2016-11-29 01:44:11 -080040using DegredationPreference = VideoSendStream::DegradationPreference;
sprangb1ca0732017-02-01 08:38:12 -080041using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080042using ::testing::_;
43using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080044
perkj803d97f2016-11-01 11:45:46 -070045namespace {
asapersson5f7226f2016-11-25 04:37:00 -080046const size_t kMaxPayloadLength = 1440;
kthelgason2bc68642017-02-07 07:02:22 -080047const int kTargetBitrateBps = 1000000;
48const int kLowTargetBitrateBps = kTargetBitrateBps / 10;
49const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070050const int kDefaultFramerate = 30;
asapersson5f7226f2016-11-25 04:37:00 -080051
perkj803d97f2016-11-01 11:45:46 -070052class TestBuffer : public webrtc::I420Buffer {
53 public:
54 TestBuffer(rtc::Event* event, int width, int height)
55 : I420Buffer(width, height), event_(event) {}
56
57 private:
58 friend class rtc::RefCountedObject<TestBuffer>;
59 ~TestBuffer() override {
60 if (event_)
61 event_->Set();
62 }
63 rtc::Event* const event_;
64};
65
Niels Möller7dc26b72017-12-06 10:27:48 +010066class CpuOveruseDetectorProxy : public OveruseFrameDetector {
67 public:
68 CpuOveruseDetectorProxy(const CpuOveruseOptions& options,
69 AdaptationObserverInterface* overuse_observer,
Niels Möller7dc26b72017-12-06 10:27:48 +010070 CpuOveruseMetricsObserver* metrics_observer)
71 : OveruseFrameDetector(options,
72 overuse_observer,
Niels Möller7dc26b72017-12-06 10:27:48 +010073 metrics_observer),
74 last_target_framerate_fps_(-1) {}
75 virtual ~CpuOveruseDetectorProxy() {}
76
77 void OnTargetFramerateUpdated(int framerate_fps) override {
78 rtc::CritScope cs(&lock_);
79 last_target_framerate_fps_ = framerate_fps;
80 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
81 }
82
83 int GetLastTargetFramerate() {
84 rtc::CritScope cs(&lock_);
85 return last_target_framerate_fps_;
86 }
87
88 private:
89 rtc::CriticalSection lock_;
90 int last_target_framerate_fps_ RTC_GUARDED_BY(lock_);
91};
92
mflodmancc3d4422017-08-03 08:27:51 -070093class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -070094 public:
Niels Möller7dc26b72017-12-06 10:27:48 +010095 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
96 const VideoSendStream::Config::EncoderSettings& settings)
mflodmancc3d4422017-08-03 08:27:51 -070097 : VideoStreamEncoder(
98 1 /* number_of_cores */,
99 stats_proxy,
100 settings,
101 nullptr /* pre_encode_callback */,
mflodmancc3d4422017-08-03 08:27:51 -0700102 std::unique_ptr<OveruseFrameDetector>(
Niels Möller7dc26b72017-12-06 10:27:48 +0100103 overuse_detector_proxy_ = new CpuOveruseDetectorProxy(
mflodmancc3d4422017-08-03 08:27:51 -0700104 GetCpuOveruseOptions(settings.full_overuse_time),
105 this,
mflodmancc3d4422017-08-03 08:27:51 -0700106 stats_proxy))) {}
perkj803d97f2016-11-01 11:45:46 -0700107
sprangb1ca0732017-02-01 08:38:12 -0800108 void PostTaskAndWait(bool down, AdaptReason reason) {
perkj803d97f2016-11-01 11:45:46 -0700109 rtc::Event event(false, false);
kthelgason876222f2016-11-29 01:44:11 -0800110 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800111 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700112 event.Set();
113 });
perkj070ba852017-02-16 15:46:27 -0800114 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700115 }
116
kthelgason2fc52542017-03-03 00:24:41 -0800117 // This is used as a synchronisation mechanism, to make sure that the
118 // encoder queue is not blocked before we start sending it frames.
119 void WaitUntilTaskQueueIsIdle() {
120 rtc::Event event(false, false);
121 encoder_queue()->PostTask([&event] {
122 event.Set();
123 });
124 ASSERT_TRUE(event.Wait(5000));
125 }
126
sprangb1ca0732017-02-01 08:38:12 -0800127 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800128
sprangb1ca0732017-02-01 08:38:12 -0800129 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800130
sprangb1ca0732017-02-01 08:38:12 -0800131 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800132
sprangb1ca0732017-02-01 08:38:12 -0800133 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700134
Niels Möller7dc26b72017-12-06 10:27:48 +0100135 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700136};
137
asapersson5f7226f2016-11-25 04:37:00 -0800138class VideoStreamFactory
139 : public VideoEncoderConfig::VideoStreamFactoryInterface {
140 public:
sprangfda496a2017-06-15 04:21:07 -0700141 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
142 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800143 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700144 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800145 }
146
147 private:
148 std::vector<VideoStream> CreateEncoderStreams(
149 int width,
150 int height,
151 const VideoEncoderConfig& encoder_config) override {
152 std::vector<VideoStream> streams =
153 test::CreateVideoStreams(width, height, encoder_config);
154 for (VideoStream& stream : streams) {
155 stream.temporal_layer_thresholds_bps.resize(num_temporal_layers_ - 1);
sprangfda496a2017-06-15 04:21:07 -0700156 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800157 }
158 return streams;
159 }
sprangfda496a2017-06-15 04:21:07 -0700160
asapersson5f7226f2016-11-25 04:37:00 -0800161 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700162 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800163};
164
ilnik6b826ef2017-06-16 06:53:48 -0700165
sprangb1ca0732017-02-01 08:38:12 -0800166class AdaptingFrameForwarder : public test::FrameForwarder {
167 public:
168 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700169 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800170
171 void set_adaptation_enabled(bool enabled) {
172 rtc::CritScope cs(&crit_);
173 adaptation_enabled_ = enabled;
174 }
175
asaperssonfab67072017-04-04 05:51:49 -0700176 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800177 rtc::CritScope cs(&crit_);
178 return adaptation_enabled_;
179 }
180
asapersson09f05612017-05-15 23:40:18 -0700181 rtc::VideoSinkWants last_wants() const {
182 rtc::CritScope cs(&crit_);
183 return last_wants_;
184 }
185
sprangb1ca0732017-02-01 08:38:12 -0800186 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
187 int cropped_width = 0;
188 int cropped_height = 0;
189 int out_width = 0;
190 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700191 if (adaption_enabled()) {
192 if (adapter_.AdaptFrameResolution(
193 video_frame.width(), video_frame.height(),
194 video_frame.timestamp_us() * 1000, &cropped_width,
195 &cropped_height, &out_width, &out_height)) {
196 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
197 nullptr, out_width, out_height),
198 99, 99, kVideoRotation_0);
199 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
200 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
201 }
sprangb1ca0732017-02-01 08:38:12 -0800202 } else {
203 test::FrameForwarder::IncomingCapturedFrame(video_frame);
204 }
205 }
206
207 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
208 const rtc::VideoSinkWants& wants) override {
209 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700210 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700211 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
212 wants.max_pixel_count,
213 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800214 test::FrameForwarder::AddOrUpdateSink(sink, wants);
215 }
sprangb1ca0732017-02-01 08:38:12 -0800216 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700217 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
218 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
sprangb1ca0732017-02-01 08:38:12 -0800219};
sprangc5d62e22017-04-02 23:53:04 -0700220
221class MockableSendStatisticsProxy : public SendStatisticsProxy {
222 public:
223 MockableSendStatisticsProxy(Clock* clock,
224 const VideoSendStream::Config& config,
225 VideoEncoderConfig::ContentType content_type)
226 : SendStatisticsProxy(clock, config, content_type) {}
227
228 VideoSendStream::Stats GetStats() override {
229 rtc::CritScope cs(&lock_);
230 if (mock_stats_)
231 return *mock_stats_;
232 return SendStatisticsProxy::GetStats();
233 }
234
235 void SetMockStats(const VideoSendStream::Stats& stats) {
236 rtc::CritScope cs(&lock_);
237 mock_stats_.emplace(stats);
238 }
239
240 void ResetMockStats() {
241 rtc::CritScope cs(&lock_);
242 mock_stats_.reset();
243 }
244
245 private:
246 rtc::CriticalSection lock_;
danilchapa37de392017-09-09 04:17:22 -0700247 rtc::Optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700248};
249
sprang4847ae62017-06-27 07:06:52 -0700250class MockBitrateObserver : public VideoBitrateAllocationObserver {
251 public:
252 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const BitrateAllocation&));
253};
254
perkj803d97f2016-11-01 11:45:46 -0700255} // namespace
256
mflodmancc3d4422017-08-03 08:27:51 -0700257class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700258 public:
259 static const int kDefaultTimeoutMs = 30 * 1000;
260
mflodmancc3d4422017-08-03 08:27:51 -0700261 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700262 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700263 codec_width_(320),
264 codec_height_(240),
sprang4847ae62017-06-27 07:06:52 -0700265 max_framerate_(30),
perkj26091b12016-09-01 01:17:40 -0700266 fake_encoder_(),
sprangc5d62e22017-04-02 23:53:04 -0700267 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700268 Clock::GetRealTimeClock(),
269 video_send_config_,
270 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700271 sink_(&fake_encoder_) {}
272
273 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700274 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700275 video_send_config_ = VideoSendStream::Config(nullptr);
276 video_send_config_.encoder_settings.encoder = &fake_encoder_;
277 video_send_config_.encoder_settings.payload_name = "FAKE";
278 video_send_config_.encoder_settings.payload_type = 125;
279
Per512ecb32016-09-23 15:52:06 +0200280 VideoEncoderConfig video_encoder_config;
perkjfa10b552016-10-02 23:45:26 -0700281 test::FillEncoderConfiguration(1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700282 video_encoder_config.video_stream_factory =
283 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100284 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700285
286 // Framerate limit is specified by the VideoStreamFactory.
287 std::vector<VideoStream> streams =
288 video_encoder_config.video_stream_factory->CreateEncoderStreams(
289 codec_width_, codec_height_, video_encoder_config);
290 max_framerate_ = streams[0].max_framerate;
291 fake_clock_.SetTimeMicros(1234);
292
asapersson5f7226f2016-11-25 04:37:00 -0800293 ConfigureEncoder(std::move(video_encoder_config), true /* nack_enabled */);
294 }
295
296 void ConfigureEncoder(VideoEncoderConfig video_encoder_config,
297 bool nack_enabled) {
mflodmancc3d4422017-08-03 08:27:51 -0700298 if (video_stream_encoder_)
299 video_stream_encoder_->Stop();
300 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700301 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700302 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
303 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -0700304 &video_source_,
305 VideoSendStream::DegradationPreference::kMaintainFramerate);
mflodmancc3d4422017-08-03 08:27:51 -0700306 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
307 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
308 kMaxPayloadLength, nack_enabled);
309 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800310 }
311
312 void ResetEncoder(const std::string& payload_name,
313 size_t num_streams,
314 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700315 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700316 bool nack_enabled,
317 bool screenshare) {
asapersson5f7226f2016-11-25 04:37:00 -0800318 video_send_config_.encoder_settings.payload_name = payload_name;
319
320 VideoEncoderConfig video_encoder_config;
321 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800322 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800323 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700324 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
325 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700326 video_encoder_config.content_type =
327 screenshare ? VideoEncoderConfig::ContentType::kScreen
328 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700329 if (payload_name == "VP9") {
330 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
331 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
332 video_encoder_config.encoder_specific_settings =
333 new rtc::RefCountedObject<
334 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
335 }
asapersson5f7226f2016-11-25 04:37:00 -0800336 ConfigureEncoder(std::move(video_encoder_config), nack_enabled);
perkj26091b12016-09-01 01:17:40 -0700337 }
338
sprang57c2fff2017-01-16 06:24:02 -0800339 VideoFrame CreateFrame(int64_t ntp_time_ms,
340 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200341 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
342 destruction_event, codec_width_, codec_height_),
343 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800344 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700345 return frame;
346 }
347
sprang57c2fff2017-01-16 06:24:02 -0800348 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700349 VideoFrame frame(
350 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
351 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800352 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700353 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700354 return frame;
355 }
356
asapersson02465b82017-04-10 01:12:52 -0700357 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700358 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700359 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
360 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700361 }
362
asapersson09f05612017-05-15 23:40:18 -0700363 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
364 const rtc::VideoSinkWants& wants2) {
365 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
366 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
367 }
368
369 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
370 const rtc::VideoSinkWants& wants2) {
371 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
372 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
373 EXPECT_GT(wants1.max_pixel_count, 0);
374 }
375
376 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
377 const rtc::VideoSinkWants& wants2) {
378 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
379 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
380 }
381
asaperssonf7e294d2017-06-13 23:25:22 -0700382 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
383 const rtc::VideoSinkWants& wants2) {
384 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
385 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
386 }
387
388 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
389 const rtc::VideoSinkWants& wants2) {
390 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
391 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
392 }
393
394 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
395 const rtc::VideoSinkWants& wants2) {
396 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
397 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
398 }
399
400 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
401 const rtc::VideoSinkWants& wants2) {
402 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
403 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
404 EXPECT_GT(wants1.max_pixel_count, 0);
405 }
406
407 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
408 const rtc::VideoSinkWants& wants2) {
409 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
410 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
411 }
412
asapersson09f05612017-05-15 23:40:18 -0700413 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
414 int pixel_count) {
415 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700416 EXPECT_LT(wants.max_pixel_count, pixel_count);
417 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700418 }
419
420 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
421 EXPECT_LT(wants.max_framerate_fps, fps);
422 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
423 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700424 }
425
asaperssonf7e294d2017-06-13 23:25:22 -0700426 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
427 int expected_fps) {
428 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
429 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
430 EXPECT_FALSE(wants.target_pixel_count);
431 }
432
sprang4847ae62017-06-27 07:06:52 -0700433 void WaitForEncodedFrame(int64_t expected_ntp_time) {
434 sink_.WaitForEncodedFrame(expected_ntp_time);
435 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
436 }
437
438 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
439 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
440 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
441 return ok;
442 }
443
444 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
445 sink_.WaitForEncodedFrame(expected_width, expected_height);
446 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
447 }
448
449 void ExpectDroppedFrame() {
450 sink_.ExpectDroppedFrame();
451 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
452 }
453
454 bool WaitForFrame(int64_t timeout_ms) {
455 bool ok = sink_.WaitForFrame(timeout_ms);
456 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
457 return ok;
458 }
459
perkj26091b12016-09-01 01:17:40 -0700460 class TestEncoder : public test::FakeEncoder {
461 public:
462 TestEncoder()
463 : FakeEncoder(Clock::GetRealTimeClock()),
464 continue_encode_event_(false, false) {}
465
asaperssonfab67072017-04-04 05:51:49 -0700466 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800467 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700468 return config_;
469 }
470
471 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800472 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700473 block_next_encode_ = true;
474 }
475
kthelgason876222f2016-11-29 01:44:11 -0800476 VideoEncoder::ScalingSettings GetScalingSettings() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800477 rtc::CritScope lock(&local_crit_sect_);
kthelgasonad9010c2017-02-14 00:46:51 -0800478 if (quality_scaling_)
asapersson142fcc92017-08-17 08:58:54 -0700479 return VideoEncoder::ScalingSettings(true, 1, 2, kMinPixelsPerFrame);
kthelgasonad9010c2017-02-14 00:46:51 -0800480 return VideoEncoder::ScalingSettings(false);
kthelgason876222f2016-11-29 01:44:11 -0800481 }
482
perkjfa10b552016-10-02 23:45:26 -0700483 void ContinueEncode() { continue_encode_event_.Set(); }
484
485 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
486 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800487 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700488 EXPECT_EQ(timestamp_, timestamp);
489 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
490 }
491
kthelgason2fc52542017-03-03 00:24:41 -0800492 void SetQualityScaling(bool b) {
493 rtc::CritScope lock(&local_crit_sect_);
494 quality_scaling_ = b;
495 }
kthelgasonad9010c2017-02-14 00:46:51 -0800496
sprangfe627f32017-03-29 08:24:59 -0700497 void ForceInitEncodeFailure(bool force_failure) {
498 rtc::CritScope lock(&local_crit_sect_);
499 force_init_encode_failed_ = force_failure;
500 }
501
perkjfa10b552016-10-02 23:45:26 -0700502 private:
perkj26091b12016-09-01 01:17:40 -0700503 int32_t Encode(const VideoFrame& input_image,
504 const CodecSpecificInfo* codec_specific_info,
505 const std::vector<FrameType>* frame_types) override {
506 bool block_encode;
507 {
brandtre78d2662017-01-16 05:57:16 -0800508 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700509 EXPECT_GT(input_image.timestamp(), timestamp_);
510 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
511 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
512
513 timestamp_ = input_image.timestamp();
514 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700515 last_input_width_ = input_image.width();
516 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700517 block_encode = block_next_encode_;
518 block_next_encode_ = false;
519 }
520 int32_t result =
521 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
522 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700523 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700524 return result;
525 }
526
sprangfe627f32017-03-29 08:24:59 -0700527 int32_t InitEncode(const VideoCodec* config,
528 int32_t number_of_cores,
529 size_t max_payload_size) override {
530 int res =
531 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
532 rtc::CritScope lock(&local_crit_sect_);
533 if (config->codecType == kVideoCodecVP8 && config->VP8().tl_factory) {
534 // Simulate setting up temporal layers, in order to validate the life
535 // cycle of these objects.
536 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
537 int num_temporal_layers =
538 std::max<int>(1, config->VP8().numberOfTemporalLayers);
539 for (int i = 0; i < num_streams; ++i) {
540 allocated_temporal_layers_.emplace_back(
541 config->VP8().tl_factory->Create(i, num_temporal_layers, 42));
542 }
543 }
544 if (force_init_encode_failed_)
545 return -1;
546 return res;
547 }
548
brandtre78d2662017-01-16 05:57:16 -0800549 rtc::CriticalSection local_crit_sect_;
danilchapa37de392017-09-09 04:17:22 -0700550 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700551 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700552 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
553 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
554 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
555 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
556 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
sprangfe627f32017-03-29 08:24:59 -0700557 std::vector<std::unique_ptr<TemporalLayers>> allocated_temporal_layers_
danilchapa37de392017-09-09 04:17:22 -0700558 RTC_GUARDED_BY(local_crit_sect_);
559 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700560 };
561
mflodmancc3d4422017-08-03 08:27:51 -0700562 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700563 public:
564 explicit TestSink(TestEncoder* test_encoder)
565 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
566
perkj26091b12016-09-01 01:17:40 -0700567 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700568 EXPECT_TRUE(
569 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
570 }
571
572 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
573 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700574 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700575 if (!encoded_frame_event_.Wait(timeout_ms))
576 return false;
perkj26091b12016-09-01 01:17:40 -0700577 {
578 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800579 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700580 }
581 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700582 return true;
perkj26091b12016-09-01 01:17:40 -0700583 }
584
sprangb1ca0732017-02-01 08:38:12 -0800585 void WaitForEncodedFrame(uint32_t expected_width,
586 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700587 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100588 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700589 }
590
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100591 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700592 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800593 uint32_t width = 0;
594 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800595 {
596 rtc::CritScope lock(&crit_);
597 width = last_width_;
598 height = last_height_;
599 }
600 EXPECT_EQ(expected_height, height);
601 EXPECT_EQ(expected_width, width);
602 }
603
kthelgason2fc52542017-03-03 00:24:41 -0800604 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800605
sprangc5d62e22017-04-02 23:53:04 -0700606 bool WaitForFrame(int64_t timeout_ms) {
607 return encoded_frame_event_.Wait(timeout_ms);
608 }
609
perkj26091b12016-09-01 01:17:40 -0700610 void SetExpectNoFrames() {
611 rtc::CritScope lock(&crit_);
612 expect_frames_ = false;
613 }
614
asaperssonfab67072017-04-04 05:51:49 -0700615 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200616 rtc::CritScope lock(&crit_);
617 return number_of_reconfigurations_;
618 }
619
asaperssonfab67072017-04-04 05:51:49 -0700620 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200621 rtc::CritScope lock(&crit_);
622 return min_transmit_bitrate_bps_;
623 }
624
perkj26091b12016-09-01 01:17:40 -0700625 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700626 Result OnEncodedImage(
627 const EncodedImage& encoded_image,
628 const CodecSpecificInfo* codec_specific_info,
629 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200630 rtc::CritScope lock(&crit_);
631 EXPECT_TRUE(expect_frames_);
sprangb1ca0732017-02-01 08:38:12 -0800632 last_timestamp_ = encoded_image._timeStamp;
633 last_width_ = encoded_image._encodedWidth;
634 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200635 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800636 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200637 }
638
639 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
640 int min_transmit_bitrate_bps) override {
641 rtc::CriticalSection crit_;
642 ++number_of_reconfigurations_;
643 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
644 }
645
perkj26091b12016-09-01 01:17:40 -0700646 rtc::CriticalSection crit_;
647 TestEncoder* test_encoder_;
648 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800649 uint32_t last_timestamp_ = 0;
650 uint32_t last_height_ = 0;
651 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700652 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200653 int number_of_reconfigurations_ = 0;
654 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700655 };
656
657 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100658 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200659 int codec_width_;
660 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700661 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700662 TestEncoder fake_encoder_;
sprangc5d62e22017-04-02 23:53:04 -0700663 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700664 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800665 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700666 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700667 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700668};
669
mflodmancc3d4422017-08-03 08:27:51 -0700670TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
671 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700672 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700673 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700674 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700675 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700676 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700677}
678
mflodmancc3d4422017-08-03 08:27:51 -0700679TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700680 // Dropped since no target bitrate has been set.
681 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700682 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
683 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700684
mflodmancc3d4422017-08-03 08:27:51 -0700685 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700686
perkja49cbd32016-09-16 07:53:41 -0700687 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700688 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700689 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700690}
691
mflodmancc3d4422017-08-03 08:27:51 -0700692TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
693 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700694 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700695 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700696
mflodmancc3d4422017-08-03 08:27:51 -0700697 video_stream_encoder_->OnBitrateUpdated(0, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700698 // Dropped since bitrate is zero.
perkja49cbd32016-09-16 07:53:41 -0700699 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkj26091b12016-09-01 01:17:40 -0700700
mflodmancc3d4422017-08-03 08:27:51 -0700701 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700702 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700703 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700704 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700705}
706
mflodmancc3d4422017-08-03 08:27:51 -0700707TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
708 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700709 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700710 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700711
712 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700713 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700714
perkja49cbd32016-09-16 07:53:41 -0700715 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700716 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700717 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700718}
719
mflodmancc3d4422017-08-03 08:27:51 -0700720TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
721 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700722
perkja49cbd32016-09-16 07:53:41 -0700723 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700724 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700725
mflodmancc3d4422017-08-03 08:27:51 -0700726 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700727 sink_.SetExpectNoFrames();
728 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700729 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
730 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700731}
732
mflodmancc3d4422017-08-03 08:27:51 -0700733TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
734 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700735
736 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700737 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700738 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700739 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
740 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700741 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
742 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700743 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700744 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700745
mflodmancc3d4422017-08-03 08:27:51 -0700746 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700747}
748
mflodmancc3d4422017-08-03 08:27:51 -0700749TEST_F(VideoStreamEncoderTest,
750 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
751 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100752 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200753
754 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200755 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700756 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100757 // The encoder will have been configured once when the first frame is
758 // received.
759 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200760
761 VideoEncoderConfig video_encoder_config;
perkjfa10b552016-10-02 23:45:26 -0700762 test::FillEncoderConfiguration(1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200763 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -0700764 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
765 kMaxPayloadLength,
766 true /* nack_enabled */);
Per512ecb32016-09-23 15:52:06 +0200767
768 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200769 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700770 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100771 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700772 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700773
mflodmancc3d4422017-08-03 08:27:51 -0700774 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -0700775}
776
mflodmancc3d4422017-08-03 08:27:51 -0700777TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
778 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkjfa10b552016-10-02 23:45:26 -0700779
780 // Capture a frame and wait for it to synchronize with the encoder thread.
781 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700782 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100783 // The encoder will have been configured once.
784 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700785 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
786 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
787
788 codec_width_ *= 2;
789 codec_height_ *= 2;
790 // Capture a frame with a higher resolution and wait for it to synchronize
791 // with the encoder thread.
792 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700793 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700794 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
795 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100796 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700797
mflodmancc3d4422017-08-03 08:27:51 -0700798 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -0700799}
800
mflodmancc3d4422017-08-03 08:27:51 -0700801TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOffFor1S1TLWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800802 const bool kNackEnabled = true;
803 const size_t kNumStreams = 1;
804 const size_t kNumTl = 1;
emircanbbcc3562017-08-18 00:28:40 -0700805 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700806 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800807
808 // Capture a frame and wait for it to synchronize with the encoder thread.
809 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700810 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800811 // The encoder have been configured once when the first frame is received.
812 EXPECT_EQ(1, sink_.number_of_reconfigurations());
813 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
814 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
815 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
816 // Resilience is off for no temporal layers with nack on.
817 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700818 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800819}
820
mflodmancc3d4422017-08-03 08:27:51 -0700821TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOffFor2S1TlWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800822 const bool kNackEnabled = true;
823 const size_t kNumStreams = 2;
824 const size_t kNumTl = 1;
emircanbbcc3562017-08-18 00:28:40 -0700825 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700826 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800827
828 // Capture a frame and wait for it to synchronize with the encoder thread.
829 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700830 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800831 // The encoder have been configured once when the first frame is received.
832 EXPECT_EQ(1, sink_.number_of_reconfigurations());
833 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
834 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
835 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
836 // Resilience is off for no temporal layers and >1 streams with nack on.
837 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700838 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800839}
840
mflodmancc3d4422017-08-03 08:27:51 -0700841TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOnFor1S1TLWithNackDisabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800842 const bool kNackEnabled = false;
843 const size_t kNumStreams = 1;
844 const size_t kNumTl = 1;
emircanbbcc3562017-08-18 00:28:40 -0700845 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700846 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800847
848 // Capture a frame and wait for it to synchronize with the encoder thread.
849 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700850 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800851 // The encoder have been configured once when the first frame is received.
852 EXPECT_EQ(1, sink_.number_of_reconfigurations());
853 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
854 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
855 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
856 // Resilience is on for no temporal layers with nack off.
857 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700858 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800859}
860
mflodmancc3d4422017-08-03 08:27:51 -0700861TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOnFor1S2TlWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800862 const bool kNackEnabled = true;
863 const size_t kNumStreams = 1;
864 const size_t kNumTl = 2;
emircanbbcc3562017-08-18 00:28:40 -0700865 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700866 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800867
868 // Capture a frame and wait for it to synchronize with the encoder thread.
869 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700870 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800871 // The encoder have been configured once when the first frame is received.
872 EXPECT_EQ(1, sink_.number_of_reconfigurations());
873 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
874 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
875 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
876 // Resilience is on for temporal layers.
877 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700878 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800879}
880
emircanbbcc3562017-08-18 00:28:40 -0700881TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOffFor1SL1TLWithNackEnabled) {
882 const bool kNackEnabled = true;
883 const size_t kNumStreams = 1;
884 const size_t kNumTl = 1;
885 const unsigned char kNumSl = 1;
886 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
887 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
888
889 // Capture a frame and wait for it to synchronize with the encoder thread.
890 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
891 sink_.WaitForEncodedFrame(1);
892 // The encoder have been configured once when the first frame is received.
893 EXPECT_EQ(1, sink_.number_of_reconfigurations());
894 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
895 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
896 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
897 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
898 // Resilience is off for no spatial and temporal layers with nack on.
899 EXPECT_FALSE(fake_encoder_.codec_config().VP9()->resilienceOn);
900 video_stream_encoder_->Stop();
901}
902
903TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOnFor1SL1TLWithNackDisabled) {
904 const bool kNackEnabled = false;
905 const size_t kNumStreams = 1;
906 const size_t kNumTl = 1;
907 const unsigned char kNumSl = 1;
908 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
909 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
910
911 // Capture a frame and wait for it to synchronize with the encoder thread.
912 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
913 sink_.WaitForEncodedFrame(1);
914 // The encoder have been configured once when the first frame is received.
915 EXPECT_EQ(1, sink_.number_of_reconfigurations());
916 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
917 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
918 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
919 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
920 // Resilience is on if nack is off.
921 EXPECT_TRUE(fake_encoder_.codec_config().VP9()->resilienceOn);
922 video_stream_encoder_->Stop();
923}
924
925TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOnFor2SL1TLWithNackEnabled) {
926 const bool kNackEnabled = true;
927 const size_t kNumStreams = 1;
928 const size_t kNumTl = 1;
929 const unsigned char kNumSl = 2;
930 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
931 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
932
933 // Capture a frame and wait for it to synchronize with the encoder thread.
934 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
935 sink_.WaitForEncodedFrame(1);
936 // The encoder have been configured once when the first frame is received.
937 EXPECT_EQ(1, sink_.number_of_reconfigurations());
938 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
939 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
940 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
941 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
942 // Resilience is on for spatial layers.
943 EXPECT_TRUE(fake_encoder_.codec_config().VP9()->resilienceOn);
944 video_stream_encoder_->Stop();
945}
946
947TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOnFor1SL2TLWithNackEnabled) {
948 const bool kNackEnabled = true;
949 const size_t kNumStreams = 1;
950 const size_t kNumTl = 2;
951 const unsigned char kNumSl = 1;
952 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
953 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
954
955 // Capture a frame and wait for it to synchronize with the encoder thread.
956 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
957 sink_.WaitForEncodedFrame(1);
958 // The encoder have been configured once when the first frame is received.
959 EXPECT_EQ(1, sink_.number_of_reconfigurations());
960 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
961 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
962 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
963 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
964 // Resilience is on for temporal layers.
965 EXPECT_TRUE(fake_encoder_.codec_config().VP9()->resilienceOn);
966 video_stream_encoder_->Stop();
967}
968
mflodmancc3d4422017-08-03 08:27:51 -0700969TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -0700970 EXPECT_TRUE(video_source_.has_sinks());
971 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700972 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -0700973 &new_video_source,
974 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -0700975 EXPECT_FALSE(video_source_.has_sinks());
976 EXPECT_TRUE(new_video_source.has_sinks());
977
mflodmancc3d4422017-08-03 08:27:51 -0700978 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700979}
980
mflodmancc3d4422017-08-03 08:27:51 -0700981TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -0700982 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700983 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -0700984 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700985 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700986}
987
mflodmancc3d4422017-08-03 08:27:51 -0700988TEST_F(VideoStreamEncoderTest, SinkWantsFromOveruseDetector) {
989 const int kMaxDowngrades = VideoStreamEncoder::kMaxCpuResolutionDowngrades;
990 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -0700991
asapersson02465b82017-04-10 01:12:52 -0700992 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700993
994 int frame_width = 1280;
995 int frame_height = 720;
996
mflodmancc3d4422017-08-03 08:27:51 -0700997 // Trigger CPU overuse kMaxCpuDowngrades times. Every time, VideoStreamEncoder
998 // should request lower resolution.
asaperssond0de2952017-04-21 01:47:31 -0700999 for (int i = 1; i <= kMaxDowngrades; ++i) {
perkj803d97f2016-11-01 11:45:46 -07001000 video_source_.IncomingCapturedFrame(
1001 CreateFrame(i, frame_width, frame_height));
sprang4847ae62017-06-27 07:06:52 -07001002 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07001003
mflodmancc3d4422017-08-03 08:27:51 -07001004 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001005
sprang84a37592017-02-10 07:04:27 -08001006 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001007 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
perkj803d97f2016-11-01 11:45:46 -07001008 frame_width * frame_height);
asaperssond0de2952017-04-21 01:47:31 -07001009 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1010 EXPECT_EQ(i, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001011
1012 frame_width /= 2;
1013 frame_height /= 2;
1014 }
1015
kthelgason876222f2016-11-29 01:44:11 -08001016 // Trigger CPU overuse one more time. This should not trigger a request for
perkj803d97f2016-11-01 11:45:46 -07001017 // lower resolution.
1018 rtc::VideoSinkWants current_wants = video_source_.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07001019 video_source_.IncomingCapturedFrame(
1020 CreateFrame(kMaxDowngrades + 1, frame_width, frame_height));
sprang4847ae62017-06-27 07:06:52 -07001021 WaitForEncodedFrame(kMaxDowngrades + 1);
mflodmancc3d4422017-08-03 08:27:51 -07001022 video_stream_encoder_->TriggerCpuOveruse();
sprang84a37592017-02-10 07:04:27 -08001023 EXPECT_EQ(video_source_.sink_wants().target_pixel_count,
1024 current_wants.target_pixel_count);
perkj803d97f2016-11-01 11:45:46 -07001025 EXPECT_EQ(video_source_.sink_wants().max_pixel_count,
1026 current_wants.max_pixel_count);
asaperssond0de2952017-04-21 01:47:31 -07001027 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1028 EXPECT_EQ(kMaxDowngrades,
1029 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001030
1031 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001032 video_stream_encoder_->TriggerCpuNormalUsage();
sprang84a37592017-02-10 07:04:27 -08001033 EXPECT_EQ(frame_width * frame_height * 5 / 3,
1034 video_source_.sink_wants().target_pixel_count.value_or(0));
1035 EXPECT_EQ(frame_width * frame_height * 4,
sprangc5d62e22017-04-02 23:53:04 -07001036 video_source_.sink_wants().max_pixel_count);
asaperssond0de2952017-04-21 01:47:31 -07001037 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1038 EXPECT_EQ(kMaxDowngrades + 1,
1039 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001040
mflodmancc3d4422017-08-03 08:27:51 -07001041 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001042}
1043
mflodmancc3d4422017-08-03 08:27:51 -07001044TEST_F(VideoStreamEncoderTest,
1045 TestMaxCpuResolutionDowngrades_BalancedMode_NoFpsLimit) {
1046 const int kMaxDowngrades = VideoStreamEncoder::kMaxCpuResolutionDowngrades;
asaperssonf7e294d2017-06-13 23:25:22 -07001047 const int kWidth = 1280;
1048 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001049 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001050
1051 // Enable kBalanced preference, no initial limitation.
1052 AdaptingFrameForwarder source;
1053 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001054 video_stream_encoder_->SetSource(
1055 &source,
1056 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001057 VerifyNoLimitation(source.sink_wants());
1058 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1059 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1060
1061 // Trigger adapt down kMaxCpuDowngrades times.
1062 int t = 1;
1063 for (int i = 1; i <= kMaxDowngrades; ++i) {
1064 source.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1065 sink_.WaitForEncodedFrame(t++);
mflodmancc3d4422017-08-03 08:27:51 -07001066 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07001067 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
1068 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1069 EXPECT_EQ(i, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1070 }
1071
1072 // Trigger adapt down, max cpu downgrades reach, expect no change.
1073 rtc::VideoSinkWants last_wants = source.sink_wants();
1074 source.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1075 sink_.WaitForEncodedFrame(t++);
mflodmancc3d4422017-08-03 08:27:51 -07001076 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07001077 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
1078 EXPECT_EQ(last_wants.max_pixel_count, source.sink_wants().max_pixel_count);
1079 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1080 EXPECT_EQ(kMaxDowngrades,
1081 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1082
1083 // Trigger adapt up kMaxCpuDowngrades times.
1084 for (int i = 1; i <= kMaxDowngrades; ++i) {
1085 source.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1086 sink_.WaitForEncodedFrame(t++);
mflodmancc3d4422017-08-03 08:27:51 -07001087 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07001088 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
1089 EXPECT_GT(source.sink_wants().max_pixel_count, last_wants.max_pixel_count);
1090 EXPECT_EQ(kMaxDowngrades + i,
1091 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1092 }
1093
1094 VerifyNoLimitation(source.sink_wants());
1095 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1096
mflodmancc3d4422017-08-03 08:27:51 -07001097 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001098}
mflodmancc3d4422017-08-03 08:27:51 -07001099TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
1100 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001101 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001102
sprangc5d62e22017-04-02 23:53:04 -07001103 const int kFrameWidth = 1280;
1104 const int kFrameHeight = 720;
1105 const int kFrameIntervalMs = 1000 / 30;
1106
1107 int frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -07001108
kthelgason5e13d412016-12-01 03:59:51 -08001109 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001110 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001111 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001112 frame_timestamp += kFrameIntervalMs;
1113
perkj803d97f2016-11-01 11:45:46 -07001114 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001115 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001116 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001117 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001118 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001119 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -07001120
asapersson0944a802017-04-07 00:57:58 -07001121 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -07001122 // wanted resolution.
1123 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
1124 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
1125 kFrameWidth * kFrameHeight);
1126 EXPECT_EQ(std::numeric_limits<int>::max(),
1127 video_source_.sink_wants().max_framerate_fps);
1128
1129 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -07001130 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001131 video_stream_encoder_->SetSource(
perkj803d97f2016-11-01 11:45:46 -07001132 &new_video_source,
1133 VideoSendStream::DegradationPreference::kMaintainResolution);
1134
sprangc5d62e22017-04-02 23:53:04 -07001135 // Initially no degradation registered.
asapersson02465b82017-04-10 01:12:52 -07001136 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001137
sprangc5d62e22017-04-02 23:53:04 -07001138 // Force an input frame rate to be available, or the adaptation call won't
1139 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -07001140 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -07001141 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -07001142 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -07001143 stats_proxy_->SetMockStats(stats);
1144
mflodmancc3d4422017-08-03 08:27:51 -07001145 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001146 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001147 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001148 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001149 frame_timestamp += kFrameIntervalMs;
1150
1151 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001152 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001153 EXPECT_EQ(std::numeric_limits<int>::max(),
1154 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001155 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001156
asapersson02465b82017-04-10 01:12:52 -07001157 // Turn off degradation completely.
mflodmancc3d4422017-08-03 08:27:51 -07001158 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001159 &new_video_source,
1160 VideoSendStream::DegradationPreference::kDegradationDisabled);
asapersson02465b82017-04-10 01:12:52 -07001161 VerifyNoLimitation(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001162
mflodmancc3d4422017-08-03 08:27:51 -07001163 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001164 new_video_source.IncomingCapturedFrame(
1165 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001166 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001167 frame_timestamp += kFrameIntervalMs;
1168
1169 // Still no degradation.
asapersson02465b82017-04-10 01:12:52 -07001170 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001171
1172 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001173 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001174 &new_video_source,
1175 VideoSendStream::DegradationPreference::kMaintainFramerate);
1176 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1177 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001178 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001179 EXPECT_EQ(std::numeric_limits<int>::max(),
1180 new_video_source.sink_wants().max_framerate_fps);
1181
1182 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001183 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001184 &new_video_source,
1185 VideoSendStream::DegradationPreference::kMaintainResolution);
1186 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1187 EXPECT_EQ(std::numeric_limits<int>::max(),
1188 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001189 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001190
mflodmancc3d4422017-08-03 08:27:51 -07001191 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001192}
1193
mflodmancc3d4422017-08-03 08:27:51 -07001194TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
1195 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001196
asaperssonfab67072017-04-04 05:51:49 -07001197 const int kWidth = 1280;
1198 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001199 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001200 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001201 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1202 EXPECT_FALSE(stats.bw_limited_resolution);
1203 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1204
1205 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001206 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001207 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001208 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001209
1210 stats = stats_proxy_->GetStats();
1211 EXPECT_TRUE(stats.bw_limited_resolution);
1212 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1213
1214 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001215 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001216 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001217 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001218
1219 stats = stats_proxy_->GetStats();
1220 EXPECT_FALSE(stats.bw_limited_resolution);
1221 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1222 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1223
mflodmancc3d4422017-08-03 08:27:51 -07001224 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001225}
1226
mflodmancc3d4422017-08-03 08:27:51 -07001227TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
1228 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001229
1230 const int kWidth = 1280;
1231 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001232 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001233 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001234 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1235 EXPECT_FALSE(stats.cpu_limited_resolution);
1236 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1237
1238 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001239 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001240 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001241 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001242
1243 stats = stats_proxy_->GetStats();
1244 EXPECT_TRUE(stats.cpu_limited_resolution);
1245 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1246
1247 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001248 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001249 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001250 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001251
1252 stats = stats_proxy_->GetStats();
1253 EXPECT_FALSE(stats.cpu_limited_resolution);
1254 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001255 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001256
mflodmancc3d4422017-08-03 08:27:51 -07001257 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001258}
1259
mflodmancc3d4422017-08-03 08:27:51 -07001260TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
1261 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001262
asaperssonfab67072017-04-04 05:51:49 -07001263 const int kWidth = 1280;
1264 const int kHeight = 720;
1265 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001266 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001267 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001268 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001269 EXPECT_FALSE(stats.cpu_limited_resolution);
1270 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1271
asaperssonfab67072017-04-04 05:51:49 -07001272 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001273 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001274 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001275 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001276 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001277 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001278 EXPECT_TRUE(stats.cpu_limited_resolution);
1279 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1280
1281 // Set new source with adaptation still enabled.
1282 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001283 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001284 &new_video_source,
1285 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001286
asaperssonfab67072017-04-04 05:51:49 -07001287 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001288 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001289 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001290 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001291 EXPECT_TRUE(stats.cpu_limited_resolution);
1292 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1293
1294 // Set adaptation disabled.
mflodmancc3d4422017-08-03 08:27:51 -07001295 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001296 &new_video_source,
sprangc5d62e22017-04-02 23:53:04 -07001297 VideoSendStream::DegradationPreference::kDegradationDisabled);
kthelgason876222f2016-11-29 01:44:11 -08001298
asaperssonfab67072017-04-04 05:51:49 -07001299 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001300 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001301 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001302 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001303 EXPECT_FALSE(stats.cpu_limited_resolution);
1304 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1305
1306 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001307 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001308 &new_video_source,
1309 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001310
asaperssonfab67072017-04-04 05:51:49 -07001311 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001312 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001313 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001314 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001315 EXPECT_TRUE(stats.cpu_limited_resolution);
1316 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1317
asaperssonfab67072017-04-04 05:51:49 -07001318 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001319 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001320 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001321 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001322 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001323 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001324 EXPECT_FALSE(stats.cpu_limited_resolution);
1325 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001326 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001327
mflodmancc3d4422017-08-03 08:27:51 -07001328 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001329}
1330
mflodmancc3d4422017-08-03 08:27:51 -07001331TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
1332 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001333
asaperssonfab67072017-04-04 05:51:49 -07001334 const int kWidth = 1280;
1335 const int kHeight = 720;
1336 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001337 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001338 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001339 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001340 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001341 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001342
1343 // Set new source with adaptation still enabled.
1344 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001345 video_stream_encoder_->SetSource(
1346 &new_video_source,
1347 VideoSendStream::DegradationPreference::kBalanced);
kthelgason876222f2016-11-29 01:44:11 -08001348
asaperssonfab67072017-04-04 05:51:49 -07001349 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001350 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001351 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001352 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001353 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001354 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001355
asaperssonfab67072017-04-04 05:51:49 -07001356 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001357 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001358 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001359 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001360 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001361 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001362 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001363 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001364
asaperssonfab67072017-04-04 05:51:49 -07001365 // Set new source with adaptation still enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001366 video_stream_encoder_->SetSource(
1367 &new_video_source,
1368 VideoSendStream::DegradationPreference::kBalanced);
kthelgason876222f2016-11-29 01:44:11 -08001369
asaperssonfab67072017-04-04 05:51:49 -07001370 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001371 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001372 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001373 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001374 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001375 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001376
asapersson02465b82017-04-10 01:12:52 -07001377 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001378 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001379 &new_video_source,
1380 VideoSendStream::DegradationPreference::kMaintainResolution);
1381
asaperssonfab67072017-04-04 05:51:49 -07001382 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001383 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001384 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001385 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001386 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001387 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1388 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001389
mflodmancc3d4422017-08-03 08:27:51 -07001390 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001391}
1392
mflodmancc3d4422017-08-03 08:27:51 -07001393TEST_F(VideoStreamEncoderTest,
1394 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1395 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001396
1397 const int kWidth = 1280;
1398 const int kHeight = 720;
1399 video_source_.set_adaptation_enabled(true);
1400 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001401 WaitForEncodedFrame(1);
asapersson36e9eb42017-03-31 05:29:12 -07001402 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1403 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1404 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1405
1406 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001407 video_stream_encoder_->TriggerQualityLow();
asapersson36e9eb42017-03-31 05:29:12 -07001408 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001409 WaitForEncodedFrame(2);
asapersson36e9eb42017-03-31 05:29:12 -07001410 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1411 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1412 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1413
1414 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001415 video_stream_encoder_->TriggerCpuOveruse();
asapersson36e9eb42017-03-31 05:29:12 -07001416 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001417 WaitForEncodedFrame(3);
asapersson36e9eb42017-03-31 05:29:12 -07001418 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1419 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1420 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1421
1422 // Set source with adaptation still enabled but quality scaler is off.
1423 fake_encoder_.SetQualityScaling(false);
mflodmancc3d4422017-08-03 08:27:51 -07001424 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001425 &video_source_,
1426 VideoSendStream::DegradationPreference::kMaintainFramerate);
asapersson36e9eb42017-03-31 05:29:12 -07001427
1428 video_source_.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001429 WaitForEncodedFrame(4);
asapersson36e9eb42017-03-31 05:29:12 -07001430 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1431 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1432 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1433
mflodmancc3d4422017-08-03 08:27:51 -07001434 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001435}
1436
mflodmancc3d4422017-08-03 08:27:51 -07001437TEST_F(VideoStreamEncoderTest,
1438 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
1439 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001440
asapersson0944a802017-04-07 00:57:58 -07001441 const int kWidth = 1280;
1442 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001443 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001444
asaperssonfab67072017-04-04 05:51:49 -07001445 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001446 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001447 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001448 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001449 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001450 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1451
asapersson02465b82017-04-10 01:12:52 -07001452 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001453 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001454 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001455 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001456 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001457 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001458 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001459 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1460
1461 // Set new source with adaptation still enabled.
1462 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001463 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001464 &new_video_source,
1465 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001466
1467 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001468 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001469 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001470 stats = stats_proxy_->GetStats();
1471 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001472 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001473 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1474
sprangc5d62e22017-04-02 23:53:04 -07001475 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001476 video_stream_encoder_->SetSource(
perkj803d97f2016-11-01 11:45:46 -07001477 &new_video_source,
1478 VideoSendStream::DegradationPreference::kMaintainResolution);
1479 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001480 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001481 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001482 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001483 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001484 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001485 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001486 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1487
sprangc5d62e22017-04-02 23:53:04 -07001488 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001489 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001490 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1491 mock_stats.input_frame_rate = 30;
1492 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001493 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001494 stats_proxy_->ResetMockStats();
1495
1496 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001497 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001498 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001499
1500 // Framerate now adapted.
1501 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001502 EXPECT_FALSE(stats.cpu_limited_resolution);
1503 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001504 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1505
1506 // Disable CPU adaptation.
mflodmancc3d4422017-08-03 08:27:51 -07001507 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001508 &new_video_source,
1509 VideoSendStream::DegradationPreference::kDegradationDisabled);
1510 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001511 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001512 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001513
1514 stats = stats_proxy_->GetStats();
1515 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001516 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001517 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1518
1519 // Try to trigger overuse. Should not succeed.
1520 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001521 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001522 stats_proxy_->ResetMockStats();
1523
1524 stats = stats_proxy_->GetStats();
1525 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001526 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001527 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1528
1529 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001530 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001531 &video_source_,
1532 VideoSendStream::DegradationPreference::kMaintainFramerate);
asaperssonfab67072017-04-04 05:51:49 -07001533 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001534 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001535 stats = stats_proxy_->GetStats();
1536 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001537 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001538 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001539
1540 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001541 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001542 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001543 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001544 stats = stats_proxy_->GetStats();
1545 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001546 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001547 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1548
1549 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001550 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001551 &new_video_source,
1552 VideoSendStream::DegradationPreference::kMaintainResolution);
1553 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001554 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001555 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001556 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001557 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001558 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001559 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001560 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1561
1562 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001563 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001564 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001565 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001566 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001567 stats = stats_proxy_->GetStats();
1568 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001569 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001570 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001571 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001572
mflodmancc3d4422017-08-03 08:27:51 -07001573 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001574}
1575
mflodmancc3d4422017-08-03 08:27:51 -07001576TEST_F(VideoStreamEncoderTest, StatsTracksPreferredBitrate) {
1577 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Erik Språng08127a92016-11-16 16:41:30 +01001578
asaperssonfab67072017-04-04 05:51:49 -07001579 const int kWidth = 1280;
1580 const int kHeight = 720;
1581 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001582 WaitForEncodedFrame(1);
Erik Språng08127a92016-11-16 16:41:30 +01001583
1584 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1585 EXPECT_EQ(video_encoder_config_.max_bitrate_bps,
1586 stats.preferred_media_bitrate_bps);
1587
mflodmancc3d4422017-08-03 08:27:51 -07001588 video_stream_encoder_->Stop();
Erik Språng08127a92016-11-16 16:41:30 +01001589}
1590
mflodmancc3d4422017-08-03 08:27:51 -07001591TEST_F(VideoStreamEncoderTest,
1592 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001593 const int kWidth = 1280;
1594 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001595 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001596
asaperssonfab67072017-04-04 05:51:49 -07001597 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001598 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001599
asaperssonfab67072017-04-04 05:51:49 -07001600 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001601 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001602
asaperssonfab67072017-04-04 05:51:49 -07001603 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001604 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001605
asaperssonfab67072017-04-04 05:51:49 -07001606 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001607 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001608
kthelgason876222f2016-11-29 01:44:11 -08001609 // Expect a scale down.
1610 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001611 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001612
asapersson02465b82017-04-10 01:12:52 -07001613 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001614 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001615 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001616 &new_video_source,
1617 VideoSendStream::DegradationPreference::kMaintainResolution);
1618
asaperssonfab67072017-04-04 05:51:49 -07001619 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001620 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001621 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001622 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001623
asaperssonfab67072017-04-04 05:51:49 -07001624 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001625 EXPECT_EQ(std::numeric_limits<int>::max(),
1626 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001627
asaperssonfab67072017-04-04 05:51:49 -07001628 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001629 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001630 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001631 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001632
asapersson02465b82017-04-10 01:12:52 -07001633 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001634 EXPECT_EQ(std::numeric_limits<int>::max(),
1635 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001636
mflodmancc3d4422017-08-03 08:27:51 -07001637 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001638}
1639
mflodmancc3d4422017-08-03 08:27:51 -07001640TEST_F(VideoStreamEncoderTest,
1641 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001642 const int kWidth = 1280;
1643 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001644 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001645
1646 // Enable kMaintainFramerate preference, no initial limitation.
1647 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001648 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001649 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1650
1651 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001652 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001653 VerifyNoLimitation(source.sink_wants());
1654 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1655 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1656
1657 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001658 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001659 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001660 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1661 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1662 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1663
1664 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001665 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001666 EXPECT_EQ(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
mflodmancc3d4422017-08-03 08:27:51 -07001670 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001671}
1672
mflodmancc3d4422017-08-03 08:27:51 -07001673TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001674 const int kWidth = 1280;
1675 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001676 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001677
1678 // Enable kBalanced preference, no initial limitation.
1679 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001680 video_stream_encoder_->SetSource(
1681 &source,
1682 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001683 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1684 sink_.WaitForEncodedFrame(1);
1685 VerifyNoLimitation(source.sink_wants());
1686
1687 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001688 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001689 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1690 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1691 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1692 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1693
1694 // Trigger adapt down for same input resolution, expect no change.
1695 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1696 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001697 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001698 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1699 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1700 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1701
1702 // Trigger adapt down for larger input resolution, expect no change.
1703 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1704 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001705 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001706 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1707 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1708 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1709
mflodmancc3d4422017-08-03 08:27:51 -07001710 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001711}
1712
mflodmancc3d4422017-08-03 08:27:51 -07001713TEST_F(VideoStreamEncoderTest,
1714 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001715 const int kWidth = 1280;
1716 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001717 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001718
1719 // Enable kMaintainFramerate preference, no initial limitation.
1720 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001721 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001722 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1723
1724 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001725 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001726 VerifyNoLimitation(source.sink_wants());
1727 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1728 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1729
1730 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001731 video_stream_encoder_->TriggerCpuNormalUsage();
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
mflodmancc3d4422017-08-03 08:27:51 -07001736 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001737}
1738
mflodmancc3d4422017-08-03 08:27:51 -07001739TEST_F(VideoStreamEncoderTest,
1740 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001741 const int kWidth = 1280;
1742 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001743 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001744
1745 // Enable kMaintainResolution preference, no initial limitation.
1746 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001747 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001748 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
1749
1750 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001751 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001752 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001753 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001754 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1755
1756 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001757 video_stream_encoder_->TriggerCpuNormalUsage();
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
mflodmancc3d4422017-08-03 08:27:51 -07001762 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001763}
1764
mflodmancc3d4422017-08-03 08:27:51 -07001765TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001766 const int kWidth = 1280;
1767 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001768 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001769
1770 // Enable kBalanced preference, no initial limitation.
1771 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001772 video_stream_encoder_->SetSource(
1773 &source,
1774 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001775
1776 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1777 sink_.WaitForEncodedFrame(kWidth, kHeight);
1778 VerifyNoLimitation(source.sink_wants());
1779 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1780 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1781 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1782
1783 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001784 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001785 VerifyNoLimitation(source.sink_wants());
1786 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1787 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1788 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1789
mflodmancc3d4422017-08-03 08:27:51 -07001790 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001791}
1792
mflodmancc3d4422017-08-03 08:27:51 -07001793TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001794 const int kWidth = 1280;
1795 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001796 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001797
1798 // Enable kDegradationDisabled preference, no initial limitation.
1799 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001800 video_stream_encoder_->SetSource(
asapersson09f05612017-05-15 23:40:18 -07001801 &source, VideoSendStream::DegradationPreference::kDegradationDisabled);
1802
1803 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1804 sink_.WaitForEncodedFrame(kWidth, kHeight);
1805 VerifyNoLimitation(source.sink_wants());
1806 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1807 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1808 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1809
1810 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001811 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001812 VerifyNoLimitation(source.sink_wants());
1813 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1814 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1815 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1816
mflodmancc3d4422017-08-03 08:27:51 -07001817 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001818}
1819
mflodmancc3d4422017-08-03 08:27:51 -07001820TEST_F(VideoStreamEncoderTest,
1821 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001822 const int kWidth = 1280;
1823 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001824 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001825
1826 // Enable kMaintainFramerate preference, no initial limitation.
1827 AdaptingFrameForwarder source;
1828 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001829 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001830 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1831
1832 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001833 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001834 VerifyNoLimitation(source.sink_wants());
1835 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1836 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1837
1838 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001839 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001840 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001841 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001842 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001843 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1844 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1845
1846 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001847 video_stream_encoder_->TriggerQualityHigh();
asapersson02465b82017-04-10 01:12:52 -07001848 VerifyNoLimitation(source.sink_wants());
1849 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1850 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1851 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1852
mflodmancc3d4422017-08-03 08:27:51 -07001853 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001854}
1855
mflodmancc3d4422017-08-03 08:27:51 -07001856TEST_F(VideoStreamEncoderTest,
1857 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001858 const int kWidth = 1280;
1859 const int kHeight = 720;
1860 const int kInputFps = 30;
mflodmancc3d4422017-08-03 08:27:51 -07001861 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001862
1863 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1864 stats.input_frame_rate = kInputFps;
1865 stats_proxy_->SetMockStats(stats);
1866
1867 // Expect no scaling to begin with (preference: kMaintainFramerate).
1868 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1869 sink_.WaitForEncodedFrame(1);
1870 VerifyNoLimitation(video_source_.sink_wants());
1871
1872 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001873 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001874 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1875 sink_.WaitForEncodedFrame(2);
1876 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1877
1878 // Enable kMaintainResolution preference.
1879 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001880 video_stream_encoder_->SetSource(
asapersson09f05612017-05-15 23:40:18 -07001881 &new_video_source,
1882 VideoSendStream::DegradationPreference::kMaintainResolution);
1883 VerifyNoLimitation(new_video_source.sink_wants());
1884
1885 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001886 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001887 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1888 sink_.WaitForEncodedFrame(3);
1889 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1890
1891 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001892 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001893 VerifyNoLimitation(new_video_source.sink_wants());
1894
mflodmancc3d4422017-08-03 08:27:51 -07001895 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001896}
1897
mflodmancc3d4422017-08-03 08:27:51 -07001898TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001899 const int kWidth = 1280;
1900 const int kHeight = 720;
1901 const size_t kNumFrames = 10;
1902
mflodmancc3d4422017-08-03 08:27:51 -07001903 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001904
asaperssond0de2952017-04-21 01:47:31 -07001905 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001906 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001907 video_source_.set_adaptation_enabled(true);
1908
1909 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1910 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1911
1912 int downscales = 0;
1913 for (size_t i = 1; i <= kNumFrames; i++) {
1914 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001915 WaitForEncodedFrame(i);
asaperssond0de2952017-04-21 01:47:31 -07001916
asaperssonfab67072017-04-04 05:51:49 -07001917 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001918 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001919 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001920 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001921
1922 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1923 ++downscales;
1924
1925 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1926 EXPECT_EQ(downscales,
1927 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1928 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001929 }
mflodmancc3d4422017-08-03 08:27:51 -07001930 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001931}
1932
mflodmancc3d4422017-08-03 08:27:51 -07001933TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001934 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1935 const int kWidth = 1280;
1936 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001937 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001938
1939 // Enable kMaintainFramerate preference, no initial limitation.
1940 AdaptingFrameForwarder source;
1941 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001942 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07001943 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1944
1945 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001946 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001947 VerifyNoLimitation(source.sink_wants());
1948 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1949 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1950
1951 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001952 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001953 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001954 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001955 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001956 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1957 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1958
1959 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001960 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07001961 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001962 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001963 VerifyNoLimitation(source.sink_wants());
1964 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1965 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1966
1967 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001968 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001969 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001970 WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07001971 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001972 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1973 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1974
1975 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001976 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson09f05612017-05-15 23:40:18 -07001977 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1978 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001979 VerifyNoLimitation(source.sink_wants());
1980 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1981 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1982
mflodmancc3d4422017-08-03 08:27:51 -07001983 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001984}
1985
mflodmancc3d4422017-08-03 08:27:51 -07001986TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07001987 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
1988 const int kWidth = 1280;
1989 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001990 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001991
1992 // Enable kBalanced preference, no initial limitation.
1993 AdaptingFrameForwarder source;
1994 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001995 video_stream_encoder_->SetSource(
1996 &source,
1997 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001998
1999 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2000 sink_.WaitForEncodedFrame(kWidth, kHeight);
2001 VerifyNoLimitation(source.sink_wants());
2002 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2003 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2004
2005 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002006 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002007 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
2008 sink_.WaitForEncodedFrame(2);
2009 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2010 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2011 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2012
2013 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002014 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002015 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
2016 sink_.WaitForEncodedFrame(kWidth, kHeight);
2017 VerifyNoLimitation(source.sink_wants());
2018 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2019 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2020
2021 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002022 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002023 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
2024 sink_.WaitForEncodedFrame(4);
2025 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2026 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2027 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2028
2029 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002030 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002031 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
2032 sink_.WaitForEncodedFrame(kWidth, kHeight);
2033 VerifyNoLimitation(source.sink_wants());
2034 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2035 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2036
mflodmancc3d4422017-08-03 08:27:51 -07002037 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002038}
2039
mflodmancc3d4422017-08-03 08:27:51 -07002040TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002041 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
2042 const int kWidth = 1280;
2043 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07002044 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002045
2046 // Enable kMaintainFramerate preference, no initial limitation.
2047 AdaptingFrameForwarder source;
2048 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002049 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07002050 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
2051
2052 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002053 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002054 VerifyNoLimitation(source.sink_wants());
2055 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2056 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2057 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2058 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2059
2060 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002061 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002062 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002063 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07002064 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002065 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2066 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2067 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2068 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2069
2070 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07002071 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002072 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002073 WaitForEncodedFrame(3);
asapersson09f05612017-05-15 23:40:18 -07002074 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2075 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07002076 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2077 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2078 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2079 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2080
2081 // Trigger cpu adapt down, max cpu downgrades reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002082 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002083 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002084 WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07002085 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002086 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2087 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2088 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2089 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2090
2091 // Trigger quality adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002092 video_stream_encoder_->TriggerQualityLow();
asaperssond0de2952017-04-21 01:47:31 -07002093 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002094 WaitForEncodedFrame(5);
asapersson09f05612017-05-15 23:40:18 -07002095 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002096 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2097 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2098 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2099 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2100
2101 // Trigger cpu adapt up, expect upscaled resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07002102 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07002103 source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002104 WaitForEncodedFrame(6);
asapersson09f05612017-05-15 23:40:18 -07002105 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002106 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2107 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2108 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2109 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2110
2111 // Trigger cpu adapt up, expect upscaled resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002112 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07002113 source.IncomingCapturedFrame(CreateFrame(7, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002114 WaitForEncodedFrame(7);
asapersson09f05612017-05-15 23:40:18 -07002115 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002116 last_wants = source.sink_wants();
2117 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2118 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2119 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2120 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2121
2122 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002123 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07002124 source.IncomingCapturedFrame(CreateFrame(8, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002125 WaitForEncodedFrame(8);
asapersson09f05612017-05-15 23:40:18 -07002126 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002127 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2128 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2129 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2130 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2131
2132 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002133 video_stream_encoder_->TriggerQualityHigh();
asaperssond0de2952017-04-21 01:47:31 -07002134 source.IncomingCapturedFrame(CreateFrame(9, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002135 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002136 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002137 VerifyNoLimitation(source.sink_wants());
2138 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2139 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2140 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2141 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002142
mflodmancc3d4422017-08-03 08:27:51 -07002143 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002144}
2145
mflodmancc3d4422017-08-03 08:27:51 -07002146TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002147 const int kWidth = 640;
2148 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002149
mflodmancc3d4422017-08-03 08:27:51 -07002150 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002151
perkj803d97f2016-11-01 11:45:46 -07002152 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002153 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002154 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002155 }
2156
mflodmancc3d4422017-08-03 08:27:51 -07002157 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002158 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002159 video_source_.IncomingCapturedFrame(CreateFrame(
2160 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002161 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002162 }
2163
mflodmancc3d4422017-08-03 08:27:51 -07002164 video_stream_encoder_->Stop();
2165 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002166 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002167
perkj803d97f2016-11-01 11:45:46 -07002168 EXPECT_EQ(1,
2169 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2170 EXPECT_EQ(
2171 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2172}
2173
mflodmancc3d4422017-08-03 08:27:51 -07002174TEST_F(VideoStreamEncoderTest,
2175 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2176 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002177 const int kWidth = 640;
2178 const int kHeight = 360;
2179
mflodmancc3d4422017-08-03 08:27:51 -07002180 video_stream_encoder_->SetSource(
asaperssonf4e44af2017-04-19 02:01:06 -07002181 &video_source_,
2182 VideoSendStream::DegradationPreference::kDegradationDisabled);
2183
2184 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2185 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002186 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002187 }
2188
mflodmancc3d4422017-08-03 08:27:51 -07002189 video_stream_encoder_->Stop();
2190 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002191 stats_proxy_.reset();
2192
2193 EXPECT_EQ(0,
2194 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2195}
2196
mflodmancc3d4422017-08-03 08:27:51 -07002197TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002198 MockBitrateObserver bitrate_observer;
mflodmancc3d4422017-08-03 08:27:51 -07002199 video_stream_encoder_->SetBitrateObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002200
2201 const int kDefaultFps = 30;
2202 const BitrateAllocation expected_bitrate =
2203 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002204 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002205
2206 // First called on bitrate updated, then again on first frame.
2207 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2208 .Times(2);
mflodmancc3d4422017-08-03 08:27:51 -07002209 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002210
2211 const int64_t kStartTimeMs = 1;
2212 video_source_.IncomingCapturedFrame(
2213 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002214 WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002215
2216 // Not called on second frame.
2217 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2218 .Times(0);
2219 video_source_.IncomingCapturedFrame(
2220 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002221 WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002222
2223 // Called after a process interval.
2224 const int64_t kProcessIntervalMs =
2225 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang4847ae62017-06-27 07:06:52 -07002226 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec *
2227 (kProcessIntervalMs + (1000 / kDefaultFps)));
sprang57c2fff2017-01-16 06:24:02 -08002228 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2229 .Times(1);
2230 video_source_.IncomingCapturedFrame(CreateFrame(
2231 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002232 WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002233
mflodmancc3d4422017-08-03 08:27:51 -07002234 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002235}
2236
Niels Möller7dc26b72017-12-06 10:27:48 +01002237TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2238 const int kFrameWidth = 1280;
2239 const int kFrameHeight = 720;
2240 const int kFramerate = 24;
2241
2242 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2243 test::FrameForwarder source;
2244 video_stream_encoder_->SetSource(
2245 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2246
2247 // Insert a single frame, triggering initial configuration.
2248 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2249 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2250
2251 EXPECT_EQ(
2252 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2253 kDefaultFramerate);
2254
2255 // Trigger reconfigure encoder (without resetting the entire instance).
2256 VideoEncoderConfig video_encoder_config;
2257 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2258 video_encoder_config.number_of_streams = 1;
2259 video_encoder_config.video_stream_factory =
2260 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2261 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2262 kMaxPayloadLength, false);
2263 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2264
2265 // Detector should be updated with fps limit from codec config.
2266 EXPECT_EQ(
2267 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2268 kFramerate);
2269
2270 // Trigger overuse, max framerate should be reduced.
2271 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2272 stats.input_frame_rate = kFramerate;
2273 stats_proxy_->SetMockStats(stats);
2274 video_stream_encoder_->TriggerCpuOveruse();
2275 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2276 int adapted_framerate =
2277 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2278 EXPECT_LT(adapted_framerate, kFramerate);
2279
2280 // Trigger underuse, max framerate should go back to codec configured fps.
2281 // Set extra low fps, to make sure it's actually reset, not just incremented.
2282 stats = stats_proxy_->GetStats();
2283 stats.input_frame_rate = adapted_framerate / 2;
2284 stats_proxy_->SetMockStats(stats);
2285 video_stream_encoder_->TriggerCpuNormalUsage();
2286 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2287 EXPECT_EQ(
2288 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2289 kFramerate);
2290
2291 video_stream_encoder_->Stop();
2292}
2293
2294TEST_F(VideoStreamEncoderTest,
2295 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2296 const int kFrameWidth = 1280;
2297 const int kFrameHeight = 720;
2298 const int kLowFramerate = 15;
2299 const int kHighFramerate = 25;
2300
2301 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2302 test::FrameForwarder source;
2303 video_stream_encoder_->SetSource(
2304 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2305
2306 // Trigger initial configuration.
2307 VideoEncoderConfig video_encoder_config;
2308 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2309 video_encoder_config.number_of_streams = 1;
2310 video_encoder_config.video_stream_factory =
2311 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2312 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2313 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2314 kMaxPayloadLength, false);
2315 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2316
2317 EXPECT_EQ(
2318 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2319 kLowFramerate);
2320
2321 // Trigger overuse, max framerate should be reduced.
2322 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2323 stats.input_frame_rate = kLowFramerate;
2324 stats_proxy_->SetMockStats(stats);
2325 video_stream_encoder_->TriggerCpuOveruse();
2326 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2327 int adapted_framerate =
2328 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2329 EXPECT_LT(adapted_framerate, kLowFramerate);
2330
2331 // Reconfigure the encoder with a new (higher max framerate), max fps should
2332 // still respect the adaptation.
2333 video_encoder_config.video_stream_factory =
2334 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2335 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2336 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2337 kMaxPayloadLength, false);
2338 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2339
2340 EXPECT_EQ(
2341 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2342 adapted_framerate);
2343
2344 // Trigger underuse, max framerate should go back to codec configured fps.
2345 stats = stats_proxy_->GetStats();
2346 stats.input_frame_rate = adapted_framerate;
2347 stats_proxy_->SetMockStats(stats);
2348 video_stream_encoder_->TriggerCpuNormalUsage();
2349 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2350 EXPECT_EQ(
2351 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2352 kHighFramerate);
2353
2354 video_stream_encoder_->Stop();
2355}
2356
mflodmancc3d4422017-08-03 08:27:51 -07002357TEST_F(VideoStreamEncoderTest,
2358 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002359 const int kFrameWidth = 1280;
2360 const int kFrameHeight = 720;
2361 const int kFramerate = 24;
2362
mflodmancc3d4422017-08-03 08:27:51 -07002363 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002364 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002365 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002366 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2367
2368 // Trigger initial configuration.
2369 VideoEncoderConfig video_encoder_config;
2370 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2371 video_encoder_config.number_of_streams = 1;
2372 video_encoder_config.video_stream_factory =
2373 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2374 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002375 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2376 kMaxPayloadLength, false);
2377 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002378
Niels Möller7dc26b72017-12-06 10:27:48 +01002379 EXPECT_EQ(
2380 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2381 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002382
2383 // Trigger overuse, max framerate should be reduced.
2384 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2385 stats.input_frame_rate = kFramerate;
2386 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002387 video_stream_encoder_->TriggerCpuOveruse();
2388 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002389 int adapted_framerate =
2390 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002391 EXPECT_LT(adapted_framerate, kFramerate);
2392
2393 // Change degradation preference to not enable framerate scaling. Target
2394 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002395 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002396 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07002397 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002398 EXPECT_EQ(
2399 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2400 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002401
mflodmancc3d4422017-08-03 08:27:51 -07002402 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002403}
2404
mflodmancc3d4422017-08-03 08:27:51 -07002405TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002406 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002407 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002408 const int kWidth = 640;
2409 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002410
asaperssonfab67072017-04-04 05:51:49 -07002411 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002412
2413 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002414 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002415
2416 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002417 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002418
sprangc5d62e22017-04-02 23:53:04 -07002419 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002420
asaperssonfab67072017-04-04 05:51:49 -07002421 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002422 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002423 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002424
2425 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002426 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002427
sprangc5d62e22017-04-02 23:53:04 -07002428 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002429
mflodmancc3d4422017-08-03 08:27:51 -07002430 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002431}
2432
mflodmancc3d4422017-08-03 08:27:51 -07002433TEST_F(VideoStreamEncoderTest,
2434 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
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
2440 // We expect the n initial frames to get dropped.
2441 int i;
2442 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002443 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002444 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002445 }
2446 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002447 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002448 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002449
2450 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002451 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002452
mflodmancc3d4422017-08-03 08:27:51 -07002453 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002454}
2455
mflodmancc3d4422017-08-03 08:27:51 -07002456TEST_F(VideoStreamEncoderTest,
2457 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002458 const int kWidth = 640;
2459 const int kHeight = 360;
mflodmancc3d4422017-08-03 08:27:51 -07002460 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002461
2462 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002463 video_stream_encoder_->SetSource(
kthelgason2bc68642017-02-07 07:02:22 -08002464 &video_source_,
2465 VideoSendStream::DegradationPreference::kMaintainResolution);
2466
asaperssonfab67072017-04-04 05:51:49 -07002467 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002468 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002469 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002470
mflodmancc3d4422017-08-03 08:27:51 -07002471 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002472}
2473
mflodmancc3d4422017-08-03 08:27:51 -07002474TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002475 const int kWidth = 640;
2476 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002477 fake_encoder_.SetQualityScaling(false);
mflodmancc3d4422017-08-03 08:27:51 -07002478 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002479
kthelgasonb83797b2017-02-14 11:57:25 -08002480 // Force quality scaler reconfiguration by resetting the source.
mflodmancc3d4422017-08-03 08:27:51 -07002481 video_stream_encoder_->SetSource(
2482 &video_source_,
2483 VideoSendStream::DegradationPreference::kBalanced);
kthelgasonad9010c2017-02-14 00:46:51 -08002484
asaperssonfab67072017-04-04 05:51:49 -07002485 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002486 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002487 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002488
mflodmancc3d4422017-08-03 08:27:51 -07002489 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002490 fake_encoder_.SetQualityScaling(true);
2491}
2492
mflodmancc3d4422017-08-03 08:27:51 -07002493TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002494 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2495 const int kTooSmallWidth = 10;
2496 const int kTooSmallHeight = 10;
mflodmancc3d4422017-08-03 08:27:51 -07002497 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002498
2499 // Enable kMaintainFramerate preference, no initial limitation.
2500 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002501 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07002502 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
2503 VerifyNoLimitation(source.sink_wants());
2504 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2505
2506 // Trigger adapt down, too small frame, expect no change.
2507 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002508 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002509 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002510 VerifyNoLimitation(source.sink_wants());
2511 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2512 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2513
mflodmancc3d4422017-08-03 08:27:51 -07002514 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002515}
2516
mflodmancc3d4422017-08-03 08:27:51 -07002517TEST_F(VideoStreamEncoderTest,
2518 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002519 const int kTooSmallWidth = 10;
2520 const int kTooSmallHeight = 10;
2521 const int kFpsLimit = 7;
mflodmancc3d4422017-08-03 08:27:51 -07002522 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002523
2524 // Enable kBalanced preference, no initial limitation.
2525 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002526 video_stream_encoder_->SetSource(
2527 &source,
2528 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002529 VerifyNoLimitation(source.sink_wants());
2530 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2531 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2532
2533 // Trigger adapt down, expect limited framerate.
2534 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002535 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002536 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002537 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2538 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2539 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2540 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2541
2542 // Trigger adapt down, too small frame, expect no change.
2543 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002544 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002545 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002546 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2547 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2548 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2549 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2550
mflodmancc3d4422017-08-03 08:27:51 -07002551 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002552}
2553
mflodmancc3d4422017-08-03 08:27:51 -07002554TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002555 fake_encoder_.ForceInitEncodeFailure(true);
mflodmancc3d4422017-08-03 08:27:51 -07002556 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
emircanbbcc3562017-08-18 00:28:40 -07002557 ResetEncoder("VP8", 2, 1, 1, true, false);
asapersson02465b82017-04-10 01:12:52 -07002558 const int kFrameWidth = 1280;
2559 const int kFrameHeight = 720;
2560 video_source_.IncomingCapturedFrame(
2561 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002562 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002563 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002564}
2565
sprangb1ca0732017-02-01 08:38:12 -08002566// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002567TEST_F(VideoStreamEncoderTest,
2568 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
2569 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002570
2571 const int kFrameWidth = 1280;
2572 const int kFrameHeight = 720;
2573 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002574 // requested by
2575 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002576 video_source_.set_adaptation_enabled(true);
2577
2578 video_source_.IncomingCapturedFrame(
2579 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002580 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002581
2582 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002583 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002584 video_source_.IncomingCapturedFrame(
2585 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002586 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002587
asaperssonfab67072017-04-04 05:51:49 -07002588 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002589 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002590 video_source_.IncomingCapturedFrame(
2591 CreateFrame(3, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002592 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002593
mflodmancc3d4422017-08-03 08:27:51 -07002594 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002595}
sprangfe627f32017-03-29 08:24:59 -07002596
mflodmancc3d4422017-08-03 08:27:51 -07002597TEST_F(VideoStreamEncoderTest,
2598 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002599 const int kFrameWidth = 1280;
2600 const int kFrameHeight = 720;
sprang4847ae62017-06-27 07:06:52 -07002601 int kFrameIntervalMs = rtc::kNumMillisecsPerSec / max_framerate_;
sprangc5d62e22017-04-02 23:53:04 -07002602
mflodmancc3d4422017-08-03 08:27:51 -07002603 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2604 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07002605 &video_source_,
2606 VideoSendStream::DegradationPreference::kMaintainResolution);
2607 video_source_.set_adaptation_enabled(true);
2608
sprang4847ae62017-06-27 07:06:52 -07002609 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002610
2611 video_source_.IncomingCapturedFrame(
2612 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002613 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002614
2615 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002616 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002617
2618 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002619 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002620 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002621 video_source_.IncomingCapturedFrame(
2622 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002623 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002624 }
2625
2626 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002627 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002628 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002629 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002630 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002631 video_source_.IncomingCapturedFrame(
2632 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002633 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002634 ++num_frames_dropped;
2635 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002636 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002637 }
2638 }
2639
sprang4847ae62017-06-27 07:06:52 -07002640 // Add some slack to account for frames dropped by the frame dropper.
2641 const int kErrorMargin = 1;
2642 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002643 kErrorMargin);
2644
2645 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002646 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002647 num_frames_dropped = 0;
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 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002653 ++num_frames_dropped;
2654 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002655 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002656 }
2657 }
sprang4847ae62017-06-27 07:06:52 -07002658 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002659 kErrorMargin);
2660
2661 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002662 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002663 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002664 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002665 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002666 video_source_.IncomingCapturedFrame(
2667 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002668 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002669 ++num_frames_dropped;
2670 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002671 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002672 }
2673 }
sprang4847ae62017-06-27 07:06:52 -07002674 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002675 kErrorMargin);
2676
2677 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002678 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002679 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002680 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002681 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002682 video_source_.IncomingCapturedFrame(
2683 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002684 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002685 ++num_frames_dropped;
2686 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002687 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002688 }
2689 }
2690 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2691
mflodmancc3d4422017-08-03 08:27:51 -07002692 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002693}
2694
mflodmancc3d4422017-08-03 08:27:51 -07002695TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002696 const int kFramerateFps = 5;
2697 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
2698 const int kMinFpsFrameInterval = rtc::kNumMillisecsPerSec / kMinFramerateFps;
2699 const int kFrameWidth = 1280;
2700 const int kFrameHeight = 720;
2701
sprang4847ae62017-06-27 07:06:52 -07002702 // Reconfigure encoder with two temporal layers and screensharing, which will
2703 // disable frame dropping and make testing easier.
emircanbbcc3562017-08-18 00:28:40 -07002704 ResetEncoder("VP8", 1, 2, 1, true, true);
sprang4847ae62017-06-27 07:06:52 -07002705
mflodmancc3d4422017-08-03 08:27:51 -07002706 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2707 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07002708 &video_source_,
2709 VideoSendStream::DegradationPreference::kMaintainResolution);
2710 video_source_.set_adaptation_enabled(true);
2711
sprang4847ae62017-06-27 07:06:52 -07002712 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002713
2714 // Trigger overuse as much as we can.
mflodmancc3d4422017-08-03 08:27:51 -07002715 for (int i = 0; i < VideoStreamEncoder::kMaxCpuResolutionDowngrades; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002716 // Insert frames to get a new fps estimate...
2717 for (int j = 0; j < kFramerateFps; ++j) {
2718 video_source_.IncomingCapturedFrame(
2719 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
2720 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002721 }
2722 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002723 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002724 }
2725
2726 // Drain any frame in the pipeline.
sprang4847ae62017-06-27 07:06:52 -07002727 WaitForFrame(kDefaultTimeoutMs);
sprangc5d62e22017-04-02 23:53:04 -07002728
2729 // Insert frames at min fps, all should go through.
2730 for (int i = 0; i < 10; ++i) {
2731 timestamp_ms += kMinFpsFrameInterval;
sprangc5d62e22017-04-02 23:53:04 -07002732 video_source_.IncomingCapturedFrame(
2733 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002734 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002735 }
asaperssonf7e294d2017-06-13 23:25:22 -07002736
mflodmancc3d4422017-08-03 08:27:51 -07002737 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002738}
asaperssonf7e294d2017-06-13 23:25:22 -07002739
mflodmancc3d4422017-08-03 08:27:51 -07002740TEST_F(VideoStreamEncoderTest,
2741 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002742 const int kWidth = 1280;
2743 const int kHeight = 720;
2744 const int64_t kFrameIntervalMs = 150;
2745 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002746 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002747
2748 // Enable kBalanced preference, no initial limitation.
2749 AdaptingFrameForwarder source;
2750 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002751 video_stream_encoder_->SetSource(
2752 &source,
2753 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002754 timestamp_ms += kFrameIntervalMs;
2755 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002756 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002757 VerifyNoLimitation(source.sink_wants());
2758 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2759 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2760 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2761
2762 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002763 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002764 timestamp_ms += kFrameIntervalMs;
2765 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002766 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002767 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2768 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2769 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2770 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2771
2772 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002773 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002774 timestamp_ms += kFrameIntervalMs;
2775 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002776 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002777 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2778 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2779 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2780 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2781
2782 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002783 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002784 timestamp_ms += kFrameIntervalMs;
2785 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002786 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002787 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2788 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2789 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2790 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2791
2792 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002793 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002794 timestamp_ms += kFrameIntervalMs;
2795 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002796 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002797 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2798 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2799 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2800 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2801
2802 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002803 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002804 timestamp_ms += kFrameIntervalMs;
2805 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002806 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002807 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2808 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2809 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2810 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2811
2812 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002813 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002814 timestamp_ms += kFrameIntervalMs;
2815 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002816 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002817 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2818 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2819 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2820 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2821
2822 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002823 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002824 timestamp_ms += kFrameIntervalMs;
2825 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002826 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002827 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2828 rtc::VideoSinkWants last_wants = source.sink_wants();
2829 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2830 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2831 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2832
2833 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002834 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002835 timestamp_ms += kFrameIntervalMs;
2836 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002837 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002838 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2839 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2840 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2841 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2842
2843 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002844 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002845 timestamp_ms += kFrameIntervalMs;
2846 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002847 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002848 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2849 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2850 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2851 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2852
2853 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002854 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002855 timestamp_ms += kFrameIntervalMs;
2856 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002857 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002858 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2859 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2860 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2861 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2862
2863 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002864 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002865 timestamp_ms += kFrameIntervalMs;
2866 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002867 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002868 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2869 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2870 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2871 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2872
2873 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002874 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002875 timestamp_ms += kFrameIntervalMs;
2876 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002877 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002878 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2879 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2880 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2881 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2882
2883 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002884 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002885 timestamp_ms += kFrameIntervalMs;
2886 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002887 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002888 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2889 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2890 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2891 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2892
2893 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002894 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002895 timestamp_ms += kFrameIntervalMs;
2896 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002897 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002898 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2899 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2900 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2901 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2902
2903 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002904 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002905 timestamp_ms += kFrameIntervalMs;
2906 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002907 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002908 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2909 VerifyNoLimitation(source.sink_wants());
2910 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2911 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2912 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2913
2914 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002915 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002916 VerifyNoLimitation(source.sink_wants());
2917 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2918
mflodmancc3d4422017-08-03 08:27:51 -07002919 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002920}
2921
mflodmancc3d4422017-08-03 08:27:51 -07002922TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07002923 const int kWidth = 1280;
2924 const int kHeight = 720;
2925 const int64_t kFrameIntervalMs = 150;
2926 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002927 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002928
2929 // Enable kBalanced preference, no initial limitation.
2930 AdaptingFrameForwarder source;
2931 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002932 video_stream_encoder_->SetSource(
2933 &source,
2934 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002935 timestamp_ms += kFrameIntervalMs;
2936 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002937 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002938 VerifyNoLimitation(source.sink_wants());
2939 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2940 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2941 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2942 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2943 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2944 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2945
2946 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002947 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002948 timestamp_ms += kFrameIntervalMs;
2949 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002950 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002951 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2952 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2953 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2954 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2955 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2956 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2957 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2958
2959 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002960 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002961 timestamp_ms += kFrameIntervalMs;
2962 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002963 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002964 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2965 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2966 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2967 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2968 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2969 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2970 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2971
2972 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002973 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002974 timestamp_ms += kFrameIntervalMs;
2975 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002976 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002977 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2978 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2979 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2980 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2981 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2982 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2983 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2984
2985 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002986 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002987 timestamp_ms += kFrameIntervalMs;
2988 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002989 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002990 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2991 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2992 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2993 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2994 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2995 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2996 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2997
2998 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002999 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003000 timestamp_ms += kFrameIntervalMs;
3001 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003002 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003003 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3004 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3005 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3006 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3007 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3008 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3009 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3010
3011 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003012 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003013 timestamp_ms += kFrameIntervalMs;
3014 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003015 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003016 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3017 VerifyNoLimitation(source.sink_wants());
3018 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3019 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3020 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3021 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3022 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3023 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3024
3025 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003026 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003027 VerifyNoLimitation(source.sink_wants());
3028 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3029 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3030
mflodmancc3d4422017-08-03 08:27:51 -07003031 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003032}
3033
mflodmancc3d4422017-08-03 08:27:51 -07003034TEST_F(VideoStreamEncoderTest,
3035 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07003036 const int kWidth = 640;
3037 const int kHeight = 360;
3038 const int kFpsLimit = 15;
3039 const int64_t kFrameIntervalMs = 150;
3040 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07003041 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07003042
3043 // Enable kBalanced preference, no initial limitation.
3044 AdaptingFrameForwarder source;
3045 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07003046 video_stream_encoder_->SetSource(
3047 &source,
3048 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07003049 timestamp_ms += kFrameIntervalMs;
3050 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003051 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003052 VerifyNoLimitation(source.sink_wants());
3053 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3054 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3055 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3056 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3057 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3058 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3059
3060 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003061 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003062 timestamp_ms += kFrameIntervalMs;
3063 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003064 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003065 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
3066 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3067 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3068 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3069 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3070 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3071 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3072
3073 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003074 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003075 timestamp_ms += kFrameIntervalMs;
3076 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003077 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003078 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
3079 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3080 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3081 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3082 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3083 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3084 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3085
3086 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003087 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003088 timestamp_ms += kFrameIntervalMs;
3089 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003090 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003091 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3092 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3093 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3094 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3095 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3096 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3097 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3098
3099 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003100 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003101 timestamp_ms += kFrameIntervalMs;
3102 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003103 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003104 VerifyNoLimitation(source.sink_wants());
3105 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3106 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3107 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3108 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3109 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3110 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3111
3112 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003113 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003114 VerifyNoLimitation(source.sink_wants());
3115 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3116 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3117
mflodmancc3d4422017-08-03 08:27:51 -07003118 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003119}
3120
mflodmancc3d4422017-08-03 08:27:51 -07003121TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003122 // Simulates simulcast behavior and makes highest stream resolutions divisible
3123 // by 4.
3124 class CroppingVideoStreamFactory
3125 : public VideoEncoderConfig::VideoStreamFactoryInterface {
3126 public:
3127 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
3128 int framerate)
3129 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
3130 EXPECT_GT(num_temporal_layers, 0u);
3131 EXPECT_GT(framerate, 0);
3132 }
3133
3134 private:
3135 std::vector<VideoStream> CreateEncoderStreams(
3136 int width,
3137 int height,
3138 const VideoEncoderConfig& encoder_config) override {
3139 std::vector<VideoStream> streams =
3140 test::CreateVideoStreams(width - width % 4, height - height % 4,
3141 encoder_config);
3142 for (VideoStream& stream : streams) {
3143 stream.temporal_layer_thresholds_bps.resize(num_temporal_layers_ - 1);
3144 stream.max_framerate = framerate_;
3145 }
3146 return streams;
3147 }
3148
3149 const size_t num_temporal_layers_;
3150 const int framerate_;
3151 };
3152
3153 const int kFrameWidth = 1920;
3154 const int kFrameHeight = 1080;
3155 // 3/4 of 1920.
3156 const int kAdaptedFrameWidth = 1440;
3157 // 3/4 of 1080 rounded down to multiple of 4.
3158 const int kAdaptedFrameHeight = 808;
3159 const int kFramerate = 24;
3160
mflodmancc3d4422017-08-03 08:27:51 -07003161 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003162 // Trigger reconfigure encoder (without resetting the entire instance).
3163 VideoEncoderConfig video_encoder_config;
3164 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3165 video_encoder_config.number_of_streams = 1;
3166 video_encoder_config.video_stream_factory =
3167 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003168 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
3169 kMaxPayloadLength, false);
3170 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003171
3172 video_source_.set_adaptation_enabled(true);
3173
3174 video_source_.IncomingCapturedFrame(
3175 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003176 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003177
3178 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003179 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003180 video_source_.IncomingCapturedFrame(
3181 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003182 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003183
mflodmancc3d4422017-08-03 08:27:51 -07003184 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003185}
3186
mflodmancc3d4422017-08-03 08:27:51 -07003187TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003188 const int kFrameWidth = 1280;
3189 const int kFrameHeight = 720;
3190 const int kLowFps = 2;
3191 const int kHighFps = 30;
3192
mflodmancc3d4422017-08-03 08:27:51 -07003193 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003194
3195 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3196 max_framerate_ = kLowFps;
3197
3198 // Insert 2 seconds of 2fps video.
3199 for (int i = 0; i < kLowFps * 2; ++i) {
3200 video_source_.IncomingCapturedFrame(
3201 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3202 WaitForEncodedFrame(timestamp_ms);
3203 timestamp_ms += 1000 / kLowFps;
3204 }
3205
3206 // Make sure encoder is updated with new target.
mflodmancc3d4422017-08-03 08:27:51 -07003207 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003208 video_source_.IncomingCapturedFrame(
3209 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3210 WaitForEncodedFrame(timestamp_ms);
3211 timestamp_ms += 1000 / kLowFps;
3212
3213 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3214
3215 // Insert 30fps frames for just a little more than the forced update period.
3216 const int kVcmTimerIntervalFrames =
3217 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3218 const int kFrameIntervalMs = 1000 / kHighFps;
3219 max_framerate_ = kHighFps;
3220 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3221 video_source_.IncomingCapturedFrame(
3222 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3223 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3224 // be dropped if the encoder hans't been updated with the new higher target
3225 // framerate yet, causing it to overshoot the target bitrate and then
3226 // suffering the wrath of the media optimizer.
3227 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3228 timestamp_ms += kFrameIntervalMs;
3229 }
3230
3231 // Don expect correct measurement just yet, but it should be higher than
3232 // before.
3233 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3234
mflodmancc3d4422017-08-03 08:27:51 -07003235 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003236}
3237
mflodmancc3d4422017-08-03 08:27:51 -07003238TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003239 const int kFrameWidth = 1280;
3240 const int kFrameHeight = 720;
3241 const int kTargetBitrateBps = 1000000;
3242
3243 MockBitrateObserver bitrate_observer;
mflodmancc3d4422017-08-03 08:27:51 -07003244 video_stream_encoder_->SetBitrateObserver(&bitrate_observer);
sprang4847ae62017-06-27 07:06:52 -07003245
3246 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3247 // Initial bitrate update.
mflodmancc3d4422017-08-03 08:27:51 -07003248 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3249 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003250
3251 // Insert a first video frame, causes another bitrate update.
3252 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3253 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3254 video_source_.IncomingCapturedFrame(
3255 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3256 WaitForEncodedFrame(timestamp_ms);
3257
3258 // Next, simulate video suspension due to pacer queue overrun.
mflodmancc3d4422017-08-03 08:27:51 -07003259 video_stream_encoder_->OnBitrateUpdated(0, 0, 1);
sprang4847ae62017-06-27 07:06:52 -07003260
3261 // Skip ahead until a new periodic parameter update should have occured.
3262 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3263 fake_clock_.AdvanceTimeMicros(
3264 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3265 rtc::kNumMicrosecsPerMillisec);
3266
3267 // Bitrate observer should not be called.
3268 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3269 video_source_.IncomingCapturedFrame(
3270 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3271 ExpectDroppedFrame();
3272
mflodmancc3d4422017-08-03 08:27:51 -07003273 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003274}
ilnik6b826ef2017-06-16 06:53:48 -07003275
perkj26091b12016-09-01 01:17:40 -07003276} // namespace webrtc