blob: 5afbe27d2b78488f76915370428cbbcf861b30e2 [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
sprangfda496a2017-06-15 04:21:07 -070066class CpuOveruseDetectorProxy : public OveruseFrameDetector {
67 public:
68 CpuOveruseDetectorProxy(const CpuOveruseOptions& options,
69 AdaptationObserverInterface* overuse_observer,
70 EncodedFrameObserver* encoder_timing_,
71 CpuOveruseMetricsObserver* metrics_observer)
72 : OveruseFrameDetector(options,
73 overuse_observer,
74 encoder_timing_,
75 metrics_observer),
76 last_target_framerate_fps_(-1) {}
77 virtual ~CpuOveruseDetectorProxy() {}
78
79 void OnTargetFramerateUpdated(int framerate_fps) override {
80 rtc::CritScope cs(&lock_);
81 last_target_framerate_fps_ = framerate_fps;
82 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
83 }
84
85 int GetLastTargetFramerate() {
86 rtc::CritScope cs(&lock_);
87 return last_target_framerate_fps_;
88 }
89
90 private:
91 rtc::CriticalSection lock_;
danilchapa37de392017-09-09 04:17:22 -070092 int last_target_framerate_fps_ RTC_GUARDED_BY(lock_);
sprangfda496a2017-06-15 04:21:07 -070093};
94
mflodmancc3d4422017-08-03 08:27:51 -070095class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -070096 public:
mflodmancc3d4422017-08-03 08:27:51 -070097 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
kthelgason876222f2016-11-29 01:44:11 -080098 const VideoSendStream::Config::EncoderSettings& settings)
mflodmancc3d4422017-08-03 08:27:51 -070099 : VideoStreamEncoder(
100 1 /* number_of_cores */,
101 stats_proxy,
102 settings,
103 nullptr /* pre_encode_callback */,
104 nullptr /* encoder_timing */,
105 std::unique_ptr<OveruseFrameDetector>(
106 overuse_detector_proxy_ = new CpuOveruseDetectorProxy(
107 GetCpuOveruseOptions(settings.full_overuse_time),
108 this,
109 nullptr,
110 stats_proxy))) {}
perkj803d97f2016-11-01 11:45:46 -0700111
sprangb1ca0732017-02-01 08:38:12 -0800112 void PostTaskAndWait(bool down, AdaptReason reason) {
perkj803d97f2016-11-01 11:45:46 -0700113 rtc::Event event(false, false);
kthelgason876222f2016-11-29 01:44:11 -0800114 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800115 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700116 event.Set();
117 });
perkj070ba852017-02-16 15:46:27 -0800118 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700119 }
120
kthelgason2fc52542017-03-03 00:24:41 -0800121 // This is used as a synchronisation mechanism, to make sure that the
122 // encoder queue is not blocked before we start sending it frames.
123 void WaitUntilTaskQueueIsIdle() {
124 rtc::Event event(false, false);
125 encoder_queue()->PostTask([&event] {
126 event.Set();
127 });
128 ASSERT_TRUE(event.Wait(5000));
129 }
130
sprangb1ca0732017-02-01 08:38:12 -0800131 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800132
sprangb1ca0732017-02-01 08:38:12 -0800133 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800134
sprangb1ca0732017-02-01 08:38:12 -0800135 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800136
sprangb1ca0732017-02-01 08:38:12 -0800137 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700138
139 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700140};
141
asapersson5f7226f2016-11-25 04:37:00 -0800142class VideoStreamFactory
143 : public VideoEncoderConfig::VideoStreamFactoryInterface {
144 public:
sprangfda496a2017-06-15 04:21:07 -0700145 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
146 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800147 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700148 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800149 }
150
151 private:
152 std::vector<VideoStream> CreateEncoderStreams(
153 int width,
154 int height,
155 const VideoEncoderConfig& encoder_config) override {
156 std::vector<VideoStream> streams =
157 test::CreateVideoStreams(width, height, encoder_config);
158 for (VideoStream& stream : streams) {
159 stream.temporal_layer_thresholds_bps.resize(num_temporal_layers_ - 1);
sprangfda496a2017-06-15 04:21:07 -0700160 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800161 }
162 return streams;
163 }
sprangfda496a2017-06-15 04:21:07 -0700164
asapersson5f7226f2016-11-25 04:37:00 -0800165 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700166 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800167};
168
ilnik6b826ef2017-06-16 06:53:48 -0700169
sprangb1ca0732017-02-01 08:38:12 -0800170class AdaptingFrameForwarder : public test::FrameForwarder {
171 public:
172 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700173 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800174
175 void set_adaptation_enabled(bool enabled) {
176 rtc::CritScope cs(&crit_);
177 adaptation_enabled_ = enabled;
178 }
179
asaperssonfab67072017-04-04 05:51:49 -0700180 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800181 rtc::CritScope cs(&crit_);
182 return adaptation_enabled_;
183 }
184
asapersson09f05612017-05-15 23:40:18 -0700185 rtc::VideoSinkWants last_wants() const {
186 rtc::CritScope cs(&crit_);
187 return last_wants_;
188 }
189
sprangb1ca0732017-02-01 08:38:12 -0800190 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
191 int cropped_width = 0;
192 int cropped_height = 0;
193 int out_width = 0;
194 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700195 if (adaption_enabled()) {
196 if (adapter_.AdaptFrameResolution(
197 video_frame.width(), video_frame.height(),
198 video_frame.timestamp_us() * 1000, &cropped_width,
199 &cropped_height, &out_width, &out_height)) {
200 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
201 nullptr, out_width, out_height),
202 99, 99, kVideoRotation_0);
203 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
204 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
205 }
sprangb1ca0732017-02-01 08:38:12 -0800206 } else {
207 test::FrameForwarder::IncomingCapturedFrame(video_frame);
208 }
209 }
210
211 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
212 const rtc::VideoSinkWants& wants) override {
213 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700214 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700215 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
216 wants.max_pixel_count,
217 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800218 test::FrameForwarder::AddOrUpdateSink(sink, wants);
219 }
sprangb1ca0732017-02-01 08:38:12 -0800220 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700221 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
222 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
sprangb1ca0732017-02-01 08:38:12 -0800223};
sprangc5d62e22017-04-02 23:53:04 -0700224
225class MockableSendStatisticsProxy : public SendStatisticsProxy {
226 public:
227 MockableSendStatisticsProxy(Clock* clock,
228 const VideoSendStream::Config& config,
229 VideoEncoderConfig::ContentType content_type)
230 : SendStatisticsProxy(clock, config, content_type) {}
231
232 VideoSendStream::Stats GetStats() override {
233 rtc::CritScope cs(&lock_);
234 if (mock_stats_)
235 return *mock_stats_;
236 return SendStatisticsProxy::GetStats();
237 }
238
239 void SetMockStats(const VideoSendStream::Stats& stats) {
240 rtc::CritScope cs(&lock_);
241 mock_stats_.emplace(stats);
242 }
243
244 void ResetMockStats() {
245 rtc::CritScope cs(&lock_);
246 mock_stats_.reset();
247 }
248
249 private:
250 rtc::CriticalSection lock_;
danilchapa37de392017-09-09 04:17:22 -0700251 rtc::Optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700252};
253
sprang4847ae62017-06-27 07:06:52 -0700254class MockBitrateObserver : public VideoBitrateAllocationObserver {
255 public:
256 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const BitrateAllocation&));
257};
258
perkj803d97f2016-11-01 11:45:46 -0700259} // namespace
260
mflodmancc3d4422017-08-03 08:27:51 -0700261class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700262 public:
263 static const int kDefaultTimeoutMs = 30 * 1000;
264
mflodmancc3d4422017-08-03 08:27:51 -0700265 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700266 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700267 codec_width_(320),
268 codec_height_(240),
sprang4847ae62017-06-27 07:06:52 -0700269 max_framerate_(30),
perkj26091b12016-09-01 01:17:40 -0700270 fake_encoder_(),
sprangc5d62e22017-04-02 23:53:04 -0700271 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700272 Clock::GetRealTimeClock(),
273 video_send_config_,
274 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700275 sink_(&fake_encoder_) {}
276
277 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700278 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700279 video_send_config_ = VideoSendStream::Config(nullptr);
280 video_send_config_.encoder_settings.encoder = &fake_encoder_;
281 video_send_config_.encoder_settings.payload_name = "FAKE";
282 video_send_config_.encoder_settings.payload_type = 125;
283
Per512ecb32016-09-23 15:52:06 +0200284 VideoEncoderConfig video_encoder_config;
perkjfa10b552016-10-02 23:45:26 -0700285 test::FillEncoderConfiguration(1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700286 video_encoder_config.video_stream_factory =
287 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100288 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700289
290 // Framerate limit is specified by the VideoStreamFactory.
291 std::vector<VideoStream> streams =
292 video_encoder_config.video_stream_factory->CreateEncoderStreams(
293 codec_width_, codec_height_, video_encoder_config);
294 max_framerate_ = streams[0].max_framerate;
295 fake_clock_.SetTimeMicros(1234);
296
asapersson5f7226f2016-11-25 04:37:00 -0800297 ConfigureEncoder(std::move(video_encoder_config), true /* nack_enabled */);
298 }
299
300 void ConfigureEncoder(VideoEncoderConfig video_encoder_config,
301 bool nack_enabled) {
mflodmancc3d4422017-08-03 08:27:51 -0700302 if (video_stream_encoder_)
303 video_stream_encoder_->Stop();
304 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700305 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700306 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
307 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -0700308 &video_source_,
309 VideoSendStream::DegradationPreference::kMaintainFramerate);
mflodmancc3d4422017-08-03 08:27:51 -0700310 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
311 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
312 kMaxPayloadLength, nack_enabled);
313 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800314 }
315
316 void ResetEncoder(const std::string& payload_name,
317 size_t num_streams,
318 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700319 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700320 bool nack_enabled,
321 bool screenshare) {
asapersson5f7226f2016-11-25 04:37:00 -0800322 video_send_config_.encoder_settings.payload_name = payload_name;
323
324 VideoEncoderConfig video_encoder_config;
325 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800326 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800327 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700328 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
329 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700330 video_encoder_config.content_type =
331 screenshare ? VideoEncoderConfig::ContentType::kScreen
332 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700333 if (payload_name == "VP9") {
334 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
335 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
336 video_encoder_config.encoder_specific_settings =
337 new rtc::RefCountedObject<
338 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
339 }
asapersson5f7226f2016-11-25 04:37:00 -0800340 ConfigureEncoder(std::move(video_encoder_config), nack_enabled);
perkj26091b12016-09-01 01:17:40 -0700341 }
342
sprang57c2fff2017-01-16 06:24:02 -0800343 VideoFrame CreateFrame(int64_t ntp_time_ms,
344 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200345 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
346 destruction_event, codec_width_, codec_height_),
347 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800348 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700349 return frame;
350 }
351
sprang57c2fff2017-01-16 06:24:02 -0800352 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700353 VideoFrame frame(
354 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
355 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800356 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700357 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700358 return frame;
359 }
360
asapersson02465b82017-04-10 01:12:52 -0700361 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700362 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700363 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
364 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700365 }
366
asapersson09f05612017-05-15 23:40:18 -0700367 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
368 const rtc::VideoSinkWants& wants2) {
369 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
370 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
371 }
372
373 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
374 const rtc::VideoSinkWants& wants2) {
375 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
376 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
377 EXPECT_GT(wants1.max_pixel_count, 0);
378 }
379
380 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
381 const rtc::VideoSinkWants& wants2) {
382 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
383 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
384 }
385
asaperssonf7e294d2017-06-13 23:25:22 -0700386 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
387 const rtc::VideoSinkWants& wants2) {
388 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
389 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
390 }
391
392 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
393 const rtc::VideoSinkWants& wants2) {
394 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
395 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
396 }
397
398 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
399 const rtc::VideoSinkWants& wants2) {
400 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
401 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
402 }
403
404 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
405 const rtc::VideoSinkWants& wants2) {
406 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
407 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
408 EXPECT_GT(wants1.max_pixel_count, 0);
409 }
410
411 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
412 const rtc::VideoSinkWants& wants2) {
413 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
414 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
415 }
416
asapersson09f05612017-05-15 23:40:18 -0700417 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
418 int pixel_count) {
419 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700420 EXPECT_LT(wants.max_pixel_count, pixel_count);
421 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700422 }
423
424 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
425 EXPECT_LT(wants.max_framerate_fps, fps);
426 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
427 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700428 }
429
asaperssonf7e294d2017-06-13 23:25:22 -0700430 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
431 int expected_fps) {
432 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
433 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
434 EXPECT_FALSE(wants.target_pixel_count);
435 }
436
sprang4847ae62017-06-27 07:06:52 -0700437 void WaitForEncodedFrame(int64_t expected_ntp_time) {
438 sink_.WaitForEncodedFrame(expected_ntp_time);
439 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
440 }
441
442 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
443 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
444 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
445 return ok;
446 }
447
448 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
449 sink_.WaitForEncodedFrame(expected_width, expected_height);
450 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
451 }
452
453 void ExpectDroppedFrame() {
454 sink_.ExpectDroppedFrame();
455 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
456 }
457
458 bool WaitForFrame(int64_t timeout_ms) {
459 bool ok = sink_.WaitForFrame(timeout_ms);
460 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
461 return ok;
462 }
463
perkj26091b12016-09-01 01:17:40 -0700464 class TestEncoder : public test::FakeEncoder {
465 public:
466 TestEncoder()
467 : FakeEncoder(Clock::GetRealTimeClock()),
468 continue_encode_event_(false, false) {}
469
asaperssonfab67072017-04-04 05:51:49 -0700470 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800471 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700472 return config_;
473 }
474
475 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800476 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700477 block_next_encode_ = true;
478 }
479
kthelgason876222f2016-11-29 01:44:11 -0800480 VideoEncoder::ScalingSettings GetScalingSettings() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800481 rtc::CritScope lock(&local_crit_sect_);
kthelgasonad9010c2017-02-14 00:46:51 -0800482 if (quality_scaling_)
asapersson142fcc92017-08-17 08:58:54 -0700483 return VideoEncoder::ScalingSettings(true, 1, 2, kMinPixelsPerFrame);
kthelgasonad9010c2017-02-14 00:46:51 -0800484 return VideoEncoder::ScalingSettings(false);
kthelgason876222f2016-11-29 01:44:11 -0800485 }
486
perkjfa10b552016-10-02 23:45:26 -0700487 void ContinueEncode() { continue_encode_event_.Set(); }
488
489 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
490 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800491 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700492 EXPECT_EQ(timestamp_, timestamp);
493 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
494 }
495
kthelgason2fc52542017-03-03 00:24:41 -0800496 void SetQualityScaling(bool b) {
497 rtc::CritScope lock(&local_crit_sect_);
498 quality_scaling_ = b;
499 }
kthelgasonad9010c2017-02-14 00:46:51 -0800500
sprangfe627f32017-03-29 08:24:59 -0700501 void ForceInitEncodeFailure(bool force_failure) {
502 rtc::CritScope lock(&local_crit_sect_);
503 force_init_encode_failed_ = force_failure;
504 }
505
perkjfa10b552016-10-02 23:45:26 -0700506 private:
perkj26091b12016-09-01 01:17:40 -0700507 int32_t Encode(const VideoFrame& input_image,
508 const CodecSpecificInfo* codec_specific_info,
509 const std::vector<FrameType>* frame_types) override {
510 bool block_encode;
511 {
brandtre78d2662017-01-16 05:57:16 -0800512 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700513 EXPECT_GT(input_image.timestamp(), timestamp_);
514 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
515 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
516
517 timestamp_ = input_image.timestamp();
518 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700519 last_input_width_ = input_image.width();
520 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700521 block_encode = block_next_encode_;
522 block_next_encode_ = false;
523 }
524 int32_t result =
525 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
526 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700527 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700528 return result;
529 }
530
sprangfe627f32017-03-29 08:24:59 -0700531 int32_t InitEncode(const VideoCodec* config,
532 int32_t number_of_cores,
533 size_t max_payload_size) override {
534 int res =
535 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
536 rtc::CritScope lock(&local_crit_sect_);
537 if (config->codecType == kVideoCodecVP8 && config->VP8().tl_factory) {
538 // Simulate setting up temporal layers, in order to validate the life
539 // cycle of these objects.
540 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
541 int num_temporal_layers =
542 std::max<int>(1, config->VP8().numberOfTemporalLayers);
543 for (int i = 0; i < num_streams; ++i) {
544 allocated_temporal_layers_.emplace_back(
545 config->VP8().tl_factory->Create(i, num_temporal_layers, 42));
546 }
547 }
548 if (force_init_encode_failed_)
549 return -1;
550 return res;
551 }
552
brandtre78d2662017-01-16 05:57:16 -0800553 rtc::CriticalSection local_crit_sect_;
danilchapa37de392017-09-09 04:17:22 -0700554 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700555 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700556 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
557 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
558 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
559 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
560 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
sprangfe627f32017-03-29 08:24:59 -0700561 std::vector<std::unique_ptr<TemporalLayers>> allocated_temporal_layers_
danilchapa37de392017-09-09 04:17:22 -0700562 RTC_GUARDED_BY(local_crit_sect_);
563 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700564 };
565
mflodmancc3d4422017-08-03 08:27:51 -0700566 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700567 public:
568 explicit TestSink(TestEncoder* test_encoder)
569 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
570
perkj26091b12016-09-01 01:17:40 -0700571 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700572 EXPECT_TRUE(
573 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
574 }
575
576 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
577 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700578 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700579 if (!encoded_frame_event_.Wait(timeout_ms))
580 return false;
perkj26091b12016-09-01 01:17:40 -0700581 {
582 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800583 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700584 }
585 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700586 return true;
perkj26091b12016-09-01 01:17:40 -0700587 }
588
sprangb1ca0732017-02-01 08:38:12 -0800589 void WaitForEncodedFrame(uint32_t expected_width,
590 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700591 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
592 CheckLastFrameSizeMathces(expected_width, expected_height);
593 }
594
595 void CheckLastFrameSizeMathces(uint32_t expected_width,
596 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800597 uint32_t width = 0;
598 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800599 {
600 rtc::CritScope lock(&crit_);
601 width = last_width_;
602 height = last_height_;
603 }
604 EXPECT_EQ(expected_height, height);
605 EXPECT_EQ(expected_width, width);
606 }
607
kthelgason2fc52542017-03-03 00:24:41 -0800608 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800609
sprangc5d62e22017-04-02 23:53:04 -0700610 bool WaitForFrame(int64_t timeout_ms) {
611 return encoded_frame_event_.Wait(timeout_ms);
612 }
613
perkj26091b12016-09-01 01:17:40 -0700614 void SetExpectNoFrames() {
615 rtc::CritScope lock(&crit_);
616 expect_frames_ = false;
617 }
618
asaperssonfab67072017-04-04 05:51:49 -0700619 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200620 rtc::CritScope lock(&crit_);
621 return number_of_reconfigurations_;
622 }
623
asaperssonfab67072017-04-04 05:51:49 -0700624 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200625 rtc::CritScope lock(&crit_);
626 return min_transmit_bitrate_bps_;
627 }
628
perkj26091b12016-09-01 01:17:40 -0700629 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700630 Result OnEncodedImage(
631 const EncodedImage& encoded_image,
632 const CodecSpecificInfo* codec_specific_info,
633 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200634 rtc::CritScope lock(&crit_);
635 EXPECT_TRUE(expect_frames_);
sprangb1ca0732017-02-01 08:38:12 -0800636 last_timestamp_ = encoded_image._timeStamp;
637 last_width_ = encoded_image._encodedWidth;
638 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200639 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800640 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200641 }
642
643 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
644 int min_transmit_bitrate_bps) override {
645 rtc::CriticalSection crit_;
646 ++number_of_reconfigurations_;
647 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
648 }
649
perkj26091b12016-09-01 01:17:40 -0700650 rtc::CriticalSection crit_;
651 TestEncoder* test_encoder_;
652 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800653 uint32_t last_timestamp_ = 0;
654 uint32_t last_height_ = 0;
655 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700656 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200657 int number_of_reconfigurations_ = 0;
658 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700659 };
660
661 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100662 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200663 int codec_width_;
664 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700665 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700666 TestEncoder fake_encoder_;
sprangc5d62e22017-04-02 23:53:04 -0700667 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700668 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800669 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700670 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700671 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700672};
673
mflodmancc3d4422017-08-03 08:27:51 -0700674TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
675 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700676 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700677 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700678 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700679 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700680 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700681}
682
mflodmancc3d4422017-08-03 08:27:51 -0700683TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700684 // Dropped since no target bitrate has been set.
685 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700686 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
687 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700688
mflodmancc3d4422017-08-03 08:27:51 -0700689 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700690
perkja49cbd32016-09-16 07:53:41 -0700691 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700692 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700693 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700694}
695
mflodmancc3d4422017-08-03 08:27:51 -0700696TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
697 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700698 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700699 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700700
mflodmancc3d4422017-08-03 08:27:51 -0700701 video_stream_encoder_->OnBitrateUpdated(0, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700702 // Dropped since bitrate is zero.
perkja49cbd32016-09-16 07:53:41 -0700703 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkj26091b12016-09-01 01:17:40 -0700704
mflodmancc3d4422017-08-03 08:27:51 -0700705 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700706 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700707 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700708 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700709}
710
mflodmancc3d4422017-08-03 08:27:51 -0700711TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
712 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700713 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700714 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700715
716 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700717 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700718
perkja49cbd32016-09-16 07:53:41 -0700719 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700720 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700721 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700722}
723
mflodmancc3d4422017-08-03 08:27:51 -0700724TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
725 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700726
perkja49cbd32016-09-16 07:53:41 -0700727 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700728 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700729
mflodmancc3d4422017-08-03 08:27:51 -0700730 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700731 sink_.SetExpectNoFrames();
732 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700733 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
734 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700735}
736
mflodmancc3d4422017-08-03 08:27:51 -0700737TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
738 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700739
740 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700741 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700742 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700743 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
744 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700745 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
746 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700747 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700748 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700749
mflodmancc3d4422017-08-03 08:27:51 -0700750 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700751}
752
mflodmancc3d4422017-08-03 08:27:51 -0700753TEST_F(VideoStreamEncoderTest,
754 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
755 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100756 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200757
758 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200759 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700760 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100761 // The encoder will have been configured once when the first frame is
762 // received.
763 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200764
765 VideoEncoderConfig video_encoder_config;
perkjfa10b552016-10-02 23:45:26 -0700766 test::FillEncoderConfiguration(1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200767 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -0700768 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
769 kMaxPayloadLength,
770 true /* nack_enabled */);
Per512ecb32016-09-23 15:52:06 +0200771
772 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200773 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700774 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100775 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700776 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700777
mflodmancc3d4422017-08-03 08:27:51 -0700778 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -0700779}
780
mflodmancc3d4422017-08-03 08:27:51 -0700781TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
782 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkjfa10b552016-10-02 23:45:26 -0700783
784 // Capture a frame and wait for it to synchronize with the encoder thread.
785 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700786 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100787 // The encoder will have been configured once.
788 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700789 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
790 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
791
792 codec_width_ *= 2;
793 codec_height_ *= 2;
794 // Capture a frame with a higher resolution and wait for it to synchronize
795 // with the encoder thread.
796 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700797 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700798 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
799 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100800 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700801
mflodmancc3d4422017-08-03 08:27:51 -0700802 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -0700803}
804
mflodmancc3d4422017-08-03 08:27:51 -0700805TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOffFor1S1TLWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800806 const bool kNackEnabled = true;
807 const size_t kNumStreams = 1;
808 const size_t kNumTl = 1;
emircanbbcc3562017-08-18 00:28:40 -0700809 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700810 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800811
812 // Capture a frame and wait for it to synchronize with the encoder thread.
813 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700814 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800815 // The encoder have been configured once when the first frame is received.
816 EXPECT_EQ(1, sink_.number_of_reconfigurations());
817 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
818 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
819 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
820 // Resilience is off for no temporal layers with nack on.
821 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700822 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800823}
824
mflodmancc3d4422017-08-03 08:27:51 -0700825TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOffFor2S1TlWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800826 const bool kNackEnabled = true;
827 const size_t kNumStreams = 2;
828 const size_t kNumTl = 1;
emircanbbcc3562017-08-18 00:28:40 -0700829 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700830 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800831
832 // Capture a frame and wait for it to synchronize with the encoder thread.
833 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700834 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800835 // The encoder have been configured once when the first frame is received.
836 EXPECT_EQ(1, sink_.number_of_reconfigurations());
837 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
838 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
839 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
840 // Resilience is off for no temporal layers and >1 streams with nack on.
841 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700842 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800843}
844
mflodmancc3d4422017-08-03 08:27:51 -0700845TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOnFor1S1TLWithNackDisabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800846 const bool kNackEnabled = false;
847 const size_t kNumStreams = 1;
848 const size_t kNumTl = 1;
emircanbbcc3562017-08-18 00:28:40 -0700849 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700850 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800851
852 // Capture a frame and wait for it to synchronize with the encoder thread.
853 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700854 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800855 // The encoder have been configured once when the first frame is received.
856 EXPECT_EQ(1, sink_.number_of_reconfigurations());
857 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
858 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
859 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
860 // Resilience is on for no temporal layers with nack off.
861 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700862 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800863}
864
mflodmancc3d4422017-08-03 08:27:51 -0700865TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOnFor1S2TlWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800866 const bool kNackEnabled = true;
867 const size_t kNumStreams = 1;
868 const size_t kNumTl = 2;
emircanbbcc3562017-08-18 00:28:40 -0700869 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700870 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800871
872 // Capture a frame and wait for it to synchronize with the encoder thread.
873 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700874 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800875 // The encoder have been configured once when the first frame is received.
876 EXPECT_EQ(1, sink_.number_of_reconfigurations());
877 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
878 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
879 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
880 // Resilience is on for temporal layers.
881 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700882 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800883}
884
emircanbbcc3562017-08-18 00:28:40 -0700885TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOffFor1SL1TLWithNackEnabled) {
886 const bool kNackEnabled = true;
887 const size_t kNumStreams = 1;
888 const size_t kNumTl = 1;
889 const unsigned char kNumSl = 1;
890 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
891 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
892
893 // Capture a frame and wait for it to synchronize with the encoder thread.
894 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
895 sink_.WaitForEncodedFrame(1);
896 // The encoder have been configured once when the first frame is received.
897 EXPECT_EQ(1, sink_.number_of_reconfigurations());
898 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
899 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
900 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
901 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
902 // Resilience is off for no spatial and temporal layers with nack on.
903 EXPECT_FALSE(fake_encoder_.codec_config().VP9()->resilienceOn);
904 video_stream_encoder_->Stop();
905}
906
907TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOnFor1SL1TLWithNackDisabled) {
908 const bool kNackEnabled = false;
909 const size_t kNumStreams = 1;
910 const size_t kNumTl = 1;
911 const unsigned char kNumSl = 1;
912 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
913 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
914
915 // Capture a frame and wait for it to synchronize with the encoder thread.
916 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
917 sink_.WaitForEncodedFrame(1);
918 // The encoder have been configured once when the first frame is received.
919 EXPECT_EQ(1, sink_.number_of_reconfigurations());
920 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
921 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
922 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
923 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
924 // Resilience is on if nack is off.
925 EXPECT_TRUE(fake_encoder_.codec_config().VP9()->resilienceOn);
926 video_stream_encoder_->Stop();
927}
928
929TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOnFor2SL1TLWithNackEnabled) {
930 const bool kNackEnabled = true;
931 const size_t kNumStreams = 1;
932 const size_t kNumTl = 1;
933 const unsigned char kNumSl = 2;
934 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
935 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
936
937 // Capture a frame and wait for it to synchronize with the encoder thread.
938 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
939 sink_.WaitForEncodedFrame(1);
940 // The encoder have been configured once when the first frame is received.
941 EXPECT_EQ(1, sink_.number_of_reconfigurations());
942 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
943 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
944 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
945 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
946 // Resilience is on for spatial layers.
947 EXPECT_TRUE(fake_encoder_.codec_config().VP9()->resilienceOn);
948 video_stream_encoder_->Stop();
949}
950
951TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOnFor1SL2TLWithNackEnabled) {
952 const bool kNackEnabled = true;
953 const size_t kNumStreams = 1;
954 const size_t kNumTl = 2;
955 const unsigned char kNumSl = 1;
956 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
957 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
958
959 // Capture a frame and wait for it to synchronize with the encoder thread.
960 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
961 sink_.WaitForEncodedFrame(1);
962 // The encoder have been configured once when the first frame is received.
963 EXPECT_EQ(1, sink_.number_of_reconfigurations());
964 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
965 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
966 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
967 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
968 // Resilience is on for temporal layers.
969 EXPECT_TRUE(fake_encoder_.codec_config().VP9()->resilienceOn);
970 video_stream_encoder_->Stop();
971}
972
mflodmancc3d4422017-08-03 08:27:51 -0700973TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -0700974 EXPECT_TRUE(video_source_.has_sinks());
975 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700976 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -0700977 &new_video_source,
978 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -0700979 EXPECT_FALSE(video_source_.has_sinks());
980 EXPECT_TRUE(new_video_source.has_sinks());
981
mflodmancc3d4422017-08-03 08:27:51 -0700982 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700983}
984
mflodmancc3d4422017-08-03 08:27:51 -0700985TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -0700986 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700987 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -0700988 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700989 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700990}
991
mflodmancc3d4422017-08-03 08:27:51 -0700992TEST_F(VideoStreamEncoderTest, SinkWantsFromOveruseDetector) {
993 const int kMaxDowngrades = VideoStreamEncoder::kMaxCpuResolutionDowngrades;
994 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -0700995
asapersson02465b82017-04-10 01:12:52 -0700996 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700997
998 int frame_width = 1280;
999 int frame_height = 720;
1000
mflodmancc3d4422017-08-03 08:27:51 -07001001 // Trigger CPU overuse kMaxCpuDowngrades times. Every time, VideoStreamEncoder
1002 // should request lower resolution.
asaperssond0de2952017-04-21 01:47:31 -07001003 for (int i = 1; i <= kMaxDowngrades; ++i) {
perkj803d97f2016-11-01 11:45:46 -07001004 video_source_.IncomingCapturedFrame(
1005 CreateFrame(i, frame_width, frame_height));
sprang4847ae62017-06-27 07:06:52 -07001006 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07001007
mflodmancc3d4422017-08-03 08:27:51 -07001008 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001009
sprang84a37592017-02-10 07:04:27 -08001010 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001011 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
perkj803d97f2016-11-01 11:45:46 -07001012 frame_width * frame_height);
asaperssond0de2952017-04-21 01:47:31 -07001013 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1014 EXPECT_EQ(i, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001015
1016 frame_width /= 2;
1017 frame_height /= 2;
1018 }
1019
kthelgason876222f2016-11-29 01:44:11 -08001020 // Trigger CPU overuse one more time. This should not trigger a request for
perkj803d97f2016-11-01 11:45:46 -07001021 // lower resolution.
1022 rtc::VideoSinkWants current_wants = video_source_.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07001023 video_source_.IncomingCapturedFrame(
1024 CreateFrame(kMaxDowngrades + 1, frame_width, frame_height));
sprang4847ae62017-06-27 07:06:52 -07001025 WaitForEncodedFrame(kMaxDowngrades + 1);
mflodmancc3d4422017-08-03 08:27:51 -07001026 video_stream_encoder_->TriggerCpuOveruse();
sprang84a37592017-02-10 07:04:27 -08001027 EXPECT_EQ(video_source_.sink_wants().target_pixel_count,
1028 current_wants.target_pixel_count);
perkj803d97f2016-11-01 11:45:46 -07001029 EXPECT_EQ(video_source_.sink_wants().max_pixel_count,
1030 current_wants.max_pixel_count);
asaperssond0de2952017-04-21 01:47:31 -07001031 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1032 EXPECT_EQ(kMaxDowngrades,
1033 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001034
1035 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001036 video_stream_encoder_->TriggerCpuNormalUsage();
sprang84a37592017-02-10 07:04:27 -08001037 EXPECT_EQ(frame_width * frame_height * 5 / 3,
1038 video_source_.sink_wants().target_pixel_count.value_or(0));
1039 EXPECT_EQ(frame_width * frame_height * 4,
sprangc5d62e22017-04-02 23:53:04 -07001040 video_source_.sink_wants().max_pixel_count);
asaperssond0de2952017-04-21 01:47:31 -07001041 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1042 EXPECT_EQ(kMaxDowngrades + 1,
1043 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001044
mflodmancc3d4422017-08-03 08:27:51 -07001045 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001046}
1047
mflodmancc3d4422017-08-03 08:27:51 -07001048TEST_F(VideoStreamEncoderTest,
1049 TestMaxCpuResolutionDowngrades_BalancedMode_NoFpsLimit) {
1050 const int kMaxDowngrades = VideoStreamEncoder::kMaxCpuResolutionDowngrades;
asaperssonf7e294d2017-06-13 23:25:22 -07001051 const int kWidth = 1280;
1052 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001053 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001054
1055 // Enable kBalanced preference, no initial limitation.
1056 AdaptingFrameForwarder source;
1057 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001058 video_stream_encoder_->SetSource(
1059 &source,
1060 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001061 VerifyNoLimitation(source.sink_wants());
1062 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1063 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1064
1065 // Trigger adapt down kMaxCpuDowngrades times.
1066 int t = 1;
1067 for (int i = 1; i <= kMaxDowngrades; ++i) {
1068 source.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1069 sink_.WaitForEncodedFrame(t++);
mflodmancc3d4422017-08-03 08:27:51 -07001070 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07001071 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
1072 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1073 EXPECT_EQ(i, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1074 }
1075
1076 // Trigger adapt down, max cpu downgrades reach, expect no change.
1077 rtc::VideoSinkWants last_wants = source.sink_wants();
1078 source.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1079 sink_.WaitForEncodedFrame(t++);
mflodmancc3d4422017-08-03 08:27:51 -07001080 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07001081 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
1082 EXPECT_EQ(last_wants.max_pixel_count, source.sink_wants().max_pixel_count);
1083 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1084 EXPECT_EQ(kMaxDowngrades,
1085 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1086
1087 // Trigger adapt up kMaxCpuDowngrades times.
1088 for (int i = 1; i <= kMaxDowngrades; ++i) {
1089 source.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1090 sink_.WaitForEncodedFrame(t++);
mflodmancc3d4422017-08-03 08:27:51 -07001091 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07001092 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
1093 EXPECT_GT(source.sink_wants().max_pixel_count, last_wants.max_pixel_count);
1094 EXPECT_EQ(kMaxDowngrades + i,
1095 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1096 }
1097
1098 VerifyNoLimitation(source.sink_wants());
1099 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1100
mflodmancc3d4422017-08-03 08:27:51 -07001101 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001102}
mflodmancc3d4422017-08-03 08:27:51 -07001103TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
1104 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001105 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001106
sprangc5d62e22017-04-02 23:53:04 -07001107 const int kFrameWidth = 1280;
1108 const int kFrameHeight = 720;
1109 const int kFrameIntervalMs = 1000 / 30;
1110
1111 int frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -07001112
kthelgason5e13d412016-12-01 03:59:51 -08001113 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001114 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001115 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001116 frame_timestamp += kFrameIntervalMs;
1117
perkj803d97f2016-11-01 11:45:46 -07001118 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001119 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001120 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001121 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001122 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001123 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -07001124
asapersson0944a802017-04-07 00:57:58 -07001125 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -07001126 // wanted resolution.
1127 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
1128 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
1129 kFrameWidth * kFrameHeight);
1130 EXPECT_EQ(std::numeric_limits<int>::max(),
1131 video_source_.sink_wants().max_framerate_fps);
1132
1133 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -07001134 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001135 video_stream_encoder_->SetSource(
perkj803d97f2016-11-01 11:45:46 -07001136 &new_video_source,
1137 VideoSendStream::DegradationPreference::kMaintainResolution);
1138
sprangc5d62e22017-04-02 23:53:04 -07001139 // Initially no degradation registered.
asapersson02465b82017-04-10 01:12:52 -07001140 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001141
sprangc5d62e22017-04-02 23:53:04 -07001142 // Force an input frame rate to be available, or the adaptation call won't
1143 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -07001144 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -07001145 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -07001146 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -07001147 stats_proxy_->SetMockStats(stats);
1148
mflodmancc3d4422017-08-03 08:27:51 -07001149 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001150 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001151 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001152 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001153 frame_timestamp += kFrameIntervalMs;
1154
1155 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001156 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001157 EXPECT_EQ(std::numeric_limits<int>::max(),
1158 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001159 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001160
asapersson02465b82017-04-10 01:12:52 -07001161 // Turn off degradation completely.
mflodmancc3d4422017-08-03 08:27:51 -07001162 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001163 &new_video_source,
1164 VideoSendStream::DegradationPreference::kDegradationDisabled);
asapersson02465b82017-04-10 01:12:52 -07001165 VerifyNoLimitation(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001166
mflodmancc3d4422017-08-03 08:27:51 -07001167 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001168 new_video_source.IncomingCapturedFrame(
1169 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001170 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001171 frame_timestamp += kFrameIntervalMs;
1172
1173 // Still no degradation.
asapersson02465b82017-04-10 01:12:52 -07001174 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001175
1176 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001177 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001178 &new_video_source,
1179 VideoSendStream::DegradationPreference::kMaintainFramerate);
1180 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1181 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001182 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001183 EXPECT_EQ(std::numeric_limits<int>::max(),
1184 new_video_source.sink_wants().max_framerate_fps);
1185
1186 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001187 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001188 &new_video_source,
1189 VideoSendStream::DegradationPreference::kMaintainResolution);
1190 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1191 EXPECT_EQ(std::numeric_limits<int>::max(),
1192 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001193 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001194
mflodmancc3d4422017-08-03 08:27:51 -07001195 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001196}
1197
mflodmancc3d4422017-08-03 08:27:51 -07001198TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
1199 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001200
asaperssonfab67072017-04-04 05:51:49 -07001201 const int kWidth = 1280;
1202 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001203 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001204 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001205 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1206 EXPECT_FALSE(stats.bw_limited_resolution);
1207 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1208
1209 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001210 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001211 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001212 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001213
1214 stats = stats_proxy_->GetStats();
1215 EXPECT_TRUE(stats.bw_limited_resolution);
1216 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1217
1218 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001219 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001220 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001221 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001222
1223 stats = stats_proxy_->GetStats();
1224 EXPECT_FALSE(stats.bw_limited_resolution);
1225 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1226 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1227
mflodmancc3d4422017-08-03 08:27:51 -07001228 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001229}
1230
mflodmancc3d4422017-08-03 08:27:51 -07001231TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
1232 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001233
1234 const int kWidth = 1280;
1235 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001236 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001237 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001238 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1239 EXPECT_FALSE(stats.cpu_limited_resolution);
1240 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1241
1242 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001243 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001244 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001245 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001246
1247 stats = stats_proxy_->GetStats();
1248 EXPECT_TRUE(stats.cpu_limited_resolution);
1249 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1250
1251 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001252 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001253 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001254 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001255
1256 stats = stats_proxy_->GetStats();
1257 EXPECT_FALSE(stats.cpu_limited_resolution);
1258 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001259 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001260
mflodmancc3d4422017-08-03 08:27:51 -07001261 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001262}
1263
mflodmancc3d4422017-08-03 08:27:51 -07001264TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
1265 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001266
asaperssonfab67072017-04-04 05:51:49 -07001267 const int kWidth = 1280;
1268 const int kHeight = 720;
1269 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001270 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001271 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001272 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001273 EXPECT_FALSE(stats.cpu_limited_resolution);
1274 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1275
asaperssonfab67072017-04-04 05:51:49 -07001276 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001277 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001278 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001279 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001280 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001281 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001282 EXPECT_TRUE(stats.cpu_limited_resolution);
1283 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1284
1285 // Set new source with adaptation still enabled.
1286 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001287 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001288 &new_video_source,
1289 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001290
asaperssonfab67072017-04-04 05:51:49 -07001291 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001292 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001293 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001294 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001295 EXPECT_TRUE(stats.cpu_limited_resolution);
1296 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1297
1298 // Set adaptation disabled.
mflodmancc3d4422017-08-03 08:27:51 -07001299 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001300 &new_video_source,
sprangc5d62e22017-04-02 23:53:04 -07001301 VideoSendStream::DegradationPreference::kDegradationDisabled);
kthelgason876222f2016-11-29 01:44:11 -08001302
asaperssonfab67072017-04-04 05:51:49 -07001303 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001304 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001305 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001306 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001307 EXPECT_FALSE(stats.cpu_limited_resolution);
1308 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1309
1310 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001311 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001312 &new_video_source,
1313 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001314
asaperssonfab67072017-04-04 05:51:49 -07001315 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001316 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001317 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001318 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001319 EXPECT_TRUE(stats.cpu_limited_resolution);
1320 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1321
asaperssonfab67072017-04-04 05:51:49 -07001322 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001323 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001324 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001325 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001326 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001327 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001328 EXPECT_FALSE(stats.cpu_limited_resolution);
1329 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001330 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001331
mflodmancc3d4422017-08-03 08:27:51 -07001332 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001333}
1334
mflodmancc3d4422017-08-03 08:27:51 -07001335TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
1336 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001337
asaperssonfab67072017-04-04 05:51:49 -07001338 const int kWidth = 1280;
1339 const int kHeight = 720;
1340 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001341 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001342 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001343 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001344 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001345 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001346
1347 // Set new source with adaptation still enabled.
1348 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001349 video_stream_encoder_->SetSource(
1350 &new_video_source,
1351 VideoSendStream::DegradationPreference::kBalanced);
kthelgason876222f2016-11-29 01:44:11 -08001352
asaperssonfab67072017-04-04 05:51:49 -07001353 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001354 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001355 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001356 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001357 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001358 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001359
asaperssonfab67072017-04-04 05:51:49 -07001360 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001361 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001362 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001363 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001364 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001365 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001366 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001367 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001368
asaperssonfab67072017-04-04 05:51:49 -07001369 // Set new source with adaptation still enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001370 video_stream_encoder_->SetSource(
1371 &new_video_source,
1372 VideoSendStream::DegradationPreference::kBalanced);
kthelgason876222f2016-11-29 01:44:11 -08001373
asaperssonfab67072017-04-04 05:51:49 -07001374 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001375 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001376 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001377 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001378 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001379 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001380
asapersson02465b82017-04-10 01:12:52 -07001381 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001382 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001383 &new_video_source,
1384 VideoSendStream::DegradationPreference::kMaintainResolution);
1385
asaperssonfab67072017-04-04 05:51:49 -07001386 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001387 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001388 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001389 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001390 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001391 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1392 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001393
mflodmancc3d4422017-08-03 08:27:51 -07001394 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001395}
1396
mflodmancc3d4422017-08-03 08:27:51 -07001397TEST_F(VideoStreamEncoderTest,
1398 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1399 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001400
1401 const int kWidth = 1280;
1402 const int kHeight = 720;
1403 video_source_.set_adaptation_enabled(true);
1404 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001405 WaitForEncodedFrame(1);
asapersson36e9eb42017-03-31 05:29:12 -07001406 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1407 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1408 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1409
1410 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001411 video_stream_encoder_->TriggerQualityLow();
asapersson36e9eb42017-03-31 05:29:12 -07001412 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001413 WaitForEncodedFrame(2);
asapersson36e9eb42017-03-31 05:29:12 -07001414 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1415 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1416 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1417
1418 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001419 video_stream_encoder_->TriggerCpuOveruse();
asapersson36e9eb42017-03-31 05:29:12 -07001420 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001421 WaitForEncodedFrame(3);
asapersson36e9eb42017-03-31 05:29:12 -07001422 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1423 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1424 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1425
1426 // Set source with adaptation still enabled but quality scaler is off.
1427 fake_encoder_.SetQualityScaling(false);
mflodmancc3d4422017-08-03 08:27:51 -07001428 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001429 &video_source_,
1430 VideoSendStream::DegradationPreference::kMaintainFramerate);
asapersson36e9eb42017-03-31 05:29:12 -07001431
1432 video_source_.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001433 WaitForEncodedFrame(4);
asapersson36e9eb42017-03-31 05:29:12 -07001434 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1435 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1436 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1437
mflodmancc3d4422017-08-03 08:27:51 -07001438 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001439}
1440
mflodmancc3d4422017-08-03 08:27:51 -07001441TEST_F(VideoStreamEncoderTest,
1442 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
1443 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001444
asapersson0944a802017-04-07 00:57:58 -07001445 const int kWidth = 1280;
1446 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001447 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001448
asaperssonfab67072017-04-04 05:51:49 -07001449 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001450 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001451 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001452 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001453 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001454 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1455
asapersson02465b82017-04-10 01:12:52 -07001456 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001457 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001458 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001459 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001460 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001461 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001462 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001463 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1464
1465 // Set new source with adaptation still enabled.
1466 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001467 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001468 &new_video_source,
1469 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001470
1471 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001472 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001473 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001474 stats = stats_proxy_->GetStats();
1475 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001476 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001477 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1478
sprangc5d62e22017-04-02 23:53:04 -07001479 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001480 video_stream_encoder_->SetSource(
perkj803d97f2016-11-01 11:45:46 -07001481 &new_video_source,
1482 VideoSendStream::DegradationPreference::kMaintainResolution);
1483 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001484 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001485 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001486 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001487 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001488 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001489 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001490 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1491
sprangc5d62e22017-04-02 23:53:04 -07001492 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001493 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001494 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1495 mock_stats.input_frame_rate = 30;
1496 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001497 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001498 stats_proxy_->ResetMockStats();
1499
1500 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001501 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001502 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001503
1504 // Framerate now adapted.
1505 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001506 EXPECT_FALSE(stats.cpu_limited_resolution);
1507 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001508 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1509
1510 // Disable CPU adaptation.
mflodmancc3d4422017-08-03 08:27:51 -07001511 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001512 &new_video_source,
1513 VideoSendStream::DegradationPreference::kDegradationDisabled);
1514 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001515 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001516 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001517
1518 stats = stats_proxy_->GetStats();
1519 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001520 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001521 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1522
1523 // Try to trigger overuse. Should not succeed.
1524 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001525 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001526 stats_proxy_->ResetMockStats();
1527
1528 stats = stats_proxy_->GetStats();
1529 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001530 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001531 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1532
1533 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001534 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001535 &video_source_,
1536 VideoSendStream::DegradationPreference::kMaintainFramerate);
asaperssonfab67072017-04-04 05:51:49 -07001537 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001538 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001539 stats = stats_proxy_->GetStats();
1540 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001541 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001542 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001543
1544 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001545 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001546 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001547 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001548 stats = stats_proxy_->GetStats();
1549 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001550 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001551 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1552
1553 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001554 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001555 &new_video_source,
1556 VideoSendStream::DegradationPreference::kMaintainResolution);
1557 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001558 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001559 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001560 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001561 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001562 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001563 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001564 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1565
1566 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001567 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001568 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001569 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001570 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001571 stats = stats_proxy_->GetStats();
1572 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001573 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001574 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001575 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001576
mflodmancc3d4422017-08-03 08:27:51 -07001577 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001578}
1579
mflodmancc3d4422017-08-03 08:27:51 -07001580TEST_F(VideoStreamEncoderTest, StatsTracksPreferredBitrate) {
1581 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Erik Språng08127a92016-11-16 16:41:30 +01001582
asaperssonfab67072017-04-04 05:51:49 -07001583 const int kWidth = 1280;
1584 const int kHeight = 720;
1585 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001586 WaitForEncodedFrame(1);
Erik Språng08127a92016-11-16 16:41:30 +01001587
1588 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1589 EXPECT_EQ(video_encoder_config_.max_bitrate_bps,
1590 stats.preferred_media_bitrate_bps);
1591
mflodmancc3d4422017-08-03 08:27:51 -07001592 video_stream_encoder_->Stop();
Erik Språng08127a92016-11-16 16:41:30 +01001593}
1594
mflodmancc3d4422017-08-03 08:27:51 -07001595TEST_F(VideoStreamEncoderTest,
1596 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001597 const int kWidth = 1280;
1598 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001599 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001600
asaperssonfab67072017-04-04 05:51:49 -07001601 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001602 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001603
asaperssonfab67072017-04-04 05:51:49 -07001604 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001605 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001606
asaperssonfab67072017-04-04 05:51:49 -07001607 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001608 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001609
asaperssonfab67072017-04-04 05:51:49 -07001610 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001611 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001612
kthelgason876222f2016-11-29 01:44:11 -08001613 // Expect a scale down.
1614 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001615 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001616
asapersson02465b82017-04-10 01:12:52 -07001617 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001618 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001619 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001620 &new_video_source,
1621 VideoSendStream::DegradationPreference::kMaintainResolution);
1622
asaperssonfab67072017-04-04 05:51:49 -07001623 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001624 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001625 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001626 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001627
asaperssonfab67072017-04-04 05:51:49 -07001628 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001629 EXPECT_EQ(std::numeric_limits<int>::max(),
1630 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001631
asaperssonfab67072017-04-04 05:51:49 -07001632 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001633 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001634 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001635 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001636
asapersson02465b82017-04-10 01:12:52 -07001637 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001638 EXPECT_EQ(std::numeric_limits<int>::max(),
1639 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001640
mflodmancc3d4422017-08-03 08:27:51 -07001641 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001642}
1643
mflodmancc3d4422017-08-03 08:27:51 -07001644TEST_F(VideoStreamEncoderTest,
1645 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001646 const int kWidth = 1280;
1647 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001648 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001649
1650 // Enable kMaintainFramerate preference, no initial limitation.
1651 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001652 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001653 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1654
1655 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001656 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001657 VerifyNoLimitation(source.sink_wants());
1658 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1659 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1660
1661 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001662 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001663 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001664 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1665 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1666 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1667
1668 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001669 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001670 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1671 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1672 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1673
mflodmancc3d4422017-08-03 08:27:51 -07001674 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001675}
1676
mflodmancc3d4422017-08-03 08:27:51 -07001677TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001678 const int kWidth = 1280;
1679 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001680 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001681
1682 // Enable kBalanced preference, no initial limitation.
1683 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001684 video_stream_encoder_->SetSource(
1685 &source,
1686 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001687 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1688 sink_.WaitForEncodedFrame(1);
1689 VerifyNoLimitation(source.sink_wants());
1690
1691 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001692 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001693 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1694 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1695 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1696 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1697
1698 // Trigger adapt down for same input resolution, expect no change.
1699 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1700 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001701 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001702 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1703 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1704 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1705
1706 // Trigger adapt down for larger input resolution, expect no change.
1707 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1708 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001709 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001710 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1711 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1712 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1713
mflodmancc3d4422017-08-03 08:27:51 -07001714 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001715}
1716
mflodmancc3d4422017-08-03 08:27:51 -07001717TEST_F(VideoStreamEncoderTest,
1718 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001719 const int kWidth = 1280;
1720 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001721 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001722
1723 // Enable kMaintainFramerate preference, no initial limitation.
1724 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001725 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001726 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1727
1728 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001729 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001730 VerifyNoLimitation(source.sink_wants());
1731 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1732 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1733
1734 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001735 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001736 VerifyNoLimitation(source.sink_wants());
1737 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1738 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1739
mflodmancc3d4422017-08-03 08:27:51 -07001740 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001741}
1742
mflodmancc3d4422017-08-03 08:27:51 -07001743TEST_F(VideoStreamEncoderTest,
1744 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001745 const int kWidth = 1280;
1746 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001747 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001748
1749 // Enable kMaintainResolution preference, no initial limitation.
1750 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001751 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001752 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
1753
1754 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001755 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001756 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001757 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001758 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1759
1760 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001761 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001762 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001763 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001764 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1765
mflodmancc3d4422017-08-03 08:27:51 -07001766 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001767}
1768
mflodmancc3d4422017-08-03 08:27:51 -07001769TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001770 const int kWidth = 1280;
1771 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001772 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001773
1774 // Enable kBalanced preference, no initial limitation.
1775 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001776 video_stream_encoder_->SetSource(
1777 &source,
1778 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001779
1780 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1781 sink_.WaitForEncodedFrame(kWidth, kHeight);
1782 VerifyNoLimitation(source.sink_wants());
1783 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1784 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1785 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1786
1787 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001788 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001789 VerifyNoLimitation(source.sink_wants());
1790 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1791 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1792 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1793
mflodmancc3d4422017-08-03 08:27:51 -07001794 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001795}
1796
mflodmancc3d4422017-08-03 08:27:51 -07001797TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001798 const int kWidth = 1280;
1799 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001800 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001801
1802 // Enable kDegradationDisabled preference, no initial limitation.
1803 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001804 video_stream_encoder_->SetSource(
asapersson09f05612017-05-15 23:40:18 -07001805 &source, VideoSendStream::DegradationPreference::kDegradationDisabled);
1806
1807 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1808 sink_.WaitForEncodedFrame(kWidth, kHeight);
1809 VerifyNoLimitation(source.sink_wants());
1810 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1811 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1812 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1813
1814 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001815 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001816 VerifyNoLimitation(source.sink_wants());
1817 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1818 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1819 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1820
mflodmancc3d4422017-08-03 08:27:51 -07001821 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001822}
1823
mflodmancc3d4422017-08-03 08:27:51 -07001824TEST_F(VideoStreamEncoderTest,
1825 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001826 const int kWidth = 1280;
1827 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001828 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001829
1830 // Enable kMaintainFramerate preference, no initial limitation.
1831 AdaptingFrameForwarder source;
1832 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001833 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001834 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1835
1836 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001837 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001838 VerifyNoLimitation(source.sink_wants());
1839 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1840 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1841
1842 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001843 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001844 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001845 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001846 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001847 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1848 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1849
1850 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001851 video_stream_encoder_->TriggerQualityHigh();
asapersson02465b82017-04-10 01:12:52 -07001852 VerifyNoLimitation(source.sink_wants());
1853 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1854 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1855 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1856
mflodmancc3d4422017-08-03 08:27:51 -07001857 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001858}
1859
mflodmancc3d4422017-08-03 08:27:51 -07001860TEST_F(VideoStreamEncoderTest,
1861 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001862 const int kWidth = 1280;
1863 const int kHeight = 720;
1864 const int kInputFps = 30;
mflodmancc3d4422017-08-03 08:27:51 -07001865 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001866
1867 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1868 stats.input_frame_rate = kInputFps;
1869 stats_proxy_->SetMockStats(stats);
1870
1871 // Expect no scaling to begin with (preference: kMaintainFramerate).
1872 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1873 sink_.WaitForEncodedFrame(1);
1874 VerifyNoLimitation(video_source_.sink_wants());
1875
1876 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001877 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001878 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1879 sink_.WaitForEncodedFrame(2);
1880 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1881
1882 // Enable kMaintainResolution preference.
1883 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001884 video_stream_encoder_->SetSource(
asapersson09f05612017-05-15 23:40:18 -07001885 &new_video_source,
1886 VideoSendStream::DegradationPreference::kMaintainResolution);
1887 VerifyNoLimitation(new_video_source.sink_wants());
1888
1889 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001890 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001891 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1892 sink_.WaitForEncodedFrame(3);
1893 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1894
1895 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001896 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001897 VerifyNoLimitation(new_video_source.sink_wants());
1898
mflodmancc3d4422017-08-03 08:27:51 -07001899 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001900}
1901
mflodmancc3d4422017-08-03 08:27:51 -07001902TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001903 const int kWidth = 1280;
1904 const int kHeight = 720;
1905 const size_t kNumFrames = 10;
1906
mflodmancc3d4422017-08-03 08:27:51 -07001907 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001908
asaperssond0de2952017-04-21 01:47:31 -07001909 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001910 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001911 video_source_.set_adaptation_enabled(true);
1912
1913 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1914 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1915
1916 int downscales = 0;
1917 for (size_t i = 1; i <= kNumFrames; i++) {
1918 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001919 WaitForEncodedFrame(i);
asaperssond0de2952017-04-21 01:47:31 -07001920
asaperssonfab67072017-04-04 05:51:49 -07001921 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001922 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001923 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001924 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001925
1926 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1927 ++downscales;
1928
1929 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1930 EXPECT_EQ(downscales,
1931 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1932 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001933 }
mflodmancc3d4422017-08-03 08:27:51 -07001934 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001935}
1936
mflodmancc3d4422017-08-03 08:27:51 -07001937TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001938 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1939 const int kWidth = 1280;
1940 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001941 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001942
1943 // Enable kMaintainFramerate preference, no initial limitation.
1944 AdaptingFrameForwarder source;
1945 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001946 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07001947 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1948
1949 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001950 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001951 VerifyNoLimitation(source.sink_wants());
1952 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1953 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1954
1955 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001956 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001957 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001958 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001959 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001960 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1961 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1962
1963 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001964 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07001965 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001966 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001967 VerifyNoLimitation(source.sink_wants());
1968 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1969 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1970
1971 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001972 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001973 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001974 WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07001975 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001976 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1977 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1978
1979 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001980 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson09f05612017-05-15 23:40:18 -07001981 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1982 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001983 VerifyNoLimitation(source.sink_wants());
1984 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1985 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1986
mflodmancc3d4422017-08-03 08:27:51 -07001987 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001988}
1989
mflodmancc3d4422017-08-03 08:27:51 -07001990TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07001991 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
1992 const int kWidth = 1280;
1993 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001994 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001995
1996 // Enable kBalanced preference, no initial limitation.
1997 AdaptingFrameForwarder source;
1998 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001999 video_stream_encoder_->SetSource(
2000 &source,
2001 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002002
2003 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2004 sink_.WaitForEncodedFrame(kWidth, kHeight);
2005 VerifyNoLimitation(source.sink_wants());
2006 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2007 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2008
2009 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002010 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002011 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
2012 sink_.WaitForEncodedFrame(2);
2013 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2014 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2015 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2016
2017 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002018 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002019 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
2020 sink_.WaitForEncodedFrame(kWidth, kHeight);
2021 VerifyNoLimitation(source.sink_wants());
2022 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2023 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2024
2025 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002026 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002027 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
2028 sink_.WaitForEncodedFrame(4);
2029 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2030 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2031 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2032
2033 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002034 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002035 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
2036 sink_.WaitForEncodedFrame(kWidth, kHeight);
2037 VerifyNoLimitation(source.sink_wants());
2038 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2039 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2040
mflodmancc3d4422017-08-03 08:27:51 -07002041 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002042}
2043
mflodmancc3d4422017-08-03 08:27:51 -07002044TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002045 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
2046 const int kWidth = 1280;
2047 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07002048 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002049
2050 // Enable kMaintainFramerate preference, no initial limitation.
2051 AdaptingFrameForwarder source;
2052 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002053 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07002054 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
2055
2056 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002057 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002058 VerifyNoLimitation(source.sink_wants());
2059 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2060 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2061 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2062 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2063
2064 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002065 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002066 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002067 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07002068 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002069 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2070 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2071 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2072 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2073
2074 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07002075 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002076 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002077 WaitForEncodedFrame(3);
asapersson09f05612017-05-15 23:40:18 -07002078 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2079 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07002080 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2081 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2082 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2083 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2084
2085 // Trigger cpu adapt down, max cpu downgrades reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002086 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002087 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002088 WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07002089 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002090 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2091 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2092 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2093 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2094
2095 // Trigger quality adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002096 video_stream_encoder_->TriggerQualityLow();
asaperssond0de2952017-04-21 01:47:31 -07002097 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002098 WaitForEncodedFrame(5);
asapersson09f05612017-05-15 23:40:18 -07002099 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002100 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2101 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2102 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2103 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2104
2105 // Trigger cpu adapt up, expect upscaled resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07002106 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07002107 source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002108 WaitForEncodedFrame(6);
asapersson09f05612017-05-15 23:40:18 -07002109 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002110 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2111 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2112 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2113 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2114
2115 // Trigger cpu adapt up, expect upscaled resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002116 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07002117 source.IncomingCapturedFrame(CreateFrame(7, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002118 WaitForEncodedFrame(7);
asapersson09f05612017-05-15 23:40:18 -07002119 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002120 last_wants = source.sink_wants();
2121 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2122 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2123 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2124 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2125
2126 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002127 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07002128 source.IncomingCapturedFrame(CreateFrame(8, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002129 WaitForEncodedFrame(8);
asapersson09f05612017-05-15 23:40:18 -07002130 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002131 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2132 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2133 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2134 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2135
2136 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002137 video_stream_encoder_->TriggerQualityHigh();
asaperssond0de2952017-04-21 01:47:31 -07002138 source.IncomingCapturedFrame(CreateFrame(9, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002139 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002140 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002141 VerifyNoLimitation(source.sink_wants());
2142 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2143 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2144 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2145 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002146
mflodmancc3d4422017-08-03 08:27:51 -07002147 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002148}
2149
mflodmancc3d4422017-08-03 08:27:51 -07002150TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002151 const int kWidth = 640;
2152 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002153
mflodmancc3d4422017-08-03 08:27:51 -07002154 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002155
perkj803d97f2016-11-01 11:45:46 -07002156 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002157 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002158 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002159 }
2160
mflodmancc3d4422017-08-03 08:27:51 -07002161 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002162 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002163 video_source_.IncomingCapturedFrame(CreateFrame(
2164 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002165 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002166 }
2167
mflodmancc3d4422017-08-03 08:27:51 -07002168 video_stream_encoder_->Stop();
2169 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002170 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002171
perkj803d97f2016-11-01 11:45:46 -07002172 EXPECT_EQ(1,
2173 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2174 EXPECT_EQ(
2175 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2176}
2177
mflodmancc3d4422017-08-03 08:27:51 -07002178TEST_F(VideoStreamEncoderTest,
2179 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2180 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002181 const int kWidth = 640;
2182 const int kHeight = 360;
2183
mflodmancc3d4422017-08-03 08:27:51 -07002184 video_stream_encoder_->SetSource(
asaperssonf4e44af2017-04-19 02:01:06 -07002185 &video_source_,
2186 VideoSendStream::DegradationPreference::kDegradationDisabled);
2187
2188 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2189 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002190 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002191 }
2192
mflodmancc3d4422017-08-03 08:27:51 -07002193 video_stream_encoder_->Stop();
2194 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002195 stats_proxy_.reset();
2196
2197 EXPECT_EQ(0,
2198 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2199}
2200
mflodmancc3d4422017-08-03 08:27:51 -07002201TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002202 MockBitrateObserver bitrate_observer;
mflodmancc3d4422017-08-03 08:27:51 -07002203 video_stream_encoder_->SetBitrateObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002204
2205 const int kDefaultFps = 30;
2206 const BitrateAllocation expected_bitrate =
2207 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002208 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002209
2210 // First called on bitrate updated, then again on first frame.
2211 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2212 .Times(2);
mflodmancc3d4422017-08-03 08:27:51 -07002213 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002214
2215 const int64_t kStartTimeMs = 1;
2216 video_source_.IncomingCapturedFrame(
2217 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002218 WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002219
2220 // Not called on second frame.
2221 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2222 .Times(0);
2223 video_source_.IncomingCapturedFrame(
2224 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002225 WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002226
2227 // Called after a process interval.
2228 const int64_t kProcessIntervalMs =
2229 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang4847ae62017-06-27 07:06:52 -07002230 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec *
2231 (kProcessIntervalMs + (1000 / kDefaultFps)));
sprang57c2fff2017-01-16 06:24:02 -08002232 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2233 .Times(1);
2234 video_source_.IncomingCapturedFrame(CreateFrame(
2235 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002236 WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002237
mflodmancc3d4422017-08-03 08:27:51 -07002238 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002239}
2240
mflodmancc3d4422017-08-03 08:27:51 -07002241TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
sprangfda496a2017-06-15 04:21:07 -07002242 const int kFrameWidth = 1280;
2243 const int kFrameHeight = 720;
2244 const int kFramerate = 24;
2245
mflodmancc3d4422017-08-03 08:27:51 -07002246 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002247 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002248 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002249 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2250
2251 // Insert a single frame, triggering initial configuration.
2252 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002253 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002254
mflodmancc3d4422017-08-03 08:27:51 -07002255 EXPECT_EQ(
2256 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2257 kDefaultFramerate);
sprangfda496a2017-06-15 04:21:07 -07002258
2259 // Trigger reconfigure encoder (without resetting the entire instance).
2260 VideoEncoderConfig video_encoder_config;
2261 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2262 video_encoder_config.number_of_streams = 1;
2263 video_encoder_config.video_stream_factory =
2264 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07002265 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2266 kMaxPayloadLength, false);
2267 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002268
2269 // Detector should be updated with fps limit from codec config.
mflodmancc3d4422017-08-03 08:27:51 -07002270 EXPECT_EQ(
2271 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2272 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002273
2274 // Trigger overuse, max framerate should be reduced.
2275 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2276 stats.input_frame_rate = kFramerate;
2277 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002278 video_stream_encoder_->TriggerCpuOveruse();
2279 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002280 int adapted_framerate =
mflodmancc3d4422017-08-03 08:27:51 -07002281 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002282 EXPECT_LT(adapted_framerate, kFramerate);
2283
2284 // Trigger underuse, max framerate should go back to codec configured fps.
2285 // Set extra low fps, to make sure it's actually reset, not just incremented.
2286 stats = stats_proxy_->GetStats();
2287 stats.input_frame_rate = adapted_framerate / 2;
2288 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002289 video_stream_encoder_->TriggerCpuNormalUsage();
2290 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2291 EXPECT_EQ(
2292 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2293 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002294
mflodmancc3d4422017-08-03 08:27:51 -07002295 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002296}
2297
mflodmancc3d4422017-08-03 08:27:51 -07002298TEST_F(VideoStreamEncoderTest,
2299 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
sprangfda496a2017-06-15 04:21:07 -07002300 const int kFrameWidth = 1280;
2301 const int kFrameHeight = 720;
2302 const int kLowFramerate = 15;
2303 const int kHighFramerate = 25;
2304
mflodmancc3d4422017-08-03 08:27:51 -07002305 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002306 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002307 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002308 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2309
2310 // Trigger initial configuration.
2311 VideoEncoderConfig video_encoder_config;
2312 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2313 video_encoder_config.number_of_streams = 1;
2314 video_encoder_config.video_stream_factory =
2315 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2316 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002317 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2318 kMaxPayloadLength, false);
2319 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002320
mflodmancc3d4422017-08-03 08:27:51 -07002321 EXPECT_EQ(
2322 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2323 kLowFramerate);
sprangfda496a2017-06-15 04:21:07 -07002324
2325 // Trigger overuse, max framerate should be reduced.
2326 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2327 stats.input_frame_rate = kLowFramerate;
2328 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002329 video_stream_encoder_->TriggerCpuOveruse();
2330 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002331 int adapted_framerate =
mflodmancc3d4422017-08-03 08:27:51 -07002332 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002333 EXPECT_LT(adapted_framerate, kLowFramerate);
2334
2335 // Reconfigure the encoder with a new (higher max framerate), max fps should
2336 // still respect the adaptation.
2337 video_encoder_config.video_stream_factory =
2338 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2339 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002340 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2341 kMaxPayloadLength, false);
2342 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002343
mflodmancc3d4422017-08-03 08:27:51 -07002344 EXPECT_EQ(
2345 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2346 adapted_framerate);
sprangfda496a2017-06-15 04:21:07 -07002347
2348 // Trigger underuse, max framerate should go back to codec configured fps.
2349 stats = stats_proxy_->GetStats();
2350 stats.input_frame_rate = adapted_framerate;
2351 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002352 video_stream_encoder_->TriggerCpuNormalUsage();
2353 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2354 EXPECT_EQ(
2355 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2356 kHighFramerate);
sprangfda496a2017-06-15 04:21:07 -07002357
mflodmancc3d4422017-08-03 08:27:51 -07002358 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002359}
2360
mflodmancc3d4422017-08-03 08:27:51 -07002361TEST_F(VideoStreamEncoderTest,
2362 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002363 const int kFrameWidth = 1280;
2364 const int kFrameHeight = 720;
2365 const int kFramerate = 24;
2366
mflodmancc3d4422017-08-03 08:27:51 -07002367 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002368 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002369 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002370 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2371
2372 // Trigger initial configuration.
2373 VideoEncoderConfig video_encoder_config;
2374 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2375 video_encoder_config.number_of_streams = 1;
2376 video_encoder_config.video_stream_factory =
2377 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2378 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002379 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2380 kMaxPayloadLength, false);
2381 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002382
mflodmancc3d4422017-08-03 08:27:51 -07002383 EXPECT_EQ(
2384 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2385 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002386
2387 // Trigger overuse, max framerate should be reduced.
2388 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2389 stats.input_frame_rate = kFramerate;
2390 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002391 video_stream_encoder_->TriggerCpuOveruse();
2392 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002393 int adapted_framerate =
mflodmancc3d4422017-08-03 08:27:51 -07002394 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002395 EXPECT_LT(adapted_framerate, kFramerate);
2396
2397 // Change degradation preference to not enable framerate scaling. Target
2398 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002399 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002400 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07002401 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2402 EXPECT_EQ(
2403 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2404 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002405
mflodmancc3d4422017-08-03 08:27:51 -07002406 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002407}
2408
mflodmancc3d4422017-08-03 08:27:51 -07002409TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002410 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002411 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002412 const int kWidth = 640;
2413 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002414
asaperssonfab67072017-04-04 05:51:49 -07002415 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002416
2417 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002418 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002419
2420 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002421 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002422
sprangc5d62e22017-04-02 23:53:04 -07002423 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002424
asaperssonfab67072017-04-04 05:51:49 -07002425 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002426 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002427 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002428
2429 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002430 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002431
sprangc5d62e22017-04-02 23:53:04 -07002432 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002433
mflodmancc3d4422017-08-03 08:27:51 -07002434 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002435}
2436
mflodmancc3d4422017-08-03 08:27:51 -07002437TEST_F(VideoStreamEncoderTest,
2438 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002439 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002440 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002441 const int kWidth = 640;
2442 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002443
2444 // We expect the n initial frames to get dropped.
2445 int i;
2446 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002447 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002448 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002449 }
2450 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002451 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002452 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002453
2454 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002455 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002456
mflodmancc3d4422017-08-03 08:27:51 -07002457 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002458}
2459
mflodmancc3d4422017-08-03 08:27:51 -07002460TEST_F(VideoStreamEncoderTest,
2461 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002462 const int kWidth = 640;
2463 const int kHeight = 360;
mflodmancc3d4422017-08-03 08:27:51 -07002464 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002465
2466 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002467 video_stream_encoder_->SetSource(
kthelgason2bc68642017-02-07 07:02:22 -08002468 &video_source_,
2469 VideoSendStream::DegradationPreference::kMaintainResolution);
2470
asaperssonfab67072017-04-04 05:51:49 -07002471 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002472 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002473 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002474
mflodmancc3d4422017-08-03 08:27:51 -07002475 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002476}
2477
mflodmancc3d4422017-08-03 08:27:51 -07002478TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002479 const int kWidth = 640;
2480 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002481 fake_encoder_.SetQualityScaling(false);
mflodmancc3d4422017-08-03 08:27:51 -07002482 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002483
kthelgasonb83797b2017-02-14 11:57:25 -08002484 // Force quality scaler reconfiguration by resetting the source.
mflodmancc3d4422017-08-03 08:27:51 -07002485 video_stream_encoder_->SetSource(
2486 &video_source_,
2487 VideoSendStream::DegradationPreference::kBalanced);
kthelgasonad9010c2017-02-14 00:46:51 -08002488
asaperssonfab67072017-04-04 05:51:49 -07002489 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002490 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002491 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002492
mflodmancc3d4422017-08-03 08:27:51 -07002493 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002494 fake_encoder_.SetQualityScaling(true);
2495}
2496
mflodmancc3d4422017-08-03 08:27:51 -07002497TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002498 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2499 const int kTooSmallWidth = 10;
2500 const int kTooSmallHeight = 10;
mflodmancc3d4422017-08-03 08:27:51 -07002501 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002502
2503 // Enable kMaintainFramerate preference, no initial limitation.
2504 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002505 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07002506 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
2507 VerifyNoLimitation(source.sink_wants());
2508 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2509
2510 // Trigger adapt down, too small frame, expect no change.
2511 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002512 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002513 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002514 VerifyNoLimitation(source.sink_wants());
2515 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2516 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2517
mflodmancc3d4422017-08-03 08:27:51 -07002518 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002519}
2520
mflodmancc3d4422017-08-03 08:27:51 -07002521TEST_F(VideoStreamEncoderTest,
2522 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002523 const int kTooSmallWidth = 10;
2524 const int kTooSmallHeight = 10;
2525 const int kFpsLimit = 7;
mflodmancc3d4422017-08-03 08:27:51 -07002526 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002527
2528 // Enable kBalanced preference, no initial limitation.
2529 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002530 video_stream_encoder_->SetSource(
2531 &source,
2532 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002533 VerifyNoLimitation(source.sink_wants());
2534 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2535 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2536
2537 // Trigger adapt down, expect limited framerate.
2538 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002539 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002540 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002541 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2542 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2543 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2544 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2545
2546 // Trigger adapt down, too small frame, expect no change.
2547 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002548 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002549 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002550 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2551 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2552 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2553 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2554
mflodmancc3d4422017-08-03 08:27:51 -07002555 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002556}
2557
mflodmancc3d4422017-08-03 08:27:51 -07002558TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002559 fake_encoder_.ForceInitEncodeFailure(true);
mflodmancc3d4422017-08-03 08:27:51 -07002560 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
emircanbbcc3562017-08-18 00:28:40 -07002561 ResetEncoder("VP8", 2, 1, 1, true, false);
asapersson02465b82017-04-10 01:12:52 -07002562 const int kFrameWidth = 1280;
2563 const int kFrameHeight = 720;
2564 video_source_.IncomingCapturedFrame(
2565 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002566 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002567 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002568}
2569
sprangb1ca0732017-02-01 08:38:12 -08002570// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002571TEST_F(VideoStreamEncoderTest,
2572 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
2573 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002574
2575 const int kFrameWidth = 1280;
2576 const int kFrameHeight = 720;
2577 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002578 // requested by
2579 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002580 video_source_.set_adaptation_enabled(true);
2581
2582 video_source_.IncomingCapturedFrame(
2583 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002584 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002585
2586 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002587 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002588 video_source_.IncomingCapturedFrame(
2589 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002590 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002591
asaperssonfab67072017-04-04 05:51:49 -07002592 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002593 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002594 video_source_.IncomingCapturedFrame(
2595 CreateFrame(3, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002596 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002597
mflodmancc3d4422017-08-03 08:27:51 -07002598 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002599}
sprangfe627f32017-03-29 08:24:59 -07002600
mflodmancc3d4422017-08-03 08:27:51 -07002601TEST_F(VideoStreamEncoderTest,
2602 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002603 const int kFrameWidth = 1280;
2604 const int kFrameHeight = 720;
sprang4847ae62017-06-27 07:06:52 -07002605 int kFrameIntervalMs = rtc::kNumMillisecsPerSec / max_framerate_;
sprangc5d62e22017-04-02 23:53:04 -07002606
mflodmancc3d4422017-08-03 08:27:51 -07002607 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2608 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07002609 &video_source_,
2610 VideoSendStream::DegradationPreference::kMaintainResolution);
2611 video_source_.set_adaptation_enabled(true);
2612
sprang4847ae62017-06-27 07:06:52 -07002613 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002614
2615 video_source_.IncomingCapturedFrame(
2616 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002617 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002618
2619 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002620 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002621
2622 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002623 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002624 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002625 video_source_.IncomingCapturedFrame(
2626 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002627 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002628 }
2629
2630 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002631 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002632 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002633 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002634 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002635 video_source_.IncomingCapturedFrame(
2636 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002637 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002638 ++num_frames_dropped;
2639 } else {
2640 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2641 }
2642 }
2643
sprang4847ae62017-06-27 07:06:52 -07002644 // Add some slack to account for frames dropped by the frame dropper.
2645 const int kErrorMargin = 1;
2646 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002647 kErrorMargin);
2648
2649 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002650 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002651 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002652 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002653 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002654 video_source_.IncomingCapturedFrame(
2655 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002656 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002657 ++num_frames_dropped;
2658 } else {
2659 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2660 }
2661 }
sprang4847ae62017-06-27 07:06:52 -07002662 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002663 kErrorMargin);
2664
2665 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002666 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002667 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002668 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002669 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002670 video_source_.IncomingCapturedFrame(
2671 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002672 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002673 ++num_frames_dropped;
2674 } else {
2675 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2676 }
2677 }
sprang4847ae62017-06-27 07:06:52 -07002678 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002679 kErrorMargin);
2680
2681 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002682 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002683 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002684 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002685 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002686 video_source_.IncomingCapturedFrame(
2687 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002688 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002689 ++num_frames_dropped;
2690 } else {
2691 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2692 }
2693 }
2694 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2695
mflodmancc3d4422017-08-03 08:27:51 -07002696 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002697}
2698
mflodmancc3d4422017-08-03 08:27:51 -07002699TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002700 const int kFramerateFps = 5;
2701 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
2702 const int kMinFpsFrameInterval = rtc::kNumMillisecsPerSec / kMinFramerateFps;
2703 const int kFrameWidth = 1280;
2704 const int kFrameHeight = 720;
2705
sprang4847ae62017-06-27 07:06:52 -07002706 // Reconfigure encoder with two temporal layers and screensharing, which will
2707 // disable frame dropping and make testing easier.
emircanbbcc3562017-08-18 00:28:40 -07002708 ResetEncoder("VP8", 1, 2, 1, true, true);
sprang4847ae62017-06-27 07:06:52 -07002709
mflodmancc3d4422017-08-03 08:27:51 -07002710 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2711 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07002712 &video_source_,
2713 VideoSendStream::DegradationPreference::kMaintainResolution);
2714 video_source_.set_adaptation_enabled(true);
2715
sprang4847ae62017-06-27 07:06:52 -07002716 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002717
2718 // Trigger overuse as much as we can.
mflodmancc3d4422017-08-03 08:27:51 -07002719 for (int i = 0; i < VideoStreamEncoder::kMaxCpuResolutionDowngrades; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002720 // Insert frames to get a new fps estimate...
2721 for (int j = 0; j < kFramerateFps; ++j) {
2722 video_source_.IncomingCapturedFrame(
2723 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
2724 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002725 }
2726 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002727 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002728 }
2729
2730 // Drain any frame in the pipeline.
sprang4847ae62017-06-27 07:06:52 -07002731 WaitForFrame(kDefaultTimeoutMs);
sprangc5d62e22017-04-02 23:53:04 -07002732
2733 // Insert frames at min fps, all should go through.
2734 for (int i = 0; i < 10; ++i) {
2735 timestamp_ms += kMinFpsFrameInterval;
sprangc5d62e22017-04-02 23:53:04 -07002736 video_source_.IncomingCapturedFrame(
2737 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002738 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002739 }
asaperssonf7e294d2017-06-13 23:25:22 -07002740
mflodmancc3d4422017-08-03 08:27:51 -07002741 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002742}
asaperssonf7e294d2017-06-13 23:25:22 -07002743
mflodmancc3d4422017-08-03 08:27:51 -07002744TEST_F(VideoStreamEncoderTest,
2745 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002746 const int kWidth = 1280;
2747 const int kHeight = 720;
2748 const int64_t kFrameIntervalMs = 150;
2749 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002750 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002751
2752 // Enable kBalanced preference, no initial limitation.
2753 AdaptingFrameForwarder source;
2754 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002755 video_stream_encoder_->SetSource(
2756 &source,
2757 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002758 timestamp_ms += kFrameIntervalMs;
2759 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002760 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002761 VerifyNoLimitation(source.sink_wants());
2762 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2763 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2764 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2765
2766 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002767 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002768 timestamp_ms += kFrameIntervalMs;
2769 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002770 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002771 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2772 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2773 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2774 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2775
2776 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002777 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002778 timestamp_ms += kFrameIntervalMs;
2779 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002780 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002781 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2782 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2783 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2784 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2785
2786 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002787 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002788 timestamp_ms += kFrameIntervalMs;
2789 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002790 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002791 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2792 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2793 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2794 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2795
2796 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002797 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002798 timestamp_ms += kFrameIntervalMs;
2799 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002800 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002801 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2802 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2803 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2804 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2805
2806 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002807 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002808 timestamp_ms += kFrameIntervalMs;
2809 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002810 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002811 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2812 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2813 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2814 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2815
2816 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002817 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002818 timestamp_ms += kFrameIntervalMs;
2819 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002820 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002821 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2822 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2823 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2824 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2825
2826 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002827 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002828 timestamp_ms += kFrameIntervalMs;
2829 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002830 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002831 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2832 rtc::VideoSinkWants last_wants = source.sink_wants();
2833 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2834 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2835 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2836
2837 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002838 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002839 timestamp_ms += kFrameIntervalMs;
2840 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002841 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002842 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2843 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2844 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2845 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2846
2847 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002848 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002849 timestamp_ms += kFrameIntervalMs;
2850 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002851 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002852 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2853 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2854 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2855 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2856
2857 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002858 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002859 timestamp_ms += kFrameIntervalMs;
2860 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002861 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002862 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2863 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2864 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2865 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2866
2867 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002868 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002869 timestamp_ms += kFrameIntervalMs;
2870 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002871 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002872 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2873 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2874 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2875 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2876
2877 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002878 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002879 timestamp_ms += kFrameIntervalMs;
2880 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002881 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002882 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2883 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2884 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2885 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2886
2887 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002888 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002889 timestamp_ms += kFrameIntervalMs;
2890 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002891 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002892 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2893 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2894 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2895 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2896
2897 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002898 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002899 timestamp_ms += kFrameIntervalMs;
2900 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002901 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002902 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2903 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2904 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2905 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2906
2907 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002908 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002909 timestamp_ms += kFrameIntervalMs;
2910 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002911 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002912 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2913 VerifyNoLimitation(source.sink_wants());
2914 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2915 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2916 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2917
2918 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002919 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002920 VerifyNoLimitation(source.sink_wants());
2921 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2922
mflodmancc3d4422017-08-03 08:27:51 -07002923 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002924}
2925
mflodmancc3d4422017-08-03 08:27:51 -07002926TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07002927 const int kWidth = 1280;
2928 const int kHeight = 720;
2929 const int64_t kFrameIntervalMs = 150;
2930 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002931 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002932
2933 // Enable kBalanced preference, no initial limitation.
2934 AdaptingFrameForwarder source;
2935 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002936 video_stream_encoder_->SetSource(
2937 &source,
2938 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002939 timestamp_ms += kFrameIntervalMs;
2940 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002941 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002942 VerifyNoLimitation(source.sink_wants());
2943 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2944 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2945 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2946 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2947 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2948 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2949
2950 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002951 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002952 timestamp_ms += kFrameIntervalMs;
2953 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002954 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002955 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2956 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2957 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2958 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2959 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2960 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2961 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2962
2963 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002964 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002965 timestamp_ms += kFrameIntervalMs;
2966 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002967 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002968 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2969 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2970 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2971 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2972 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2973 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2974 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2975
2976 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002977 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002978 timestamp_ms += kFrameIntervalMs;
2979 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002980 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002981 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2982 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2983 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2984 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2985 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2986 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2987 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2988
2989 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002990 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002991 timestamp_ms += kFrameIntervalMs;
2992 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002993 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002994 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2995 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2996 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2997 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2998 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2999 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3000 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3001
3002 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003003 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003004 timestamp_ms += kFrameIntervalMs;
3005 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003006 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003007 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3008 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3009 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3010 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3011 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3012 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3013 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3014
3015 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003016 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003017 timestamp_ms += kFrameIntervalMs;
3018 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003019 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003020 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3021 VerifyNoLimitation(source.sink_wants());
3022 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3023 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3024 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3025 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3026 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3027 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3028
3029 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003030 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003031 VerifyNoLimitation(source.sink_wants());
3032 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3033 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3034
mflodmancc3d4422017-08-03 08:27:51 -07003035 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003036}
3037
mflodmancc3d4422017-08-03 08:27:51 -07003038TEST_F(VideoStreamEncoderTest,
3039 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07003040 const int kWidth = 640;
3041 const int kHeight = 360;
3042 const int kFpsLimit = 15;
3043 const int64_t kFrameIntervalMs = 150;
3044 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07003045 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07003046
3047 // Enable kBalanced preference, no initial limitation.
3048 AdaptingFrameForwarder source;
3049 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07003050 video_stream_encoder_->SetSource(
3051 &source,
3052 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07003053 timestamp_ms += kFrameIntervalMs;
3054 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003055 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003056 VerifyNoLimitation(source.sink_wants());
3057 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3058 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3059 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3060 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3061 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3062 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3063
3064 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003065 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003066 timestamp_ms += kFrameIntervalMs;
3067 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003068 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003069 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
3070 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3071 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3072 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3073 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3074 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3075 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3076
3077 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003078 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003079 timestamp_ms += kFrameIntervalMs;
3080 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003081 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003082 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
3083 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3084 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3085 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3086 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3087 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3088 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3089
3090 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003091 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003092 timestamp_ms += kFrameIntervalMs;
3093 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003094 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003095 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3096 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3097 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3098 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3099 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3100 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3101 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3102
3103 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003104 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003105 timestamp_ms += kFrameIntervalMs;
3106 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003107 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003108 VerifyNoLimitation(source.sink_wants());
3109 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3110 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3111 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3112 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3113 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3114 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3115
3116 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003117 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003118 VerifyNoLimitation(source.sink_wants());
3119 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3120 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3121
mflodmancc3d4422017-08-03 08:27:51 -07003122 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003123}
3124
mflodmancc3d4422017-08-03 08:27:51 -07003125TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003126 // Simulates simulcast behavior and makes highest stream resolutions divisible
3127 // by 4.
3128 class CroppingVideoStreamFactory
3129 : public VideoEncoderConfig::VideoStreamFactoryInterface {
3130 public:
3131 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
3132 int framerate)
3133 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
3134 EXPECT_GT(num_temporal_layers, 0u);
3135 EXPECT_GT(framerate, 0);
3136 }
3137
3138 private:
3139 std::vector<VideoStream> CreateEncoderStreams(
3140 int width,
3141 int height,
3142 const VideoEncoderConfig& encoder_config) override {
3143 std::vector<VideoStream> streams =
3144 test::CreateVideoStreams(width - width % 4, height - height % 4,
3145 encoder_config);
3146 for (VideoStream& stream : streams) {
3147 stream.temporal_layer_thresholds_bps.resize(num_temporal_layers_ - 1);
3148 stream.max_framerate = framerate_;
3149 }
3150 return streams;
3151 }
3152
3153 const size_t num_temporal_layers_;
3154 const int framerate_;
3155 };
3156
3157 const int kFrameWidth = 1920;
3158 const int kFrameHeight = 1080;
3159 // 3/4 of 1920.
3160 const int kAdaptedFrameWidth = 1440;
3161 // 3/4 of 1080 rounded down to multiple of 4.
3162 const int kAdaptedFrameHeight = 808;
3163 const int kFramerate = 24;
3164
mflodmancc3d4422017-08-03 08:27:51 -07003165 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003166 // Trigger reconfigure encoder (without resetting the entire instance).
3167 VideoEncoderConfig video_encoder_config;
3168 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3169 video_encoder_config.number_of_streams = 1;
3170 video_encoder_config.video_stream_factory =
3171 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003172 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
3173 kMaxPayloadLength, false);
3174 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003175
3176 video_source_.set_adaptation_enabled(true);
3177
3178 video_source_.IncomingCapturedFrame(
3179 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003180 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003181
3182 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003183 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003184 video_source_.IncomingCapturedFrame(
3185 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003186 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003187
mflodmancc3d4422017-08-03 08:27:51 -07003188 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003189}
3190
mflodmancc3d4422017-08-03 08:27:51 -07003191TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003192 const int kFrameWidth = 1280;
3193 const int kFrameHeight = 720;
3194 const int kLowFps = 2;
3195 const int kHighFps = 30;
3196
mflodmancc3d4422017-08-03 08:27:51 -07003197 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003198
3199 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3200 max_framerate_ = kLowFps;
3201
3202 // Insert 2 seconds of 2fps video.
3203 for (int i = 0; i < kLowFps * 2; ++i) {
3204 video_source_.IncomingCapturedFrame(
3205 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3206 WaitForEncodedFrame(timestamp_ms);
3207 timestamp_ms += 1000 / kLowFps;
3208 }
3209
3210 // Make sure encoder is updated with new target.
mflodmancc3d4422017-08-03 08:27:51 -07003211 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003212 video_source_.IncomingCapturedFrame(
3213 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3214 WaitForEncodedFrame(timestamp_ms);
3215 timestamp_ms += 1000 / kLowFps;
3216
3217 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3218
3219 // Insert 30fps frames for just a little more than the forced update period.
3220 const int kVcmTimerIntervalFrames =
3221 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3222 const int kFrameIntervalMs = 1000 / kHighFps;
3223 max_framerate_ = kHighFps;
3224 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3225 video_source_.IncomingCapturedFrame(
3226 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3227 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3228 // be dropped if the encoder hans't been updated with the new higher target
3229 // framerate yet, causing it to overshoot the target bitrate and then
3230 // suffering the wrath of the media optimizer.
3231 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3232 timestamp_ms += kFrameIntervalMs;
3233 }
3234
3235 // Don expect correct measurement just yet, but it should be higher than
3236 // before.
3237 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3238
mflodmancc3d4422017-08-03 08:27:51 -07003239 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003240}
3241
mflodmancc3d4422017-08-03 08:27:51 -07003242TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003243 const int kFrameWidth = 1280;
3244 const int kFrameHeight = 720;
3245 const int kTargetBitrateBps = 1000000;
3246
3247 MockBitrateObserver bitrate_observer;
mflodmancc3d4422017-08-03 08:27:51 -07003248 video_stream_encoder_->SetBitrateObserver(&bitrate_observer);
sprang4847ae62017-06-27 07:06:52 -07003249
3250 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3251 // Initial bitrate update.
mflodmancc3d4422017-08-03 08:27:51 -07003252 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3253 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003254
3255 // Insert a first video frame, causes another bitrate update.
3256 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3257 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3258 video_source_.IncomingCapturedFrame(
3259 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3260 WaitForEncodedFrame(timestamp_ms);
3261
3262 // Next, simulate video suspension due to pacer queue overrun.
mflodmancc3d4422017-08-03 08:27:51 -07003263 video_stream_encoder_->OnBitrateUpdated(0, 0, 1);
sprang4847ae62017-06-27 07:06:52 -07003264
3265 // Skip ahead until a new periodic parameter update should have occured.
3266 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3267 fake_clock_.AdvanceTimeMicros(
3268 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3269 rtc::kNumMicrosecsPerMillisec);
3270
3271 // Bitrate observer should not be called.
3272 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3273 video_source_.IncomingCapturedFrame(
3274 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3275 ExpectDroppedFrame();
3276
mflodmancc3d4422017-08-03 08:27:51 -07003277 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003278}
ilnik6b826ef2017-06-16 06:53:48 -07003279
perkj26091b12016-09-01 01:17:40 -07003280} // namespace webrtc