blob: b143e4d54624b405419fd42bc22cf97d66d10590 [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
nisseaf916892017-01-10 07:44:26 -080015#include "webrtc/api/video/i420_buffer.h"
sprangc5d62e22017-04-02 23:53:04 -070016#include "webrtc/base/fakeclock.h"
perkj26091b12016-09-01 01:17:40 -070017#include "webrtc/base/logging.h"
sprangb1ca0732017-02-01 08:38:12 -080018#include "webrtc/media/base/videoadapter.h"
sprangfe627f32017-03-29 08:24:59 -070019#include "webrtc/modules/video_coding/codecs/vp8/temporal_layers.h"
sprang57c2fff2017-01-16 06:24:02 -080020#include "webrtc/modules/video_coding/utility/default_video_bitrate_allocator.h"
perkj803d97f2016-11-01 11:45:46 -070021#include "webrtc/system_wrappers/include/metrics_default.h"
sprang57c2fff2017-01-16 06:24:02 -080022#include "webrtc/system_wrappers/include/sleep.h"
perkj26091b12016-09-01 01:17:40 -070023#include "webrtc/test/encoder_settings.h"
24#include "webrtc/test/fake_encoder.h"
perkja49cbd32016-09-16 07:53:41 -070025#include "webrtc/test/frame_generator.h"
sprang57c2fff2017-01-16 06:24:02 -080026#include "webrtc/test/gmock.h"
kwibergac9f8762016-09-30 22:29:43 -070027#include "webrtc/test/gtest.h"
perkj26091b12016-09-01 01:17:40 -070028#include "webrtc/video/send_statistics_proxy.h"
29#include "webrtc/video/vie_encoder.h"
30
kthelgason33ce8892016-12-09 03:53:59 -080031namespace {
kthelgason33ce8892016-12-09 03:53:59 -080032// TODO(kthelgason): Lower this limit when better testing
33// on MediaCodec and fallback implementations are in place.
34const int kMinPixelsPerFrame = 320 * 180;
sprangc5d62e22017-04-02 23:53:04 -070035const int kMinFramerateFps = 2;
36const int64_t kFrameTimeoutMs = 100;
37} // namespace
kthelgason33ce8892016-12-09 03:53:59 -080038
perkj26091b12016-09-01 01:17:40 -070039namespace webrtc {
40
kthelgason876222f2016-11-29 01:44:11 -080041using DegredationPreference = VideoSendStream::DegradationPreference;
sprangb1ca0732017-02-01 08:38:12 -080042using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080043using ::testing::_;
44using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080045
perkj803d97f2016-11-01 11:45:46 -070046namespace {
asapersson5f7226f2016-11-25 04:37:00 -080047const size_t kMaxPayloadLength = 1440;
kthelgason2bc68642017-02-07 07:02:22 -080048const int kTargetBitrateBps = 1000000;
49const int kLowTargetBitrateBps = kTargetBitrateBps / 10;
50const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070051const int kDefaultFramerate = 30;
asapersson5f7226f2016-11-25 04:37:00 -080052
perkj803d97f2016-11-01 11:45:46 -070053class TestBuffer : public webrtc::I420Buffer {
54 public:
55 TestBuffer(rtc::Event* event, int width, int height)
56 : I420Buffer(width, height), event_(event) {}
57
58 private:
59 friend class rtc::RefCountedObject<TestBuffer>;
60 ~TestBuffer() override {
61 if (event_)
62 event_->Set();
63 }
64 rtc::Event* const event_;
65};
66
sprangfda496a2017-06-15 04:21:07 -070067class CpuOveruseDetectorProxy : public OveruseFrameDetector {
68 public:
69 CpuOveruseDetectorProxy(const CpuOveruseOptions& options,
70 AdaptationObserverInterface* overuse_observer,
71 EncodedFrameObserver* encoder_timing_,
72 CpuOveruseMetricsObserver* metrics_observer)
73 : OveruseFrameDetector(options,
74 overuse_observer,
75 encoder_timing_,
76 metrics_observer),
77 last_target_framerate_fps_(-1) {}
78 virtual ~CpuOveruseDetectorProxy() {}
79
80 void OnTargetFramerateUpdated(int framerate_fps) override {
81 rtc::CritScope cs(&lock_);
82 last_target_framerate_fps_ = framerate_fps;
83 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
84 }
85
86 int GetLastTargetFramerate() {
87 rtc::CritScope cs(&lock_);
88 return last_target_framerate_fps_;
89 }
90
91 private:
92 rtc::CriticalSection lock_;
93 int last_target_framerate_fps_ GUARDED_BY(lock_);
94};
95
perkj803d97f2016-11-01 11:45:46 -070096class ViEEncoderUnderTest : public ViEEncoder {
97 public:
kthelgason876222f2016-11-29 01:44:11 -080098 ViEEncoderUnderTest(SendStatisticsProxy* stats_proxy,
99 const VideoSendStream::Config::EncoderSettings& settings)
perkj803d97f2016-11-01 11:45:46 -0700100 : ViEEncoder(1 /* number_of_cores */,
101 stats_proxy,
102 settings,
103 nullptr /* pre_encode_callback */,
sprangfda496a2017-06-15 04:21:07 -0700104 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
sprangb1ca0732017-02-01 08:38:12 -0800169class AdaptingFrameForwarder : public test::FrameForwarder {
170 public:
171 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700172 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800173
174 void set_adaptation_enabled(bool enabled) {
175 rtc::CritScope cs(&crit_);
176 adaptation_enabled_ = enabled;
177 }
178
asaperssonfab67072017-04-04 05:51:49 -0700179 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800180 rtc::CritScope cs(&crit_);
181 return adaptation_enabled_;
182 }
183
asapersson09f05612017-05-15 23:40:18 -0700184 rtc::VideoSinkWants last_wants() const {
185 rtc::CritScope cs(&crit_);
186 return last_wants_;
187 }
188
sprangb1ca0732017-02-01 08:38:12 -0800189 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
190 int cropped_width = 0;
191 int cropped_height = 0;
192 int out_width = 0;
193 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700194 if (adaption_enabled()) {
195 if (adapter_.AdaptFrameResolution(
196 video_frame.width(), video_frame.height(),
197 video_frame.timestamp_us() * 1000, &cropped_width,
198 &cropped_height, &out_width, &out_height)) {
199 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
200 nullptr, out_width, out_height),
201 99, 99, kVideoRotation_0);
202 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
203 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
204 }
sprangb1ca0732017-02-01 08:38:12 -0800205 } else {
206 test::FrameForwarder::IncomingCapturedFrame(video_frame);
207 }
208 }
209
210 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
211 const rtc::VideoSinkWants& wants) override {
212 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700213 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700214 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
215 wants.max_pixel_count,
216 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800217 test::FrameForwarder::AddOrUpdateSink(sink, wants);
218 }
sprangb1ca0732017-02-01 08:38:12 -0800219 cricket::VideoAdapter adapter_;
220 bool adaptation_enabled_ GUARDED_BY(crit_);
asapersson09f05612017-05-15 23:40:18 -0700221 rtc::VideoSinkWants last_wants_ GUARDED_BY(crit_);
sprangb1ca0732017-02-01 08:38:12 -0800222};
sprangc5d62e22017-04-02 23:53:04 -0700223
224class MockableSendStatisticsProxy : public SendStatisticsProxy {
225 public:
226 MockableSendStatisticsProxy(Clock* clock,
227 const VideoSendStream::Config& config,
228 VideoEncoderConfig::ContentType content_type)
229 : SendStatisticsProxy(clock, config, content_type) {}
230
231 VideoSendStream::Stats GetStats() override {
232 rtc::CritScope cs(&lock_);
233 if (mock_stats_)
234 return *mock_stats_;
235 return SendStatisticsProxy::GetStats();
236 }
237
238 void SetMockStats(const VideoSendStream::Stats& stats) {
239 rtc::CritScope cs(&lock_);
240 mock_stats_.emplace(stats);
241 }
242
243 void ResetMockStats() {
244 rtc::CritScope cs(&lock_);
245 mock_stats_.reset();
246 }
247
248 private:
249 rtc::CriticalSection lock_;
250 rtc::Optional<VideoSendStream::Stats> mock_stats_ GUARDED_BY(lock_);
251};
252
perkj803d97f2016-11-01 11:45:46 -0700253} // namespace
254
perkj26091b12016-09-01 01:17:40 -0700255class ViEEncoderTest : public ::testing::Test {
256 public:
257 static const int kDefaultTimeoutMs = 30 * 1000;
258
259 ViEEncoderTest()
260 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700261 codec_width_(320),
262 codec_height_(240),
perkj26091b12016-09-01 01:17:40 -0700263 fake_encoder_(),
sprangc5d62e22017-04-02 23:53:04 -0700264 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700265 Clock::GetRealTimeClock(),
266 video_send_config_,
267 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700268 sink_(&fake_encoder_) {}
269
270 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700271 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700272 video_send_config_ = VideoSendStream::Config(nullptr);
273 video_send_config_.encoder_settings.encoder = &fake_encoder_;
274 video_send_config_.encoder_settings.payload_name = "FAKE";
275 video_send_config_.encoder_settings.payload_type = 125;
276
Per512ecb32016-09-23 15:52:06 +0200277 VideoEncoderConfig video_encoder_config;
perkjfa10b552016-10-02 23:45:26 -0700278 test::FillEncoderConfiguration(1, &video_encoder_config);
Erik Språng08127a92016-11-16 16:41:30 +0100279 video_encoder_config_ = video_encoder_config.Copy();
asapersson5f7226f2016-11-25 04:37:00 -0800280 ConfigureEncoder(std::move(video_encoder_config), true /* nack_enabled */);
281 }
282
283 void ConfigureEncoder(VideoEncoderConfig video_encoder_config,
284 bool nack_enabled) {
285 if (vie_encoder_)
286 vie_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700287 vie_encoder_.reset(new ViEEncoderUnderTest(
288 stats_proxy_.get(), video_send_config_.encoder_settings));
289 vie_encoder_->SetSink(&sink_, false /* rotation_applied */);
sprangc5d62e22017-04-02 23:53:04 -0700290 vie_encoder_->SetSource(
291 &video_source_,
292 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason2bc68642017-02-07 07:02:22 -0800293 vie_encoder_->SetStartBitrate(kTargetBitrateBps);
asapersson5f7226f2016-11-25 04:37:00 -0800294 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
295 kMaxPayloadLength, nack_enabled);
kthelgason2fc52542017-03-03 00:24:41 -0800296 vie_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800297 }
298
299 void ResetEncoder(const std::string& payload_name,
300 size_t num_streams,
301 size_t num_temporal_layers,
sprang317005a2017-06-08 07:12:17 -0700302 bool nack_enabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800303 video_send_config_.encoder_settings.payload_name = payload_name;
304
305 VideoEncoderConfig video_encoder_config;
306 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800307 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800308 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700309 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
310 kDefaultFramerate);
asapersson5f7226f2016-11-25 04:37:00 -0800311 ConfigureEncoder(std::move(video_encoder_config), nack_enabled);
perkj26091b12016-09-01 01:17:40 -0700312 }
313
sprang57c2fff2017-01-16 06:24:02 -0800314 VideoFrame CreateFrame(int64_t ntp_time_ms,
315 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200316 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
317 destruction_event, codec_width_, codec_height_),
318 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800319 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700320 return frame;
321 }
322
sprang57c2fff2017-01-16 06:24:02 -0800323 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700324 VideoFrame frame(
325 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
326 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800327 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700328 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700329 return frame;
330 }
331
asapersson02465b82017-04-10 01:12:52 -0700332 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700333 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700334 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
335 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700336 }
337
asapersson09f05612017-05-15 23:40:18 -0700338 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
339 const rtc::VideoSinkWants& wants2) {
340 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
341 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
342 }
343
344 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
345 const rtc::VideoSinkWants& wants2) {
346 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
347 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
348 EXPECT_GT(wants1.max_pixel_count, 0);
349 }
350
351 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
352 const rtc::VideoSinkWants& wants2) {
353 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
354 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
355 }
356
asaperssonf7e294d2017-06-13 23:25:22 -0700357 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
358 const rtc::VideoSinkWants& wants2) {
359 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
360 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
361 }
362
363 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
364 const rtc::VideoSinkWants& wants2) {
365 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
366 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
367 }
368
369 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
370 const rtc::VideoSinkWants& wants2) {
371 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
372 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
373 }
374
375 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
376 const rtc::VideoSinkWants& wants2) {
377 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
378 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
379 EXPECT_GT(wants1.max_pixel_count, 0);
380 }
381
382 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
383 const rtc::VideoSinkWants& wants2) {
384 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
385 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
386 }
387
asapersson09f05612017-05-15 23:40:18 -0700388 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
389 int pixel_count) {
390 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700391 EXPECT_LT(wants.max_pixel_count, pixel_count);
392 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700393 }
394
395 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
396 EXPECT_LT(wants.max_framerate_fps, fps);
397 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
398 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700399 }
400
asaperssonf7e294d2017-06-13 23:25:22 -0700401 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
402 int expected_fps) {
403 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
404 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
405 EXPECT_FALSE(wants.target_pixel_count);
406 }
407
perkj26091b12016-09-01 01:17:40 -0700408 class TestEncoder : public test::FakeEncoder {
409 public:
410 TestEncoder()
411 : FakeEncoder(Clock::GetRealTimeClock()),
412 continue_encode_event_(false, false) {}
413
asaperssonfab67072017-04-04 05:51:49 -0700414 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800415 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700416 return config_;
417 }
418
419 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800420 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700421 block_next_encode_ = true;
422 }
423
kthelgason876222f2016-11-29 01:44:11 -0800424 VideoEncoder::ScalingSettings GetScalingSettings() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800425 rtc::CritScope lock(&local_crit_sect_);
kthelgasonad9010c2017-02-14 00:46:51 -0800426 if (quality_scaling_)
427 return VideoEncoder::ScalingSettings(true, 1, 2);
428 return VideoEncoder::ScalingSettings(false);
kthelgason876222f2016-11-29 01:44:11 -0800429 }
430
perkjfa10b552016-10-02 23:45:26 -0700431 void ContinueEncode() { continue_encode_event_.Set(); }
432
433 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
434 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800435 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700436 EXPECT_EQ(timestamp_, timestamp);
437 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
438 }
439
kthelgason2fc52542017-03-03 00:24:41 -0800440 void SetQualityScaling(bool b) {
441 rtc::CritScope lock(&local_crit_sect_);
442 quality_scaling_ = b;
443 }
kthelgasonad9010c2017-02-14 00:46:51 -0800444
sprangfe627f32017-03-29 08:24:59 -0700445 void ForceInitEncodeFailure(bool force_failure) {
446 rtc::CritScope lock(&local_crit_sect_);
447 force_init_encode_failed_ = force_failure;
448 }
449
perkjfa10b552016-10-02 23:45:26 -0700450 private:
perkj26091b12016-09-01 01:17:40 -0700451 int32_t Encode(const VideoFrame& input_image,
452 const CodecSpecificInfo* codec_specific_info,
453 const std::vector<FrameType>* frame_types) override {
454 bool block_encode;
455 {
brandtre78d2662017-01-16 05:57:16 -0800456 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700457 EXPECT_GT(input_image.timestamp(), timestamp_);
458 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
459 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
460
461 timestamp_ = input_image.timestamp();
462 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700463 last_input_width_ = input_image.width();
464 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700465 block_encode = block_next_encode_;
466 block_next_encode_ = false;
467 }
468 int32_t result =
469 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
470 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700471 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700472 return result;
473 }
474
sprangfe627f32017-03-29 08:24:59 -0700475 int32_t InitEncode(const VideoCodec* config,
476 int32_t number_of_cores,
477 size_t max_payload_size) override {
478 int res =
479 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
480 rtc::CritScope lock(&local_crit_sect_);
481 if (config->codecType == kVideoCodecVP8 && config->VP8().tl_factory) {
482 // Simulate setting up temporal layers, in order to validate the life
483 // cycle of these objects.
484 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
485 int num_temporal_layers =
486 std::max<int>(1, config->VP8().numberOfTemporalLayers);
487 for (int i = 0; i < num_streams; ++i) {
488 allocated_temporal_layers_.emplace_back(
489 config->VP8().tl_factory->Create(i, num_temporal_layers, 42));
490 }
491 }
492 if (force_init_encode_failed_)
493 return -1;
494 return res;
495 }
496
brandtre78d2662017-01-16 05:57:16 -0800497 rtc::CriticalSection local_crit_sect_;
sprangfe627f32017-03-29 08:24:59 -0700498 bool block_next_encode_ GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700499 rtc::Event continue_encode_event_;
sprangfe627f32017-03-29 08:24:59 -0700500 uint32_t timestamp_ GUARDED_BY(local_crit_sect_) = 0;
501 int64_t ntp_time_ms_ GUARDED_BY(local_crit_sect_) = 0;
502 int last_input_width_ GUARDED_BY(local_crit_sect_) = 0;
503 int last_input_height_ GUARDED_BY(local_crit_sect_) = 0;
504 bool quality_scaling_ GUARDED_BY(local_crit_sect_) = true;
505 std::vector<std::unique_ptr<TemporalLayers>> allocated_temporal_layers_
506 GUARDED_BY(local_crit_sect_);
507 bool force_init_encode_failed_ GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700508 };
509
Per512ecb32016-09-23 15:52:06 +0200510 class TestSink : public ViEEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700511 public:
512 explicit TestSink(TestEncoder* test_encoder)
513 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
514
perkj26091b12016-09-01 01:17:40 -0700515 void WaitForEncodedFrame(int64_t expected_ntp_time) {
516 uint32_t timestamp = 0;
sprang317005a2017-06-08 07:12:17 -0700517 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700518 {
519 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800520 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700521 }
522 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
523 }
524
sprangb1ca0732017-02-01 08:38:12 -0800525 void WaitForEncodedFrame(uint32_t expected_width,
526 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700527 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
528 CheckLastFrameSizeMathces(expected_width, expected_height);
529 }
530
531 void CheckLastFrameSizeMathces(uint32_t expected_width,
532 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800533 uint32_t width = 0;
534 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800535 {
536 rtc::CritScope lock(&crit_);
537 width = last_width_;
538 height = last_height_;
539 }
540 EXPECT_EQ(expected_height, height);
541 EXPECT_EQ(expected_width, width);
542 }
543
kthelgason2fc52542017-03-03 00:24:41 -0800544 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800545
sprangc5d62e22017-04-02 23:53:04 -0700546 bool WaitForFrame(int64_t timeout_ms) {
547 return encoded_frame_event_.Wait(timeout_ms);
548 }
549
perkj26091b12016-09-01 01:17:40 -0700550 void SetExpectNoFrames() {
551 rtc::CritScope lock(&crit_);
552 expect_frames_ = false;
553 }
554
asaperssonfab67072017-04-04 05:51:49 -0700555 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200556 rtc::CritScope lock(&crit_);
557 return number_of_reconfigurations_;
558 }
559
asaperssonfab67072017-04-04 05:51:49 -0700560 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200561 rtc::CritScope lock(&crit_);
562 return min_transmit_bitrate_bps_;
563 }
564
perkj26091b12016-09-01 01:17:40 -0700565 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700566 Result OnEncodedImage(
567 const EncodedImage& encoded_image,
568 const CodecSpecificInfo* codec_specific_info,
569 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200570 rtc::CritScope lock(&crit_);
571 EXPECT_TRUE(expect_frames_);
sprangb1ca0732017-02-01 08:38:12 -0800572 last_timestamp_ = encoded_image._timeStamp;
573 last_width_ = encoded_image._encodedWidth;
574 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200575 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800576 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200577 }
578
579 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
580 int min_transmit_bitrate_bps) override {
581 rtc::CriticalSection crit_;
582 ++number_of_reconfigurations_;
583 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
584 }
585
perkj26091b12016-09-01 01:17:40 -0700586 rtc::CriticalSection crit_;
587 TestEncoder* test_encoder_;
588 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800589 uint32_t last_timestamp_ = 0;
590 uint32_t last_height_ = 0;
591 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700592 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200593 int number_of_reconfigurations_ = 0;
594 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700595 };
596
597 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100598 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200599 int codec_width_;
600 int codec_height_;
perkj26091b12016-09-01 01:17:40 -0700601 TestEncoder fake_encoder_;
sprangc5d62e22017-04-02 23:53:04 -0700602 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700603 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800604 AdaptingFrameForwarder video_source_;
perkj803d97f2016-11-01 11:45:46 -0700605 std::unique_ptr<ViEEncoderUnderTest> vie_encoder_;
perkj26091b12016-09-01 01:17:40 -0700606};
607
608TEST_F(ViEEncoderTest, EncodeOneFrame) {
perkj26091b12016-09-01 01:17:40 -0700609 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
610 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700611 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang317005a2017-06-08 07:12:17 -0700612 sink_.WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700613 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700614 vie_encoder_->Stop();
615}
616
617TEST_F(ViEEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
618 // Dropped since no target bitrate has been set.
619 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700620 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
621 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700622
perkj26091b12016-09-01 01:17:40 -0700623 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
624
perkja49cbd32016-09-16 07:53:41 -0700625 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang317005a2017-06-08 07:12:17 -0700626 sink_.WaitForEncodedFrame(2);
perkj26091b12016-09-01 01:17:40 -0700627 vie_encoder_->Stop();
628}
629
630TEST_F(ViEEncoderTest, DropsFramesWhenRateSetToZero) {
perkj26091b12016-09-01 01:17:40 -0700631 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700632 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang317005a2017-06-08 07:12:17 -0700633 sink_.WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700634
635 vie_encoder_->OnBitrateUpdated(0, 0, 0);
636 // Dropped since bitrate is zero.
perkja49cbd32016-09-16 07:53:41 -0700637 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkj26091b12016-09-01 01:17:40 -0700638
639 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700640 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
sprang317005a2017-06-08 07:12:17 -0700641 sink_.WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700642 vie_encoder_->Stop();
643}
644
645TEST_F(ViEEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
perkj26091b12016-09-01 01:17:40 -0700646 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700647 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang317005a2017-06-08 07:12:17 -0700648 sink_.WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700649
650 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700651 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700652
perkja49cbd32016-09-16 07:53:41 -0700653 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang317005a2017-06-08 07:12:17 -0700654 sink_.WaitForEncodedFrame(2);
perkj26091b12016-09-01 01:17:40 -0700655 vie_encoder_->Stop();
656}
657
658TEST_F(ViEEncoderTest, DropsFrameAfterStop) {
perkj26091b12016-09-01 01:17:40 -0700659 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
660
perkja49cbd32016-09-16 07:53:41 -0700661 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang317005a2017-06-08 07:12:17 -0700662 sink_.WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700663
664 vie_encoder_->Stop();
665 sink_.SetExpectNoFrames();
666 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700667 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
668 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700669}
670
671TEST_F(ViEEncoderTest, DropsPendingFramesOnSlowEncode) {
perkj26091b12016-09-01 01:17:40 -0700672 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
673
674 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700675 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang317005a2017-06-08 07:12:17 -0700676 sink_.WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700677 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
678 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700679 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
680 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700681 fake_encoder_.ContinueEncode();
sprang317005a2017-06-08 07:12:17 -0700682 sink_.WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700683
684 vie_encoder_->Stop();
685}
686
Per512ecb32016-09-23 15:52:06 +0200687TEST_F(ViEEncoderTest, ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
Per512ecb32016-09-23 15:52:06 +0200688 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100689 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200690
691 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200692 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang317005a2017-06-08 07:12:17 -0700693 sink_.WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100694 // The encoder will have been configured once when the first frame is
695 // received.
696 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200697
698 VideoEncoderConfig video_encoder_config;
perkjfa10b552016-10-02 23:45:26 -0700699 test::FillEncoderConfiguration(1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200700 video_encoder_config.min_transmit_bitrate_bps = 9999;
asapersson5f7226f2016-11-25 04:37:00 -0800701 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
702 kMaxPayloadLength, true /* nack_enabled */);
Per512ecb32016-09-23 15:52:06 +0200703
704 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200705 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang317005a2017-06-08 07:12:17 -0700706 sink_.WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100707 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700708 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700709
710 vie_encoder_->Stop();
711}
712
perkjfa10b552016-10-02 23:45:26 -0700713TEST_F(ViEEncoderTest, FrameResolutionChangeReconfigureEncoder) {
perkjfa10b552016-10-02 23:45:26 -0700714 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
715
716 // Capture a frame and wait for it to synchronize with the encoder thread.
717 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang317005a2017-06-08 07:12:17 -0700718 sink_.WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100719 // The encoder will have been configured once.
720 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700721 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
722 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
723
724 codec_width_ *= 2;
725 codec_height_ *= 2;
726 // Capture a frame with a higher resolution and wait for it to synchronize
727 // with the encoder thread.
728 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang317005a2017-06-08 07:12:17 -0700729 sink_.WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700730 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
731 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100732 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700733
734 vie_encoder_->Stop();
735}
736
asapersson5f7226f2016-11-25 04:37:00 -0800737TEST_F(ViEEncoderTest, Vp8ResilienceIsOffFor1S1TLWithNackEnabled) {
738 const bool kNackEnabled = true;
739 const size_t kNumStreams = 1;
740 const size_t kNumTl = 1;
sprang317005a2017-06-08 07:12:17 -0700741 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800742 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
743
744 // Capture a frame and wait for it to synchronize with the encoder thread.
745 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang317005a2017-06-08 07:12:17 -0700746 sink_.WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800747 // The encoder have been configured once when the first frame is received.
748 EXPECT_EQ(1, sink_.number_of_reconfigurations());
749 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
750 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
751 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
752 // Resilience is off for no temporal layers with nack on.
753 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
754 vie_encoder_->Stop();
755}
756
757TEST_F(ViEEncoderTest, Vp8ResilienceIsOffFor2S1TlWithNackEnabled) {
758 const bool kNackEnabled = true;
759 const size_t kNumStreams = 2;
760 const size_t kNumTl = 1;
sprang317005a2017-06-08 07:12:17 -0700761 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800762 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
763
764 // Capture a frame and wait for it to synchronize with the encoder thread.
765 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang317005a2017-06-08 07:12:17 -0700766 sink_.WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800767 // The encoder have been configured once when the first frame is received.
768 EXPECT_EQ(1, sink_.number_of_reconfigurations());
769 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
770 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
771 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
772 // Resilience is off for no temporal layers and >1 streams with nack on.
773 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
774 vie_encoder_->Stop();
775}
776
777TEST_F(ViEEncoderTest, Vp8ResilienceIsOnFor1S1TLWithNackDisabled) {
778 const bool kNackEnabled = false;
779 const size_t kNumStreams = 1;
780 const size_t kNumTl = 1;
sprang317005a2017-06-08 07:12:17 -0700781 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800782 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
783
784 // Capture a frame and wait for it to synchronize with the encoder thread.
785 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang317005a2017-06-08 07:12:17 -0700786 sink_.WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800787 // The encoder have been configured once when the first frame is received.
788 EXPECT_EQ(1, sink_.number_of_reconfigurations());
789 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
790 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
791 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
792 // Resilience is on for no temporal layers with nack off.
793 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
794 vie_encoder_->Stop();
795}
796
797TEST_F(ViEEncoderTest, Vp8ResilienceIsOnFor1S2TlWithNackEnabled) {
798 const bool kNackEnabled = true;
799 const size_t kNumStreams = 1;
800 const size_t kNumTl = 2;
sprang317005a2017-06-08 07:12:17 -0700801 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800802 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
803
804 // Capture a frame and wait for it to synchronize with the encoder thread.
805 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang317005a2017-06-08 07:12:17 -0700806 sink_.WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800807 // The encoder have been configured once when the first frame is received.
808 EXPECT_EQ(1, sink_.number_of_reconfigurations());
809 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
810 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
811 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
812 // Resilience is on for temporal layers.
813 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
814 vie_encoder_->Stop();
815}
816
perkj803d97f2016-11-01 11:45:46 -0700817TEST_F(ViEEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
818 EXPECT_TRUE(video_source_.has_sinks());
819 test::FrameForwarder new_video_source;
sprangc5d62e22017-04-02 23:53:04 -0700820 vie_encoder_->SetSource(
821 &new_video_source,
822 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -0700823 EXPECT_FALSE(video_source_.has_sinks());
824 EXPECT_TRUE(new_video_source.has_sinks());
825
826 vie_encoder_->Stop();
827}
828
829TEST_F(ViEEncoderTest, SinkWantsRotationApplied) {
830 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
831 vie_encoder_->SetSink(&sink_, true /*rotation_applied*/);
832 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
833 vie_encoder_->Stop();
834}
835
836TEST_F(ViEEncoderTest, SinkWantsFromOveruseDetector) {
asaperssond0de2952017-04-21 01:47:31 -0700837 const int kMaxDowngrades = ViEEncoder::kMaxCpuResolutionDowngrades;
perkj803d97f2016-11-01 11:45:46 -0700838 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
839
asapersson02465b82017-04-10 01:12:52 -0700840 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700841
842 int frame_width = 1280;
843 int frame_height = 720;
844
845 // Trigger CPU overuse kMaxCpuDowngrades times. Every time, ViEEncoder should
846 // request lower resolution.
asaperssond0de2952017-04-21 01:47:31 -0700847 for (int i = 1; i <= kMaxDowngrades; ++i) {
perkj803d97f2016-11-01 11:45:46 -0700848 video_source_.IncomingCapturedFrame(
849 CreateFrame(i, frame_width, frame_height));
sprang317005a2017-06-08 07:12:17 -0700850 sink_.WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -0700851
852 vie_encoder_->TriggerCpuOveruse();
853
sprang84a37592017-02-10 07:04:27 -0800854 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700855 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
perkj803d97f2016-11-01 11:45:46 -0700856 frame_width * frame_height);
asaperssond0de2952017-04-21 01:47:31 -0700857 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
858 EXPECT_EQ(i, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -0700859
860 frame_width /= 2;
861 frame_height /= 2;
862 }
863
kthelgason876222f2016-11-29 01:44:11 -0800864 // Trigger CPU overuse one more time. This should not trigger a request for
perkj803d97f2016-11-01 11:45:46 -0700865 // lower resolution.
866 rtc::VideoSinkWants current_wants = video_source_.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -0700867 video_source_.IncomingCapturedFrame(
868 CreateFrame(kMaxDowngrades + 1, frame_width, frame_height));
sprang317005a2017-06-08 07:12:17 -0700869 sink_.WaitForEncodedFrame(kMaxDowngrades + 1);
perkj803d97f2016-11-01 11:45:46 -0700870 vie_encoder_->TriggerCpuOveruse();
sprang84a37592017-02-10 07:04:27 -0800871 EXPECT_EQ(video_source_.sink_wants().target_pixel_count,
872 current_wants.target_pixel_count);
perkj803d97f2016-11-01 11:45:46 -0700873 EXPECT_EQ(video_source_.sink_wants().max_pixel_count,
874 current_wants.max_pixel_count);
asaperssond0de2952017-04-21 01:47:31 -0700875 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
876 EXPECT_EQ(kMaxDowngrades,
877 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -0700878
879 // Trigger CPU normal use.
880 vie_encoder_->TriggerCpuNormalUsage();
sprang84a37592017-02-10 07:04:27 -0800881 EXPECT_EQ(frame_width * frame_height * 5 / 3,
882 video_source_.sink_wants().target_pixel_count.value_or(0));
883 EXPECT_EQ(frame_width * frame_height * 4,
sprangc5d62e22017-04-02 23:53:04 -0700884 video_source_.sink_wants().max_pixel_count);
asaperssond0de2952017-04-21 01:47:31 -0700885 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
886 EXPECT_EQ(kMaxDowngrades + 1,
887 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -0700888
889 vie_encoder_->Stop();
890}
891
asaperssonf7e294d2017-06-13 23:25:22 -0700892TEST_F(ViEEncoderTest, TestMaxCpuResolutionDowngrades_BalancedMode_NoFpsLimit) {
893 const int kMaxDowngrades = ViEEncoder::kMaxCpuResolutionDowngrades;
894 const int kWidth = 1280;
895 const int kHeight = 720;
896 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
897
898 // Enable kBalanced preference, no initial limitation.
899 AdaptingFrameForwarder source;
900 source.set_adaptation_enabled(true);
901 vie_encoder_->SetSource(&source,
902 VideoSendStream::DegradationPreference::kBalanced);
903 VerifyNoLimitation(source.sink_wants());
904 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
905 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
906
907 // Trigger adapt down kMaxCpuDowngrades times.
908 int t = 1;
909 for (int i = 1; i <= kMaxDowngrades; ++i) {
910 source.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
911 sink_.WaitForEncodedFrame(t++);
912 vie_encoder_->TriggerCpuOveruse();
913 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
914 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
915 EXPECT_EQ(i, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
916 }
917
918 // Trigger adapt down, max cpu downgrades reach, expect no change.
919 rtc::VideoSinkWants last_wants = source.sink_wants();
920 source.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
921 sink_.WaitForEncodedFrame(t++);
922 vie_encoder_->TriggerCpuOveruse();
923 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
924 EXPECT_EQ(last_wants.max_pixel_count, source.sink_wants().max_pixel_count);
925 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
926 EXPECT_EQ(kMaxDowngrades,
927 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
928
929 // Trigger adapt up kMaxCpuDowngrades times.
930 for (int i = 1; i <= kMaxDowngrades; ++i) {
931 source.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
932 sink_.WaitForEncodedFrame(t++);
933 vie_encoder_->TriggerCpuNormalUsage();
934 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
935 EXPECT_GT(source.sink_wants().max_pixel_count, last_wants.max_pixel_count);
936 EXPECT_EQ(kMaxDowngrades + i,
937 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
938 }
939
940 VerifyNoLimitation(source.sink_wants());
941 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
942
943 vie_encoder_->Stop();
944}
sprangc5d62e22017-04-02 23:53:04 -0700945TEST_F(ViEEncoderTest, SinkWantsStoredByDegradationPreference) {
perkj803d97f2016-11-01 11:45:46 -0700946 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -0700947 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700948
sprangc5d62e22017-04-02 23:53:04 -0700949 const int kFrameWidth = 1280;
950 const int kFrameHeight = 720;
951 const int kFrameIntervalMs = 1000 / 30;
952
953 int frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -0700954
kthelgason5e13d412016-12-01 03:59:51 -0800955 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700956 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -0700957 sink_.WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700958 frame_timestamp += kFrameIntervalMs;
959
perkj803d97f2016-11-01 11:45:46 -0700960 // Trigger CPU overuse.
961 vie_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700962 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700963 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -0700964 sink_.WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700965 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -0700966
asapersson0944a802017-04-07 00:57:58 -0700967 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -0700968 // wanted resolution.
969 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
970 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
971 kFrameWidth * kFrameHeight);
972 EXPECT_EQ(std::numeric_limits<int>::max(),
973 video_source_.sink_wants().max_framerate_fps);
974
975 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -0700976 test::FrameForwarder new_video_source;
977 vie_encoder_->SetSource(
978 &new_video_source,
979 VideoSendStream::DegradationPreference::kMaintainResolution);
980
sprangc5d62e22017-04-02 23:53:04 -0700981 // Initially no degradation registered.
asapersson02465b82017-04-10 01:12:52 -0700982 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700983
sprangc5d62e22017-04-02 23:53:04 -0700984 // Force an input frame rate to be available, or the adaptation call won't
985 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -0700986 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -0700987 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -0700988 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -0700989 stats_proxy_->SetMockStats(stats);
990
991 vie_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700992 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700993 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -0700994 sink_.WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700995 frame_timestamp += kFrameIntervalMs;
996
997 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -0800998 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700999 EXPECT_EQ(std::numeric_limits<int>::max(),
1000 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001001 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001002
asapersson02465b82017-04-10 01:12:52 -07001003 // Turn off degradation completely.
sprangc5d62e22017-04-02 23:53:04 -07001004 vie_encoder_->SetSource(
1005 &new_video_source,
1006 VideoSendStream::DegradationPreference::kDegradationDisabled);
asapersson02465b82017-04-10 01:12:52 -07001007 VerifyNoLimitation(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001008
1009 vie_encoder_->TriggerCpuOveruse();
1010 new_video_source.IncomingCapturedFrame(
1011 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07001012 sink_.WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001013 frame_timestamp += kFrameIntervalMs;
1014
1015 // Still no degradation.
asapersson02465b82017-04-10 01:12:52 -07001016 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001017
1018 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
sprangc5d62e22017-04-02 23:53:04 -07001019 vie_encoder_->SetSource(
1020 &new_video_source,
1021 VideoSendStream::DegradationPreference::kMaintainFramerate);
1022 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1023 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001024 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001025 EXPECT_EQ(std::numeric_limits<int>::max(),
1026 new_video_source.sink_wants().max_framerate_fps);
1027
1028 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
1029 vie_encoder_->SetSource(
1030 &new_video_source,
1031 VideoSendStream::DegradationPreference::kMaintainResolution);
1032 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1033 EXPECT_EQ(std::numeric_limits<int>::max(),
1034 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001035 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001036
1037 vie_encoder_->Stop();
1038}
1039
asaperssonfab67072017-04-04 05:51:49 -07001040TEST_F(ViEEncoderTest, StatsTracksQualityAdaptationStats) {
perkj803d97f2016-11-01 11:45:46 -07001041 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1042
asaperssonfab67072017-04-04 05:51:49 -07001043 const int kWidth = 1280;
1044 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001045 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001046 sink_.WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001047 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1048 EXPECT_FALSE(stats.bw_limited_resolution);
1049 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1050
1051 // Trigger adapt down.
1052 vie_encoder_->TriggerQualityLow();
1053 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001054 sink_.WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001055
1056 stats = stats_proxy_->GetStats();
1057 EXPECT_TRUE(stats.bw_limited_resolution);
1058 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1059
1060 // Trigger adapt up.
1061 vie_encoder_->TriggerQualityHigh();
1062 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001063 sink_.WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001064
1065 stats = stats_proxy_->GetStats();
1066 EXPECT_FALSE(stats.bw_limited_resolution);
1067 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1068 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1069
1070 vie_encoder_->Stop();
1071}
1072
1073TEST_F(ViEEncoderTest, StatsTracksCpuAdaptationStats) {
1074 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1075
1076 const int kWidth = 1280;
1077 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001078 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001079 sink_.WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001080 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1081 EXPECT_FALSE(stats.cpu_limited_resolution);
1082 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1083
1084 // Trigger CPU overuse.
1085 vie_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001086 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001087 sink_.WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001088
1089 stats = stats_proxy_->GetStats();
1090 EXPECT_TRUE(stats.cpu_limited_resolution);
1091 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1092
1093 // Trigger CPU normal use.
1094 vie_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001095 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001096 sink_.WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001097
1098 stats = stats_proxy_->GetStats();
1099 EXPECT_FALSE(stats.cpu_limited_resolution);
1100 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001101 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001102
1103 vie_encoder_->Stop();
1104}
1105
kthelgason876222f2016-11-29 01:44:11 -08001106TEST_F(ViEEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
kthelgason876222f2016-11-29 01:44:11 -08001107 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1108
asaperssonfab67072017-04-04 05:51:49 -07001109 const int kWidth = 1280;
1110 const int kHeight = 720;
1111 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001112 sink_.WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001113 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001114 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001115 EXPECT_FALSE(stats.cpu_limited_resolution);
1116 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1117
asaperssonfab67072017-04-04 05:51:49 -07001118 // Trigger CPU overuse.
kthelgason876222f2016-11-29 01:44:11 -08001119 vie_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001120 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001121 sink_.WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001122 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001123 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001124 EXPECT_TRUE(stats.cpu_limited_resolution);
1125 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1126
1127 // Set new source with adaptation still enabled.
1128 test::FrameForwarder new_video_source;
sprangc5d62e22017-04-02 23:53:04 -07001129 vie_encoder_->SetSource(
1130 &new_video_source,
1131 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001132
asaperssonfab67072017-04-04 05:51:49 -07001133 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001134 sink_.WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001135 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001136 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001137 EXPECT_TRUE(stats.cpu_limited_resolution);
1138 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1139
1140 // Set adaptation disabled.
1141 vie_encoder_->SetSource(
1142 &new_video_source,
sprangc5d62e22017-04-02 23:53:04 -07001143 VideoSendStream::DegradationPreference::kDegradationDisabled);
kthelgason876222f2016-11-29 01:44:11 -08001144
asaperssonfab67072017-04-04 05:51:49 -07001145 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001146 sink_.WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001147 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001148 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001149 EXPECT_FALSE(stats.cpu_limited_resolution);
1150 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1151
1152 // Set adaptation back to enabled.
sprangc5d62e22017-04-02 23:53:04 -07001153 vie_encoder_->SetSource(
1154 &new_video_source,
1155 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001156
asaperssonfab67072017-04-04 05:51:49 -07001157 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001158 sink_.WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001159 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001160 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001161 EXPECT_TRUE(stats.cpu_limited_resolution);
1162 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1163
asaperssonfab67072017-04-04 05:51:49 -07001164 // Trigger CPU normal use.
kthelgason876222f2016-11-29 01:44:11 -08001165 vie_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001166 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001167 sink_.WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001168 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001169 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001170 EXPECT_FALSE(stats.cpu_limited_resolution);
1171 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001172 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001173
1174 vie_encoder_->Stop();
1175}
1176
1177TEST_F(ViEEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
kthelgason876222f2016-11-29 01:44:11 -08001178 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1179
asaperssonfab67072017-04-04 05:51:49 -07001180 const int kWidth = 1280;
1181 const int kHeight = 720;
1182 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001183 sink_.WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001184 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001185 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001186 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001187 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001188
1189 // Set new source with adaptation still enabled.
1190 test::FrameForwarder new_video_source;
1191 vie_encoder_->SetSource(&new_video_source,
1192 VideoSendStream::DegradationPreference::kBalanced);
1193
asaperssonfab67072017-04-04 05:51:49 -07001194 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001195 sink_.WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001196 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001197 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001198 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001199 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001200
asaperssonfab67072017-04-04 05:51:49 -07001201 // Trigger adapt down.
kthelgason876222f2016-11-29 01:44:11 -08001202 vie_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001203 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001204 sink_.WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001205 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001206 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001207 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001208 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001209
asaperssonfab67072017-04-04 05:51:49 -07001210 // Set new source with adaptation still enabled.
kthelgason876222f2016-11-29 01:44:11 -08001211 vie_encoder_->SetSource(&new_video_source,
1212 VideoSendStream::DegradationPreference::kBalanced);
1213
asaperssonfab67072017-04-04 05:51:49 -07001214 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001215 sink_.WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001216 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001217 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001218 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001219 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001220
asapersson02465b82017-04-10 01:12:52 -07001221 // Disable resolution scaling.
kthelgason876222f2016-11-29 01:44:11 -08001222 vie_encoder_->SetSource(
1223 &new_video_source,
1224 VideoSendStream::DegradationPreference::kMaintainResolution);
1225
asaperssonfab67072017-04-04 05:51:49 -07001226 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001227 sink_.WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001228 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001229 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001230 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001231 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1232 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001233
1234 vie_encoder_->Stop();
1235}
1236
asapersson36e9eb42017-03-31 05:29:12 -07001237TEST_F(ViEEncoderTest, QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1238 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1239
1240 const int kWidth = 1280;
1241 const int kHeight = 720;
1242 video_source_.set_adaptation_enabled(true);
1243 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001244 sink_.WaitForEncodedFrame(1);
asapersson36e9eb42017-03-31 05:29:12 -07001245 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1246 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1247 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1248
1249 // Trigger adapt down.
1250 vie_encoder_->TriggerQualityLow();
1251 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001252 sink_.WaitForEncodedFrame(2);
asapersson36e9eb42017-03-31 05:29:12 -07001253 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1254 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1255 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1256
1257 // Trigger overuse.
1258 vie_encoder_->TriggerCpuOveruse();
1259 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001260 sink_.WaitForEncodedFrame(3);
asapersson36e9eb42017-03-31 05:29:12 -07001261 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1262 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1263 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1264
1265 // Set source with adaptation still enabled but quality scaler is off.
1266 fake_encoder_.SetQualityScaling(false);
sprangc5d62e22017-04-02 23:53:04 -07001267 vie_encoder_->SetSource(
1268 &video_source_,
1269 VideoSendStream::DegradationPreference::kMaintainFramerate);
asapersson36e9eb42017-03-31 05:29:12 -07001270
1271 video_source_.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001272 sink_.WaitForEncodedFrame(4);
asapersson36e9eb42017-03-31 05:29:12 -07001273 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1274 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1275 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1276
1277 vie_encoder_->Stop();
1278}
1279
asapersson02465b82017-04-10 01:12:52 -07001280TEST_F(ViEEncoderTest, StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
perkj803d97f2016-11-01 11:45:46 -07001281 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1282
asapersson0944a802017-04-07 00:57:58 -07001283 const int kWidth = 1280;
1284 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001285 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001286
asaperssonfab67072017-04-04 05:51:49 -07001287 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001288 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001289 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001290 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001291 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001292 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1293
asapersson02465b82017-04-10 01:12:52 -07001294 // Trigger CPU overuse, should now adapt down.
sprang84a37592017-02-10 07:04:27 -08001295 vie_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001296 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001297 sink_.WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001298 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001299 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001300 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001301 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1302
1303 // Set new source with adaptation still enabled.
1304 test::FrameForwarder new_video_source;
sprangc5d62e22017-04-02 23:53:04 -07001305 vie_encoder_->SetSource(
1306 &new_video_source,
1307 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001308
1309 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001310 CreateFrame(sequence, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001311 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001312 stats = stats_proxy_->GetStats();
1313 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001314 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001315 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1316
sprangc5d62e22017-04-02 23:53:04 -07001317 // Set cpu adaptation by frame dropping.
perkj803d97f2016-11-01 11:45:46 -07001318 vie_encoder_->SetSource(
1319 &new_video_source,
1320 VideoSendStream::DegradationPreference::kMaintainResolution);
1321 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001322 CreateFrame(sequence, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001323 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001324 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001325 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001326 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001327 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001328 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1329
sprangc5d62e22017-04-02 23:53:04 -07001330 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001331 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001332 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1333 mock_stats.input_frame_rate = 30;
1334 stats_proxy_->SetMockStats(mock_stats);
1335 vie_encoder_->TriggerCpuOveruse();
1336 stats_proxy_->ResetMockStats();
1337
1338 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001339 CreateFrame(sequence, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001340 sink_.WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001341
1342 // Framerate now adapted.
1343 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001344 EXPECT_FALSE(stats.cpu_limited_resolution);
1345 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001346 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1347
1348 // Disable CPU adaptation.
1349 vie_encoder_->SetSource(
1350 &new_video_source,
1351 VideoSendStream::DegradationPreference::kDegradationDisabled);
1352 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001353 CreateFrame(sequence, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001354 sink_.WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001355
1356 stats = stats_proxy_->GetStats();
1357 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001358 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001359 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1360
1361 // Try to trigger overuse. Should not succeed.
1362 stats_proxy_->SetMockStats(mock_stats);
1363 vie_encoder_->TriggerCpuOveruse();
1364 stats_proxy_->ResetMockStats();
1365
1366 stats = stats_proxy_->GetStats();
1367 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001368 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001369 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1370
1371 // Switch back the source with resolution adaptation enabled.
1372 vie_encoder_->SetSource(
1373 &video_source_,
1374 VideoSendStream::DegradationPreference::kMaintainFramerate);
asaperssonfab67072017-04-04 05:51:49 -07001375 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001376 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001377 stats = stats_proxy_->GetStats();
1378 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001379 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001380 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001381
1382 // Trigger CPU normal usage.
1383 vie_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001384 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001385 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001386 stats = stats_proxy_->GetStats();
1387 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001388 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001389 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1390
1391 // Back to the source with adaptation off, set it back to maintain-resolution.
1392 vie_encoder_->SetSource(
1393 &new_video_source,
1394 VideoSendStream::DegradationPreference::kMaintainResolution);
1395 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001396 CreateFrame(sequence, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001397 sink_.WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001398 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001399 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001400 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001401 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001402 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1403
1404 // Trigger CPU normal usage.
1405 vie_encoder_->TriggerCpuNormalUsage();
1406 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001407 CreateFrame(sequence, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001408 sink_.WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001409 stats = stats_proxy_->GetStats();
1410 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001411 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001412 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001413 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001414
1415 vie_encoder_->Stop();
1416}
1417
Erik Språng08127a92016-11-16 16:41:30 +01001418TEST_F(ViEEncoderTest, StatsTracksPreferredBitrate) {
Erik Språng08127a92016-11-16 16:41:30 +01001419 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1420
asaperssonfab67072017-04-04 05:51:49 -07001421 const int kWidth = 1280;
1422 const int kHeight = 720;
1423 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001424 sink_.WaitForEncodedFrame(1);
Erik Språng08127a92016-11-16 16:41:30 +01001425
1426 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1427 EXPECT_EQ(video_encoder_config_.max_bitrate_bps,
1428 stats.preferred_media_bitrate_bps);
1429
1430 vie_encoder_->Stop();
1431}
1432
kthelgason876222f2016-11-29 01:44:11 -08001433TEST_F(ViEEncoderTest, ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001434 const int kWidth = 1280;
1435 const int kHeight = 720;
kthelgason876222f2016-11-29 01:44:11 -08001436 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1437
asaperssonfab67072017-04-04 05:51:49 -07001438 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001439 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001440
asaperssonfab67072017-04-04 05:51:49 -07001441 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001442 sink_.WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001443
asaperssonfab67072017-04-04 05:51:49 -07001444 // Trigger scale down.
kthelgason5e13d412016-12-01 03:59:51 -08001445 vie_encoder_->TriggerQualityLow();
1446
asaperssonfab67072017-04-04 05:51:49 -07001447 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001448 sink_.WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001449
kthelgason876222f2016-11-29 01:44:11 -08001450 // Expect a scale down.
1451 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001452 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001453
asapersson02465b82017-04-10 01:12:52 -07001454 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001455 test::FrameForwarder new_video_source;
1456 vie_encoder_->SetSource(
1457 &new_video_source,
1458 VideoSendStream::DegradationPreference::kMaintainResolution);
1459
asaperssonfab67072017-04-04 05:51:49 -07001460 // Trigger scale down.
kthelgason876222f2016-11-29 01:44:11 -08001461 vie_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001462 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001463 sink_.WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001464
asaperssonfab67072017-04-04 05:51:49 -07001465 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001466 EXPECT_EQ(std::numeric_limits<int>::max(),
1467 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001468
asaperssonfab67072017-04-04 05:51:49 -07001469 // Trigger scale up.
kthelgason876222f2016-11-29 01:44:11 -08001470 vie_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001471 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001472 sink_.WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001473
asapersson02465b82017-04-10 01:12:52 -07001474 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001475 EXPECT_EQ(std::numeric_limits<int>::max(),
1476 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001477
1478 vie_encoder_->Stop();
1479}
1480
asapersson02465b82017-04-10 01:12:52 -07001481TEST_F(ViEEncoderTest, SkipsSameAdaptDownRequest_MaintainFramerateMode) {
1482 const int kWidth = 1280;
1483 const int kHeight = 720;
1484 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1485
1486 // Enable kMaintainFramerate preference, no initial limitation.
1487 test::FrameForwarder source;
1488 vie_encoder_->SetSource(
1489 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1490
1491 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001492 sink_.WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001493 VerifyNoLimitation(source.sink_wants());
1494 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1495 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1496
1497 // Trigger adapt down, expect scaled down resolution.
1498 vie_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001499 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001500 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1501 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1502 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1503
1504 // Trigger adapt down for same input resolution, expect no change.
1505 vie_encoder_->TriggerCpuOveruse();
1506 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1507 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1508 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1509
1510 vie_encoder_->Stop();
1511}
1512
asaperssonf7e294d2017-06-13 23:25:22 -07001513TEST_F(ViEEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
1514 const int kWidth = 1280;
1515 const int kHeight = 720;
1516 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1517
1518 // Enable kBalanced preference, no initial limitation.
1519 test::FrameForwarder source;
1520 vie_encoder_->SetSource(&source,
1521 VideoSendStream::DegradationPreference::kBalanced);
1522 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1523 sink_.WaitForEncodedFrame(1);
1524 VerifyNoLimitation(source.sink_wants());
1525
1526 // Trigger adapt down, expect scaled down resolution.
1527 vie_encoder_->TriggerQualityLow();
1528 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1529 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1530 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1531 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1532
1533 // Trigger adapt down for same input resolution, expect no change.
1534 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1535 sink_.WaitForEncodedFrame(2);
1536 vie_encoder_->TriggerQualityLow();
1537 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1538 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1539 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1540
1541 // Trigger adapt down for larger input resolution, expect no change.
1542 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1543 sink_.WaitForEncodedFrame(3);
1544 vie_encoder_->TriggerQualityLow();
1545 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1546 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1547 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1548
1549 vie_encoder_->Stop();
1550}
1551
asapersson02465b82017-04-10 01:12:52 -07001552TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_MaintainFramerateMode) {
1553 const int kWidth = 1280;
1554 const int kHeight = 720;
1555 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1556
1557 // Enable kMaintainFramerate preference, no initial limitation.
1558 test::FrameForwarder source;
1559 vie_encoder_->SetSource(
1560 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1561
1562 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001563 sink_.WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001564 VerifyNoLimitation(source.sink_wants());
1565 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1566 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1567
1568 // Trigger adapt up, expect no change.
1569 vie_encoder_->TriggerCpuNormalUsage();
1570 VerifyNoLimitation(source.sink_wants());
1571 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1572 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1573
1574 vie_encoder_->Stop();
1575}
1576
1577TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_MaintainResolutionMode) {
1578 const int kWidth = 1280;
1579 const int kHeight = 720;
1580 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1581
1582 // Enable kMaintainResolution preference, no initial limitation.
1583 test::FrameForwarder source;
1584 vie_encoder_->SetSource(
1585 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
1586
1587 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001588 sink_.WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001589 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001590 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001591 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1592
1593 // Trigger adapt up, expect no change.
1594 vie_encoder_->TriggerCpuNormalUsage();
1595 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001596 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001597 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1598
1599 vie_encoder_->Stop();
1600}
1601
asaperssonf7e294d2017-06-13 23:25:22 -07001602TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
1603 const int kWidth = 1280;
1604 const int kHeight = 720;
1605 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1606
1607 // Enable kBalanced preference, no initial limitation.
1608 test::FrameForwarder source;
1609 vie_encoder_->SetSource(&source,
1610 VideoSendStream::DegradationPreference::kBalanced);
1611
1612 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1613 sink_.WaitForEncodedFrame(kWidth, kHeight);
1614 VerifyNoLimitation(source.sink_wants());
1615 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1616 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1617 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1618
1619 // Trigger adapt up, expect no change.
1620 vie_encoder_->TriggerQualityHigh();
1621 VerifyNoLimitation(source.sink_wants());
1622 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1623 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1624 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1625
1626 vie_encoder_->Stop();
1627}
1628
asapersson09f05612017-05-15 23:40:18 -07001629TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
1630 const int kWidth = 1280;
1631 const int kHeight = 720;
1632 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1633
1634 // Enable kDegradationDisabled preference, no initial limitation.
1635 test::FrameForwarder source;
1636 vie_encoder_->SetSource(
1637 &source, VideoSendStream::DegradationPreference::kDegradationDisabled);
1638
1639 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1640 sink_.WaitForEncodedFrame(kWidth, kHeight);
1641 VerifyNoLimitation(source.sink_wants());
1642 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1643 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1644 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1645
1646 // Trigger adapt up, expect no change.
1647 vie_encoder_->TriggerQualityHigh();
1648 VerifyNoLimitation(source.sink_wants());
1649 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1650 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1651 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1652
1653 vie_encoder_->Stop();
1654}
1655
asapersson02465b82017-04-10 01:12:52 -07001656TEST_F(ViEEncoderTest, AdaptsResolutionForLowQuality_MaintainFramerateMode) {
1657 const int kWidth = 1280;
1658 const int kHeight = 720;
1659 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1660
1661 // Enable kMaintainFramerate preference, no initial limitation.
1662 AdaptingFrameForwarder source;
1663 source.set_adaptation_enabled(true);
1664 vie_encoder_->SetSource(
1665 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1666
1667 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001668 sink_.WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001669 VerifyNoLimitation(source.sink_wants());
1670 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1671 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1672
1673 // Trigger adapt down, expect scaled down resolution.
1674 vie_encoder_->TriggerQualityLow();
1675 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001676 sink_.WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001677 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001678 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1679 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1680
1681 // Trigger adapt up, expect no restriction.
1682 vie_encoder_->TriggerQualityHigh();
1683 VerifyNoLimitation(source.sink_wants());
1684 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1685 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1686 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1687
1688 vie_encoder_->Stop();
1689}
1690
asapersson09f05612017-05-15 23:40:18 -07001691TEST_F(ViEEncoderTest, AdaptsFramerateForLowQuality_MaintainResolutionMode) {
1692 const int kWidth = 1280;
1693 const int kHeight = 720;
1694 const int kInputFps = 30;
1695 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1696
1697 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1698 stats.input_frame_rate = kInputFps;
1699 stats_proxy_->SetMockStats(stats);
1700
1701 // Expect no scaling to begin with (preference: kMaintainFramerate).
1702 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1703 sink_.WaitForEncodedFrame(1);
1704 VerifyNoLimitation(video_source_.sink_wants());
1705
1706 // Trigger adapt down, expect scaled down resolution.
1707 vie_encoder_->TriggerQualityLow();
1708 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1709 sink_.WaitForEncodedFrame(2);
1710 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1711
1712 // Enable kMaintainResolution preference.
1713 test::FrameForwarder new_video_source;
1714 vie_encoder_->SetSource(
1715 &new_video_source,
1716 VideoSendStream::DegradationPreference::kMaintainResolution);
1717 VerifyNoLimitation(new_video_source.sink_wants());
1718
1719 // Trigger adapt down, expect reduced framerate.
1720 vie_encoder_->TriggerQualityLow();
1721 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1722 sink_.WaitForEncodedFrame(3);
1723 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1724
1725 // Trigger adapt up, expect no restriction.
1726 vie_encoder_->TriggerQualityHigh();
1727 VerifyNoLimitation(new_video_source.sink_wants());
1728
1729 vie_encoder_->Stop();
1730}
1731
asaperssond0de2952017-04-21 01:47:31 -07001732TEST_F(ViEEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
1733 const int kWidth = 1280;
1734 const int kHeight = 720;
1735 const size_t kNumFrames = 10;
1736
kthelgason5e13d412016-12-01 03:59:51 -08001737 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1738
asaperssond0de2952017-04-21 01:47:31 -07001739 // Enable adapter, expected input resolutions when downscaling:
1740 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (min resolution limit)
1741 video_source_.set_adaptation_enabled(true);
1742
1743 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1744 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1745
1746 int downscales = 0;
1747 for (size_t i = 1; i <= kNumFrames; i++) {
1748 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001749 sink_.WaitForEncodedFrame(i);
asaperssond0de2952017-04-21 01:47:31 -07001750
asaperssonfab67072017-04-04 05:51:49 -07001751 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001752 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
kthelgason5e13d412016-12-01 03:59:51 -08001753 vie_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001754 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001755
1756 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1757 ++downscales;
1758
1759 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1760 EXPECT_EQ(downscales,
1761 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1762 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001763 }
asaperssond0de2952017-04-21 01:47:31 -07001764 vie_encoder_->Stop();
1765}
1766
1767TEST_F(ViEEncoderTest,
1768 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1769 const int kWidth = 1280;
1770 const int kHeight = 720;
1771 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1772
1773 // Enable kMaintainFramerate preference, no initial limitation.
1774 AdaptingFrameForwarder source;
1775 source.set_adaptation_enabled(true);
1776 vie_encoder_->SetSource(
1777 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1778
1779 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001780 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001781 VerifyNoLimitation(source.sink_wants());
1782 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1783 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1784
1785 // Trigger adapt down, expect scaled down resolution.
1786 vie_encoder_->TriggerCpuOveruse();
1787 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001788 sink_.WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001789 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001790 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1791 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1792
1793 // Trigger adapt up, expect no restriction.
1794 vie_encoder_->TriggerCpuNormalUsage();
1795 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001796 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001797 VerifyNoLimitation(source.sink_wants());
1798 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1799 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1800
1801 // Trigger adapt down, expect scaled down resolution.
1802 vie_encoder_->TriggerCpuOveruse();
1803 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001804 sink_.WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07001805 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001806 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1807 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1808
1809 // Trigger adapt up, expect no restriction.
1810 vie_encoder_->TriggerCpuNormalUsage();
asapersson09f05612017-05-15 23:40:18 -07001811 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1812 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001813 VerifyNoLimitation(source.sink_wants());
1814 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1815 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1816
1817 vie_encoder_->Stop();
1818}
1819
1820TEST_F(ViEEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07001821 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
1822 const int kWidth = 1280;
1823 const int kHeight = 720;
1824 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1825
1826 // Enable kBalanced preference, no initial limitation.
1827 AdaptingFrameForwarder source;
1828 source.set_adaptation_enabled(true);
1829 vie_encoder_->SetSource(&source,
1830 VideoSendStream::DegradationPreference::kBalanced);
1831
1832 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1833 sink_.WaitForEncodedFrame(kWidth, kHeight);
1834 VerifyNoLimitation(source.sink_wants());
1835 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1836 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1837
1838 // Trigger adapt down, expect scaled down resolution.
1839 vie_encoder_->TriggerQualityLow();
1840 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1841 sink_.WaitForEncodedFrame(2);
1842 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1843 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1844 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1845
1846 // Trigger adapt up, expect no restriction.
1847 vie_encoder_->TriggerQualityHigh();
1848 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1849 sink_.WaitForEncodedFrame(kWidth, kHeight);
1850 VerifyNoLimitation(source.sink_wants());
1851 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1852 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1853
1854 // Trigger adapt down, expect scaled down resolution.
1855 vie_encoder_->TriggerQualityLow();
1856 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
1857 sink_.WaitForEncodedFrame(4);
1858 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1859 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1860 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1861
1862 // Trigger adapt up, expect no restriction.
1863 vie_encoder_->TriggerQualityHigh();
1864 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1865 sink_.WaitForEncodedFrame(kWidth, kHeight);
1866 VerifyNoLimitation(source.sink_wants());
1867 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1868 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1869
1870 vie_encoder_->Stop();
1871}
1872
1873TEST_F(ViEEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001874 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
1875 const int kWidth = 1280;
1876 const int kHeight = 720;
1877 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1878
1879 // Enable kMaintainFramerate preference, no initial limitation.
1880 AdaptingFrameForwarder source;
1881 source.set_adaptation_enabled(true);
1882 vie_encoder_->SetSource(
1883 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1884
1885 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001886 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001887 VerifyNoLimitation(source.sink_wants());
1888 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1889 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1890 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1891 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1892
1893 // Trigger cpu adapt down, expect scaled down resolution (960x540).
1894 vie_encoder_->TriggerCpuOveruse();
1895 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001896 sink_.WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001897 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001898 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1899 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1900 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1901 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1902
1903 // Trigger cpu adapt down, expect scaled down resolution (640x360).
1904 vie_encoder_->TriggerCpuOveruse();
1905 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001906 sink_.WaitForEncodedFrame(3);
asapersson09f05612017-05-15 23:40:18 -07001907 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
1908 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07001909 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1910 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1911 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1912 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1913
1914 // Trigger cpu adapt down, max cpu downgrades reached, expect no change.
1915 vie_encoder_->TriggerCpuOveruse();
1916 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001917 sink_.WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07001918 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07001919 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1920 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1921 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1922 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1923
1924 // Trigger quality adapt down, expect scaled down resolution (480x270).
1925 vie_encoder_->TriggerQualityLow();
1926 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001927 sink_.WaitForEncodedFrame(5);
asapersson09f05612017-05-15 23:40:18 -07001928 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001929 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1930 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1931 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1932 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1933
1934 // Trigger cpu adapt up, expect upscaled resolution (640x360).
1935 vie_encoder_->TriggerCpuNormalUsage();
1936 source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001937 sink_.WaitForEncodedFrame(6);
asapersson09f05612017-05-15 23:40:18 -07001938 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001939 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1940 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1941 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1942 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1943
1944 // Trigger cpu adapt up, expect upscaled resolution (960x540).
1945 vie_encoder_->TriggerCpuNormalUsage();
1946 source.IncomingCapturedFrame(CreateFrame(7, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001947 sink_.WaitForEncodedFrame(7);
asapersson09f05612017-05-15 23:40:18 -07001948 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001949 last_wants = source.sink_wants();
1950 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1951 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1952 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1953 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1954
1955 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
1956 vie_encoder_->TriggerCpuNormalUsage();
1957 source.IncomingCapturedFrame(CreateFrame(8, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001958 sink_.WaitForEncodedFrame(8);
asapersson09f05612017-05-15 23:40:18 -07001959 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07001960 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1961 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1962 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1963 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1964
1965 // Trigger quality adapt up, expect no restriction (1280x720).
1966 vie_encoder_->TriggerQualityHigh();
1967 source.IncomingCapturedFrame(CreateFrame(9, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001968 sink_.WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07001969 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001970 VerifyNoLimitation(source.sink_wants());
1971 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1972 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1973 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1974 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08001975
1976 vie_encoder_->Stop();
1977}
1978
asaperssonf4e44af2017-04-19 02:01:06 -07001979TEST_F(ViEEncoderTest, CpuLimitedHistogramIsReported) {
sprang317005a2017-06-08 07:12:17 -07001980 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001981 const int kWidth = 640;
1982 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07001983
1984 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07001985 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001986 sink_.WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07001987 }
1988
1989 vie_encoder_->TriggerCpuOveruse();
1990 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07001991 video_source_.IncomingCapturedFrame(CreateFrame(
1992 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001993 sink_.WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples +
1994 i);
perkj803d97f2016-11-01 11:45:46 -07001995 }
1996
1997 vie_encoder_->Stop();
sprangf8ee65e2017-02-28 08:49:33 -08001998 vie_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07001999 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002000
perkj803d97f2016-11-01 11:45:46 -07002001 EXPECT_EQ(1,
2002 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2003 EXPECT_EQ(
2004 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2005}
2006
asaperssonf4e44af2017-04-19 02:01:06 -07002007TEST_F(ViEEncoderTest, CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2008 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2009 const int kWidth = 640;
2010 const int kHeight = 360;
2011
2012 vie_encoder_->SetSource(
2013 &video_source_,
2014 VideoSendStream::DegradationPreference::kDegradationDisabled);
2015
2016 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2017 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07002018 sink_.WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002019 }
2020
2021 vie_encoder_->Stop();
2022 vie_encoder_.reset();
2023 stats_proxy_.reset();
2024
2025 EXPECT_EQ(0,
2026 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2027}
2028
sprang57c2fff2017-01-16 06:24:02 -08002029TEST_F(ViEEncoderTest, CallsBitrateObserver) {
2030 class MockBitrateObserver : public VideoBitrateAllocationObserver {
2031 public:
2032 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const BitrateAllocation&));
2033 } bitrate_observer;
2034 vie_encoder_->SetBitrateObserver(&bitrate_observer);
2035
2036 const int kDefaultFps = 30;
2037 const BitrateAllocation expected_bitrate =
2038 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002039 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002040
2041 // First called on bitrate updated, then again on first frame.
2042 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2043 .Times(2);
kthelgason2bc68642017-02-07 07:02:22 -08002044 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002045
2046 const int64_t kStartTimeMs = 1;
2047 video_source_.IncomingCapturedFrame(
2048 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang317005a2017-06-08 07:12:17 -07002049 sink_.WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002050
2051 // Not called on second frame.
2052 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2053 .Times(0);
2054 video_source_.IncomingCapturedFrame(
2055 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang317005a2017-06-08 07:12:17 -07002056 sink_.WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002057
2058 // Called after a process interval.
2059 const int64_t kProcessIntervalMs =
2060 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang317005a2017-06-08 07:12:17 -07002061 // TODO(sprang): ViEEncoder should die and/or get injectable clock.
2062 // Sleep for one processing interval plus one frame to avoid flakiness.
2063 SleepMs(kProcessIntervalMs + 1000 / kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002064 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2065 .Times(1);
2066 video_source_.IncomingCapturedFrame(CreateFrame(
2067 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang317005a2017-06-08 07:12:17 -07002068 sink_.WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002069
2070 vie_encoder_->Stop();
2071}
2072
sprangfda496a2017-06-15 04:21:07 -07002073TEST_F(ViEEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2074 const int kFrameWidth = 1280;
2075 const int kFrameHeight = 720;
2076 const int kFramerate = 24;
2077
2078 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2079 test::FrameForwarder source;
2080 vie_encoder_->SetSource(
2081 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2082
2083 // Insert a single frame, triggering initial configuration.
2084 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2085 vie_encoder_->WaitUntilTaskQueueIsIdle();
2086
2087 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2088 kDefaultFramerate);
2089
2090 // Trigger reconfigure encoder (without resetting the entire instance).
2091 VideoEncoderConfig video_encoder_config;
2092 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2093 video_encoder_config.number_of_streams = 1;
2094 video_encoder_config.video_stream_factory =
2095 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2096 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2097 kMaxPayloadLength, false);
2098 vie_encoder_->WaitUntilTaskQueueIsIdle();
2099
2100 // Detector should be updated with fps limit from codec config.
2101 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2102 kFramerate);
2103
2104 // Trigger overuse, max framerate should be reduced.
2105 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2106 stats.input_frame_rate = kFramerate;
2107 stats_proxy_->SetMockStats(stats);
2108 vie_encoder_->TriggerCpuOveruse();
2109 vie_encoder_->WaitUntilTaskQueueIsIdle();
2110 int adapted_framerate =
2111 vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2112 EXPECT_LT(adapted_framerate, kFramerate);
2113
2114 // Trigger underuse, max framerate should go back to codec configured fps.
2115 // Set extra low fps, to make sure it's actually reset, not just incremented.
2116 stats = stats_proxy_->GetStats();
2117 stats.input_frame_rate = adapted_framerate / 2;
2118 stats_proxy_->SetMockStats(stats);
2119 vie_encoder_->TriggerCpuNormalUsage();
2120 vie_encoder_->WaitUntilTaskQueueIsIdle();
2121 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2122 kFramerate);
2123
2124 vie_encoder_->Stop();
2125}
2126
2127TEST_F(ViEEncoderTest, OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2128 const int kFrameWidth = 1280;
2129 const int kFrameHeight = 720;
2130 const int kLowFramerate = 15;
2131 const int kHighFramerate = 25;
2132
2133 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2134 test::FrameForwarder source;
2135 vie_encoder_->SetSource(
2136 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2137
2138 // Trigger initial configuration.
2139 VideoEncoderConfig video_encoder_config;
2140 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2141 video_encoder_config.number_of_streams = 1;
2142 video_encoder_config.video_stream_factory =
2143 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2144 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2145 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2146 kMaxPayloadLength, false);
2147 vie_encoder_->WaitUntilTaskQueueIsIdle();
2148
2149 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2150 kLowFramerate);
2151
2152 // Trigger overuse, max framerate should be reduced.
2153 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2154 stats.input_frame_rate = kLowFramerate;
2155 stats_proxy_->SetMockStats(stats);
2156 vie_encoder_->TriggerCpuOveruse();
2157 vie_encoder_->WaitUntilTaskQueueIsIdle();
2158 int adapted_framerate =
2159 vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2160 EXPECT_LT(adapted_framerate, kLowFramerate);
2161
2162 // Reconfigure the encoder with a new (higher max framerate), max fps should
2163 // still respect the adaptation.
2164 video_encoder_config.video_stream_factory =
2165 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2166 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2167 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2168 kMaxPayloadLength, false);
2169 vie_encoder_->WaitUntilTaskQueueIsIdle();
2170
2171 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2172 adapted_framerate);
2173
2174 // Trigger underuse, max framerate should go back to codec configured fps.
2175 stats = stats_proxy_->GetStats();
2176 stats.input_frame_rate = adapted_framerate;
2177 stats_proxy_->SetMockStats(stats);
2178 vie_encoder_->TriggerCpuNormalUsage();
2179 vie_encoder_->WaitUntilTaskQueueIsIdle();
2180 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2181 kHighFramerate);
2182
2183 vie_encoder_->Stop();
2184}
2185
2186TEST_F(ViEEncoderTest, OveruseDetectorUpdatedOnDegradationPreferenceChange) {
2187 const int kFrameWidth = 1280;
2188 const int kFrameHeight = 720;
2189 const int kFramerate = 24;
2190
2191 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2192 test::FrameForwarder source;
2193 vie_encoder_->SetSource(
2194 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2195
2196 // Trigger initial configuration.
2197 VideoEncoderConfig video_encoder_config;
2198 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2199 video_encoder_config.number_of_streams = 1;
2200 video_encoder_config.video_stream_factory =
2201 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2202 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2203 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2204 kMaxPayloadLength, false);
2205 vie_encoder_->WaitUntilTaskQueueIsIdle();
2206
2207 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2208 kFramerate);
2209
2210 // Trigger overuse, max framerate should be reduced.
2211 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2212 stats.input_frame_rate = kFramerate;
2213 stats_proxy_->SetMockStats(stats);
2214 vie_encoder_->TriggerCpuOveruse();
2215 vie_encoder_->WaitUntilTaskQueueIsIdle();
2216 int adapted_framerate =
2217 vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2218 EXPECT_LT(adapted_framerate, kFramerate);
2219
2220 // Change degradation preference to not enable framerate scaling. Target
2221 // framerate should be changed to codec defined limit.
2222 vie_encoder_->SetSource(
2223 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
2224 vie_encoder_->WaitUntilTaskQueueIsIdle();
2225 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2226 kFramerate);
2227
2228 vie_encoder_->Stop();
2229}
2230
kthelgason2bc68642017-02-07 07:02:22 -08002231TEST_F(ViEEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002232 const int kTooLowBitrateForFrameSizeBps = 10000;
2233 vie_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
2234 const int kWidth = 640;
2235 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002236
asaperssonfab67072017-04-04 05:51:49 -07002237 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002238
2239 // Expect to drop this frame, the wait should time out.
sprang317005a2017-06-08 07:12:17 -07002240 sink_.ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002241
2242 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002243 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002244
sprangc5d62e22017-04-02 23:53:04 -07002245 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002246
asaperssonfab67072017-04-04 05:51:49 -07002247 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002248 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002249 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002250
2251 // Expect to drop this frame, the wait should time out.
sprang317005a2017-06-08 07:12:17 -07002252 sink_.ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002253
sprangc5d62e22017-04-02 23:53:04 -07002254 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002255
2256 vie_encoder_->Stop();
2257}
2258
asapersson09f05612017-05-15 23:40:18 -07002259TEST_F(ViEEncoderTest, NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002260 const int kTooLowBitrateForFrameSizeBps = 10000;
2261 vie_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
2262 const int kWidth = 640;
2263 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002264
2265 // We expect the n initial frames to get dropped.
2266 int i;
2267 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002268 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07002269 sink_.ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002270 }
2271 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002272 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07002273 sink_.WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002274
2275 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002276 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002277
2278 vie_encoder_->Stop();
2279}
2280
2281TEST_F(ViEEncoderTest, InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002282 const int kWidth = 640;
2283 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002284 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
2285
2286 // Set degradation preference.
2287 vie_encoder_->SetSource(
2288 &video_source_,
2289 VideoSendStream::DegradationPreference::kMaintainResolution);
2290
asaperssonfab67072017-04-04 05:51:49 -07002291 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002292 // Frame should not be dropped, even if it's too large.
sprang317005a2017-06-08 07:12:17 -07002293 sink_.WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002294
2295 vie_encoder_->Stop();
2296}
2297
kthelgason2fc52542017-03-03 00:24:41 -08002298TEST_F(ViEEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002299 const int kWidth = 640;
2300 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002301 fake_encoder_.SetQualityScaling(false);
2302 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002303
kthelgasonb83797b2017-02-14 11:57:25 -08002304 // Force quality scaler reconfiguration by resetting the source.
2305 vie_encoder_->SetSource(&video_source_,
2306 VideoSendStream::DegradationPreference::kBalanced);
kthelgasonad9010c2017-02-14 00:46:51 -08002307
asaperssonfab67072017-04-04 05:51:49 -07002308 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002309 // Frame should not be dropped, even if it's too large.
sprang317005a2017-06-08 07:12:17 -07002310 sink_.WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002311
2312 vie_encoder_->Stop();
2313 fake_encoder_.SetQualityScaling(true);
2314}
2315
asaperssond0de2952017-04-21 01:47:31 -07002316TEST_F(ViEEncoderTest,
2317 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2318 const int kTooSmallWidth = 10;
2319 const int kTooSmallHeight = 10;
2320 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2321
2322 // Enable kMaintainFramerate preference, no initial limitation.
2323 test::FrameForwarder source;
2324 vie_encoder_->SetSource(
2325 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
2326 VerifyNoLimitation(source.sink_wants());
2327 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2328
2329 // Trigger adapt down, too small frame, expect no change.
2330 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang317005a2017-06-08 07:12:17 -07002331 sink_.WaitForEncodedFrame(1);
asaperssond0de2952017-04-21 01:47:31 -07002332 vie_encoder_->TriggerCpuOveruse();
2333 VerifyNoLimitation(source.sink_wants());
2334 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2335 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2336
2337 vie_encoder_->Stop();
2338}
2339
asaperssonf7e294d2017-06-13 23:25:22 -07002340TEST_F(ViEEncoderTest, ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
2341 const int kTooSmallWidth = 10;
2342 const int kTooSmallHeight = 10;
2343 const int kFpsLimit = 7;
2344 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2345
2346 // Enable kBalanced preference, no initial limitation.
2347 test::FrameForwarder source;
2348 vie_encoder_->SetSource(&source,
2349 VideoSendStream::DegradationPreference::kBalanced);
2350 VerifyNoLimitation(source.sink_wants());
2351 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2352 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2353
2354 // Trigger adapt down, expect limited framerate.
2355 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
2356 sink_.WaitForEncodedFrame(1);
2357 vie_encoder_->TriggerQualityLow();
2358 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2359 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2360 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2361 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2362
2363 // Trigger adapt down, too small frame, expect no change.
2364 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
2365 sink_.WaitForEncodedFrame(2);
2366 vie_encoder_->TriggerQualityLow();
2367 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2368 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2369 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2370 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2371
2372 vie_encoder_->Stop();
2373}
2374
asapersson02465b82017-04-10 01:12:52 -07002375TEST_F(ViEEncoderTest, FailingInitEncodeDoesntCauseCrash) {
2376 fake_encoder_.ForceInitEncodeFailure(true);
2377 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang317005a2017-06-08 07:12:17 -07002378 ResetEncoder("VP8", 2, 1, true);
asapersson02465b82017-04-10 01:12:52 -07002379 const int kFrameWidth = 1280;
2380 const int kFrameHeight = 720;
2381 video_source_.IncomingCapturedFrame(
2382 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07002383 sink_.ExpectDroppedFrame();
asapersson02465b82017-04-10 01:12:52 -07002384 vie_encoder_->Stop();
2385}
2386
sprangb1ca0732017-02-01 08:38:12 -08002387// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
asaperssond0de2952017-04-21 01:47:31 -07002388TEST_F(ViEEncoderTest, AdaptsResolutionOnOveruse_MaintainFramerateMode) {
sprangb1ca0732017-02-01 08:38:12 -08002389 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2390
2391 const int kFrameWidth = 1280;
2392 const int kFrameHeight = 720;
2393 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
2394 // requested by ViEEncoder::VideoSourceProxy::RequestResolutionLowerThan().
2395 video_source_.set_adaptation_enabled(true);
2396
2397 video_source_.IncomingCapturedFrame(
2398 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07002399 sink_.WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002400
2401 // Trigger CPU overuse, downscale by 3/4.
2402 vie_encoder_->TriggerCpuOveruse();
2403 video_source_.IncomingCapturedFrame(
2404 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07002405 sink_.WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002406
asaperssonfab67072017-04-04 05:51:49 -07002407 // Trigger CPU normal use, return to original resolution.
sprangb1ca0732017-02-01 08:38:12 -08002408 vie_encoder_->TriggerCpuNormalUsage();
2409 video_source_.IncomingCapturedFrame(
2410 CreateFrame(3, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07002411 sink_.WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002412
2413 vie_encoder_->Stop();
2414}
sprangfe627f32017-03-29 08:24:59 -07002415
asapersson02465b82017-04-10 01:12:52 -07002416TEST_F(ViEEncoderTest, AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprang317005a2017-06-08 07:12:17 -07002417 const int kDefaultFramerateFps = 30;
2418 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kDefaultFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002419 const int kFrameWidth = 1280;
2420 const int kFrameHeight = 720;
sprang317005a2017-06-08 07:12:17 -07002421 rtc::ScopedFakeClock fake_clock;
sprangc5d62e22017-04-02 23:53:04 -07002422
2423 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2424 vie_encoder_->SetSource(
2425 &video_source_,
2426 VideoSendStream::DegradationPreference::kMaintainResolution);
2427 video_source_.set_adaptation_enabled(true);
2428
sprang317005a2017-06-08 07:12:17 -07002429 fake_clock.SetTimeMicros(kFrameIntervalMs * 1000);
2430 int64_t timestamp_ms = kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002431
2432 video_source_.IncomingCapturedFrame(
2433 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07002434 sink_.WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002435
2436 // Try to trigger overuse. No fps estimate available => no effect.
2437 vie_encoder_->TriggerCpuOveruse();
2438
2439 // Insert frames for one second to get a stable estimate.
sprang317005a2017-06-08 07:12:17 -07002440 for (int i = 0; i < kDefaultFramerateFps; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002441 timestamp_ms += kFrameIntervalMs;
sprang317005a2017-06-08 07:12:17 -07002442 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
sprangc5d62e22017-04-02 23:53:04 -07002443 video_source_.IncomingCapturedFrame(
2444 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07002445 sink_.WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002446 }
2447
2448 // Trigger CPU overuse, reduce framerate by 2/3.
2449 vie_encoder_->TriggerCpuOveruse();
2450 int num_frames_dropped = 0;
sprang317005a2017-06-08 07:12:17 -07002451 for (int i = 0; i < kDefaultFramerateFps; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002452 timestamp_ms += kFrameIntervalMs;
sprang317005a2017-06-08 07:12:17 -07002453 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
sprangc5d62e22017-04-02 23:53:04 -07002454 video_source_.IncomingCapturedFrame(
2455 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07002456 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002457 ++num_frames_dropped;
2458 } else {
2459 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2460 }
2461 }
2462
sprang317005a2017-06-08 07:12:17 -07002463 // TODO(sprang): Find where there's rounding errors or stuff causing the
2464 // margin here to be a little larger than we'd like (input fps estimate is
2465 // off) and the frame dropping is a little too aggressive.
2466 const int kErrorMargin = 5;
2467 EXPECT_NEAR(num_frames_dropped,
2468 kDefaultFramerateFps - (kDefaultFramerateFps * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002469 kErrorMargin);
2470
2471 // Trigger CPU overuse, reduce framerate by 2/3 again.
2472 vie_encoder_->TriggerCpuOveruse();
2473 num_frames_dropped = 0;
sprang317005a2017-06-08 07:12:17 -07002474 for (int i = 0; i < kDefaultFramerateFps; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002475 timestamp_ms += kFrameIntervalMs;
sprang317005a2017-06-08 07:12:17 -07002476 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
sprangc5d62e22017-04-02 23:53:04 -07002477 video_source_.IncomingCapturedFrame(
2478 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07002479 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002480 ++num_frames_dropped;
2481 } else {
2482 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2483 }
2484 }
sprang317005a2017-06-08 07:12:17 -07002485 EXPECT_NEAR(num_frames_dropped,
2486 kDefaultFramerateFps - (kDefaultFramerateFps * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002487 kErrorMargin);
2488
2489 // Go back up one step.
2490 vie_encoder_->TriggerCpuNormalUsage();
2491 num_frames_dropped = 0;
sprang317005a2017-06-08 07:12:17 -07002492 for (int i = 0; i < kDefaultFramerateFps; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002493 timestamp_ms += kFrameIntervalMs;
sprang317005a2017-06-08 07:12:17 -07002494 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
sprangc5d62e22017-04-02 23:53:04 -07002495 video_source_.IncomingCapturedFrame(
2496 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07002497 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002498 ++num_frames_dropped;
2499 } else {
2500 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2501 }
2502 }
sprang317005a2017-06-08 07:12:17 -07002503 EXPECT_NEAR(num_frames_dropped,
2504 kDefaultFramerateFps - (kDefaultFramerateFps * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002505 kErrorMargin);
2506
2507 // Go back up to original mode.
2508 vie_encoder_->TriggerCpuNormalUsage();
2509 num_frames_dropped = 0;
sprang317005a2017-06-08 07:12:17 -07002510 for (int i = 0; i < kDefaultFramerateFps; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002511 timestamp_ms += kFrameIntervalMs;
sprang317005a2017-06-08 07:12:17 -07002512 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
sprangc5d62e22017-04-02 23:53:04 -07002513 video_source_.IncomingCapturedFrame(
2514 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07002515 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002516 ++num_frames_dropped;
2517 } else {
2518 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2519 }
2520 }
2521 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2522
2523 vie_encoder_->Stop();
2524}
2525
2526TEST_F(ViEEncoderTest, DoesntAdaptDownPastMinFramerate) {
2527 const int kFramerateFps = 5;
2528 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
2529 const int kMinFpsFrameInterval = rtc::kNumMillisecsPerSec / kMinFramerateFps;
2530 const int kFrameWidth = 1280;
2531 const int kFrameHeight = 720;
2532
sprang317005a2017-06-08 07:12:17 -07002533 rtc::ScopedFakeClock fake_clock;
sprangc5d62e22017-04-02 23:53:04 -07002534 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2535 vie_encoder_->SetSource(
2536 &video_source_,
2537 VideoSendStream::DegradationPreference::kMaintainResolution);
2538 video_source_.set_adaptation_enabled(true);
2539
sprang317005a2017-06-08 07:12:17 -07002540 fake_clock.SetTimeMicros(kFrameIntervalMs * 1000);
2541 int64_t timestamp_ms = kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002542
2543 // Trigger overuse as much as we can.
2544 for (int i = 0; i < ViEEncoder::kMaxCpuResolutionDowngrades; ++i) {
2545 // Insert frames to get a new fps estimate...
2546 for (int j = 0; j < kFramerateFps; ++j) {
2547 video_source_.IncomingCapturedFrame(
2548 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
2549 timestamp_ms += kFrameIntervalMs;
sprang317005a2017-06-08 07:12:17 -07002550 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
sprangc5d62e22017-04-02 23:53:04 -07002551 }
2552 // ...and then try to adapt again.
2553 vie_encoder_->TriggerCpuOveruse();
2554 }
2555
2556 // Drain any frame in the pipeline.
sprang317005a2017-06-08 07:12:17 -07002557 sink_.WaitForFrame(kDefaultTimeoutMs);
sprangc5d62e22017-04-02 23:53:04 -07002558
2559 // Insert frames at min fps, all should go through.
2560 for (int i = 0; i < 10; ++i) {
2561 timestamp_ms += kMinFpsFrameInterval;
sprang317005a2017-06-08 07:12:17 -07002562 fake_clock.AdvanceTimeMicros(kMinFpsFrameInterval * 1000);
sprangc5d62e22017-04-02 23:53:04 -07002563 video_source_.IncomingCapturedFrame(
2564 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07002565 sink_.WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002566 }
asaperssonf7e294d2017-06-13 23:25:22 -07002567
sprangc5d62e22017-04-02 23:53:04 -07002568 vie_encoder_->Stop();
2569}
asaperssonf7e294d2017-06-13 23:25:22 -07002570
2571TEST_F(ViEEncoderTest, AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
2572 const int kWidth = 1280;
2573 const int kHeight = 720;
2574 const int64_t kFrameIntervalMs = 150;
2575 int64_t timestamp_ms = kFrameIntervalMs;
2576 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2577
2578 // Enable kBalanced preference, no initial limitation.
2579 AdaptingFrameForwarder source;
2580 source.set_adaptation_enabled(true);
2581 vie_encoder_->SetSource(&source,
2582 VideoSendStream::DegradationPreference::kBalanced);
2583 timestamp_ms += kFrameIntervalMs;
2584 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2585 sink_.WaitForEncodedFrame(kWidth, kHeight);
2586 VerifyNoLimitation(source.sink_wants());
2587 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2588 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2589 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2590
2591 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
2592 vie_encoder_->TriggerQualityLow();
2593 timestamp_ms += kFrameIntervalMs;
2594 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2595 sink_.WaitForEncodedFrame(timestamp_ms);
2596 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2597 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2598 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2599 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2600
2601 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
2602 vie_encoder_->TriggerQualityLow();
2603 timestamp_ms += kFrameIntervalMs;
2604 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2605 sink_.WaitForEncodedFrame(timestamp_ms);
2606 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2607 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2608 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2609 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2610
2611 // Trigger adapt down, expect reduced fps (640x360@15fps).
2612 vie_encoder_->TriggerQualityLow();
2613 timestamp_ms += kFrameIntervalMs;
2614 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2615 sink_.WaitForEncodedFrame(timestamp_ms);
2616 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2617 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2618 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2619 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2620
2621 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
2622 vie_encoder_->TriggerQualityLow();
2623 timestamp_ms += kFrameIntervalMs;
2624 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2625 sink_.WaitForEncodedFrame(timestamp_ms);
2626 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2627 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2628 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2629 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2630
2631 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
2632 vie_encoder_->TriggerQualityLow();
2633 timestamp_ms += kFrameIntervalMs;
2634 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2635 sink_.WaitForEncodedFrame(timestamp_ms);
2636 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2637 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2638 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2639 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2640
2641 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
2642 vie_encoder_->TriggerQualityLow();
2643 timestamp_ms += kFrameIntervalMs;
2644 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2645 sink_.WaitForEncodedFrame(timestamp_ms);
2646 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2647 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2648 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2649 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2650
2651 // Trigger adapt down, expect reduced fps (320x180@7fps).
2652 vie_encoder_->TriggerQualityLow();
2653 timestamp_ms += kFrameIntervalMs;
2654 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2655 sink_.WaitForEncodedFrame(timestamp_ms);
2656 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2657 rtc::VideoSinkWants last_wants = source.sink_wants();
2658 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2659 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2660 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2661
2662 // Trigger adapt down, min resolution reached, expect no change.
2663 vie_encoder_->TriggerQualityLow();
2664 timestamp_ms += kFrameIntervalMs;
2665 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2666 sink_.WaitForEncodedFrame(timestamp_ms);
2667 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2668 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2669 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2670 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2671
2672 // Trigger adapt down, expect expect increased fps (320x180@10fps).
2673 vie_encoder_->TriggerQualityHigh();
2674 timestamp_ms += kFrameIntervalMs;
2675 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2676 sink_.WaitForEncodedFrame(timestamp_ms);
2677 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2678 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2679 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2680 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2681
2682 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
2683 vie_encoder_->TriggerQualityHigh();
2684 timestamp_ms += kFrameIntervalMs;
2685 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2686 sink_.WaitForEncodedFrame(timestamp_ms);
2687 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2688 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2689 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2690 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2691
2692 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
2693 vie_encoder_->TriggerQualityHigh();
2694 timestamp_ms += kFrameIntervalMs;
2695 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2696 sink_.WaitForEncodedFrame(timestamp_ms);
2697 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2698 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2699 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2700 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2701
2702 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
2703 vie_encoder_->TriggerQualityHigh();
2704 timestamp_ms += kFrameIntervalMs;
2705 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2706 sink_.WaitForEncodedFrame(timestamp_ms);
2707 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2708 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2709 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2710 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2711
2712 // Trigger adapt up, expect increased fps (640x360@30fps).
2713 vie_encoder_->TriggerQualityHigh();
2714 timestamp_ms += kFrameIntervalMs;
2715 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2716 sink_.WaitForEncodedFrame(timestamp_ms);
2717 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2718 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2719 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2720 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2721
2722 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
2723 vie_encoder_->TriggerQualityHigh();
2724 timestamp_ms += kFrameIntervalMs;
2725 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2726 sink_.WaitForEncodedFrame(timestamp_ms);
2727 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2728 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2729 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2730 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2731
2732 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
2733 vie_encoder_->TriggerQualityHigh();
2734 timestamp_ms += kFrameIntervalMs;
2735 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2736 sink_.WaitForEncodedFrame(kWidth, kHeight);
2737 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2738 VerifyNoLimitation(source.sink_wants());
2739 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2740 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2741 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2742
2743 // Trigger adapt up, expect no change.
2744 vie_encoder_->TriggerQualityHigh();
2745 VerifyNoLimitation(source.sink_wants());
2746 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2747
2748 vie_encoder_->Stop();
2749}
2750
2751TEST_F(ViEEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
2752 const int kWidth = 1280;
2753 const int kHeight = 720;
2754 const int64_t kFrameIntervalMs = 150;
2755 int64_t timestamp_ms = kFrameIntervalMs;
2756 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2757
2758 // Enable kBalanced preference, no initial limitation.
2759 AdaptingFrameForwarder source;
2760 source.set_adaptation_enabled(true);
2761 vie_encoder_->SetSource(&source,
2762 VideoSendStream::DegradationPreference::kBalanced);
2763 timestamp_ms += kFrameIntervalMs;
2764 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2765 sink_.WaitForEncodedFrame(kWidth, kHeight);
2766 VerifyNoLimitation(source.sink_wants());
2767 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2768 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2769 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2770 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2771 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2772 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2773
2774 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
2775 vie_encoder_->TriggerCpuOveruse();
2776 timestamp_ms += kFrameIntervalMs;
2777 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2778 sink_.WaitForEncodedFrame(timestamp_ms);
2779 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2780 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2781 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2782 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2783 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2784 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2785 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2786
2787 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
2788 vie_encoder_->TriggerCpuOveruse();
2789 timestamp_ms += kFrameIntervalMs;
2790 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2791 sink_.WaitForEncodedFrame(timestamp_ms);
2792 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2793 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2794 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2795 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2796 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2797 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2798 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2799
2800 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
2801 vie_encoder_->TriggerQualityLow();
2802 timestamp_ms += kFrameIntervalMs;
2803 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2804 sink_.WaitForEncodedFrame(timestamp_ms);
2805 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2806 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2807 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2808 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2809 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2810 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2811 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2812
2813 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
2814 vie_encoder_->TriggerCpuNormalUsage();
2815 timestamp_ms += kFrameIntervalMs;
2816 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2817 sink_.WaitForEncodedFrame(timestamp_ms);
2818 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2819 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2820 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2821 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2822 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2823 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2824 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2825
2826 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
2827 vie_encoder_->TriggerQualityHigh();
2828 timestamp_ms += kFrameIntervalMs;
2829 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2830 sink_.WaitForEncodedFrame(timestamp_ms);
2831 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2832 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2833 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2834 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2835 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2836 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2837 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2838
2839 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
2840 vie_encoder_->TriggerCpuNormalUsage();
2841 timestamp_ms += kFrameIntervalMs;
2842 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2843 sink_.WaitForEncodedFrame(kWidth, kHeight);
2844 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2845 VerifyNoLimitation(source.sink_wants());
2846 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2847 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2848 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2849 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2850 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2851 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2852
2853 // Trigger adapt up, expect no change.
2854 vie_encoder_->TriggerQualityHigh();
2855 VerifyNoLimitation(source.sink_wants());
2856 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2857 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2858
2859 vie_encoder_->Stop();
2860}
2861
2862TEST_F(ViEEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
2863 const int kWidth = 640;
2864 const int kHeight = 360;
2865 const int kFpsLimit = 15;
2866 const int64_t kFrameIntervalMs = 150;
2867 int64_t timestamp_ms = kFrameIntervalMs;
2868 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2869
2870 // Enable kBalanced preference, no initial limitation.
2871 AdaptingFrameForwarder source;
2872 source.set_adaptation_enabled(true);
2873 vie_encoder_->SetSource(&source,
2874 VideoSendStream::DegradationPreference::kBalanced);
2875 timestamp_ms += kFrameIntervalMs;
2876 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2877 sink_.WaitForEncodedFrame(kWidth, kHeight);
2878 VerifyNoLimitation(source.sink_wants());
2879 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2880 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2881 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2882 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2883 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2884 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2885
2886 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
2887 vie_encoder_->TriggerCpuOveruse();
2888 timestamp_ms += kFrameIntervalMs;
2889 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2890 sink_.WaitForEncodedFrame(timestamp_ms);
2891 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2892 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2893 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2894 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2895 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2896 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2897 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2898
2899 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
2900 vie_encoder_->TriggerQualityLow();
2901 timestamp_ms += kFrameIntervalMs;
2902 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2903 sink_.WaitForEncodedFrame(timestamp_ms);
2904 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2905 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2906 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2907 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2908 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2909 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2910 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2911
2912 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
2913 vie_encoder_->TriggerCpuNormalUsage();
2914 timestamp_ms += kFrameIntervalMs;
2915 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2916 sink_.WaitForEncodedFrame(timestamp_ms);
2917 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2918 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2919 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2920 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2921 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2922 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2923 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2924
2925 // Trigger quality adapt up, expect increased fps (640x360@30fps).
2926 vie_encoder_->TriggerQualityHigh();
2927 timestamp_ms += kFrameIntervalMs;
2928 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2929 sink_.WaitForEncodedFrame(timestamp_ms);
2930 VerifyNoLimitation(source.sink_wants());
2931 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2932 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2933 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2934 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2935 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2936 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2937
2938 // Trigger adapt up, expect no change.
2939 vie_encoder_->TriggerQualityHigh();
2940 VerifyNoLimitation(source.sink_wants());
2941 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2942 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2943
2944 vie_encoder_->Stop();
2945}
2946
perkj26091b12016-09-01 01:17:40 -07002947} // namespace webrtc