blob: 976cf47bb2fa504033b226c41733257c8804aab3 [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
ilnik6b826ef2017-06-16 06:53:48 -0700169
sprangb1ca0732017-02-01 08:38:12 -0800170class AdaptingFrameForwarder : public test::FrameForwarder {
171 public:
172 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700173 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800174
175 void set_adaptation_enabled(bool enabled) {
176 rtc::CritScope cs(&crit_);
177 adaptation_enabled_ = enabled;
178 }
179
asaperssonfab67072017-04-04 05:51:49 -0700180 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800181 rtc::CritScope cs(&crit_);
182 return adaptation_enabled_;
183 }
184
asapersson09f05612017-05-15 23:40:18 -0700185 rtc::VideoSinkWants last_wants() const {
186 rtc::CritScope cs(&crit_);
187 return last_wants_;
188 }
189
sprangb1ca0732017-02-01 08:38:12 -0800190 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
191 int cropped_width = 0;
192 int cropped_height = 0;
193 int out_width = 0;
194 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700195 if (adaption_enabled()) {
196 if (adapter_.AdaptFrameResolution(
197 video_frame.width(), video_frame.height(),
198 video_frame.timestamp_us() * 1000, &cropped_width,
199 &cropped_height, &out_width, &out_height)) {
200 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
201 nullptr, out_width, out_height),
202 99, 99, kVideoRotation_0);
203 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
204 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
205 }
sprangb1ca0732017-02-01 08:38:12 -0800206 } else {
207 test::FrameForwarder::IncomingCapturedFrame(video_frame);
208 }
209 }
210
211 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
212 const rtc::VideoSinkWants& wants) override {
213 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700214 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700215 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
216 wants.max_pixel_count,
217 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800218 test::FrameForwarder::AddOrUpdateSink(sink, wants);
219 }
sprangb1ca0732017-02-01 08:38:12 -0800220 cricket::VideoAdapter adapter_;
221 bool adaptation_enabled_ GUARDED_BY(crit_);
asapersson09f05612017-05-15 23:40:18 -0700222 rtc::VideoSinkWants last_wants_ GUARDED_BY(crit_);
sprangb1ca0732017-02-01 08:38:12 -0800223};
sprangc5d62e22017-04-02 23:53:04 -0700224
225class MockableSendStatisticsProxy : public SendStatisticsProxy {
226 public:
227 MockableSendStatisticsProxy(Clock* clock,
228 const VideoSendStream::Config& config,
229 VideoEncoderConfig::ContentType content_type)
230 : SendStatisticsProxy(clock, config, content_type) {}
231
232 VideoSendStream::Stats GetStats() override {
233 rtc::CritScope cs(&lock_);
234 if (mock_stats_)
235 return *mock_stats_;
236 return SendStatisticsProxy::GetStats();
237 }
238
239 void SetMockStats(const VideoSendStream::Stats& stats) {
240 rtc::CritScope cs(&lock_);
241 mock_stats_.emplace(stats);
242 }
243
244 void ResetMockStats() {
245 rtc::CritScope cs(&lock_);
246 mock_stats_.reset();
247 }
248
249 private:
250 rtc::CriticalSection lock_;
251 rtc::Optional<VideoSendStream::Stats> mock_stats_ GUARDED_BY(lock_);
252};
253
perkj803d97f2016-11-01 11:45:46 -0700254} // namespace
255
perkj26091b12016-09-01 01:17:40 -0700256class ViEEncoderTest : public ::testing::Test {
257 public:
258 static const int kDefaultTimeoutMs = 30 * 1000;
259
260 ViEEncoderTest()
261 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700262 codec_width_(320),
263 codec_height_(240),
perkj26091b12016-09-01 01:17:40 -0700264 fake_encoder_(),
sprangc5d62e22017-04-02 23:53:04 -0700265 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700266 Clock::GetRealTimeClock(),
267 video_send_config_,
268 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700269 sink_(&fake_encoder_) {}
270
271 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700272 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700273 video_send_config_ = VideoSendStream::Config(nullptr);
274 video_send_config_.encoder_settings.encoder = &fake_encoder_;
275 video_send_config_.encoder_settings.payload_name = "FAKE";
276 video_send_config_.encoder_settings.payload_type = 125;
277
Per512ecb32016-09-23 15:52:06 +0200278 VideoEncoderConfig video_encoder_config;
perkjfa10b552016-10-02 23:45:26 -0700279 test::FillEncoderConfiguration(1, &video_encoder_config);
Erik Språng08127a92016-11-16 16:41:30 +0100280 video_encoder_config_ = video_encoder_config.Copy();
asapersson5f7226f2016-11-25 04:37:00 -0800281 ConfigureEncoder(std::move(video_encoder_config), true /* nack_enabled */);
282 }
283
284 void ConfigureEncoder(VideoEncoderConfig video_encoder_config,
285 bool nack_enabled) {
286 if (vie_encoder_)
287 vie_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700288 vie_encoder_.reset(new ViEEncoderUnderTest(
289 stats_proxy_.get(), video_send_config_.encoder_settings));
290 vie_encoder_->SetSink(&sink_, false /* rotation_applied */);
sprangc5d62e22017-04-02 23:53:04 -0700291 vie_encoder_->SetSource(
292 &video_source_,
293 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason2bc68642017-02-07 07:02:22 -0800294 vie_encoder_->SetStartBitrate(kTargetBitrateBps);
asapersson5f7226f2016-11-25 04:37:00 -0800295 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
296 kMaxPayloadLength, nack_enabled);
kthelgason2fc52542017-03-03 00:24:41 -0800297 vie_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800298 }
299
300 void ResetEncoder(const std::string& payload_name,
301 size_t num_streams,
302 size_t num_temporal_layers,
sprang317005a2017-06-08 07:12:17 -0700303 bool nack_enabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800304 video_send_config_.encoder_settings.payload_name = payload_name;
305
306 VideoEncoderConfig video_encoder_config;
307 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800308 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800309 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700310 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
311 kDefaultFramerate);
asapersson5f7226f2016-11-25 04:37:00 -0800312 ConfigureEncoder(std::move(video_encoder_config), nack_enabled);
perkj26091b12016-09-01 01:17:40 -0700313 }
314
sprang57c2fff2017-01-16 06:24:02 -0800315 VideoFrame CreateFrame(int64_t ntp_time_ms,
316 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200317 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
318 destruction_event, codec_width_, codec_height_),
319 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800320 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700321 return frame;
322 }
323
sprang57c2fff2017-01-16 06:24:02 -0800324 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700325 VideoFrame frame(
326 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
327 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800328 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700329 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700330 return frame;
331 }
332
asapersson02465b82017-04-10 01:12:52 -0700333 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700334 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700335 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
336 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700337 }
338
asapersson09f05612017-05-15 23:40:18 -0700339 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
340 const rtc::VideoSinkWants& wants2) {
341 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
342 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
343 }
344
345 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
346 const rtc::VideoSinkWants& wants2) {
347 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
348 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
349 EXPECT_GT(wants1.max_pixel_count, 0);
350 }
351
352 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
353 const rtc::VideoSinkWants& wants2) {
354 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
355 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
356 }
357
asaperssonf7e294d2017-06-13 23:25:22 -0700358 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
359 const rtc::VideoSinkWants& wants2) {
360 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
361 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
362 }
363
364 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
365 const rtc::VideoSinkWants& wants2) {
366 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
367 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
368 }
369
370 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
371 const rtc::VideoSinkWants& wants2) {
372 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
373 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
374 }
375
376 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
377 const rtc::VideoSinkWants& wants2) {
378 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
379 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
380 EXPECT_GT(wants1.max_pixel_count, 0);
381 }
382
383 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
384 const rtc::VideoSinkWants& wants2) {
385 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
386 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
387 }
388
asapersson09f05612017-05-15 23:40:18 -0700389 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
390 int pixel_count) {
391 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700392 EXPECT_LT(wants.max_pixel_count, pixel_count);
393 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700394 }
395
396 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
397 EXPECT_LT(wants.max_framerate_fps, fps);
398 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
399 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700400 }
401
asaperssonf7e294d2017-06-13 23:25:22 -0700402 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
403 int expected_fps) {
404 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
405 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
406 EXPECT_FALSE(wants.target_pixel_count);
407 }
408
perkj26091b12016-09-01 01:17:40 -0700409 class TestEncoder : public test::FakeEncoder {
410 public:
411 TestEncoder()
412 : FakeEncoder(Clock::GetRealTimeClock()),
413 continue_encode_event_(false, false) {}
414
asaperssonfab67072017-04-04 05:51:49 -0700415 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800416 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700417 return config_;
418 }
419
420 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800421 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700422 block_next_encode_ = true;
423 }
424
kthelgason876222f2016-11-29 01:44:11 -0800425 VideoEncoder::ScalingSettings GetScalingSettings() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800426 rtc::CritScope lock(&local_crit_sect_);
kthelgasonad9010c2017-02-14 00:46:51 -0800427 if (quality_scaling_)
428 return VideoEncoder::ScalingSettings(true, 1, 2);
429 return VideoEncoder::ScalingSettings(false);
kthelgason876222f2016-11-29 01:44:11 -0800430 }
431
perkjfa10b552016-10-02 23:45:26 -0700432 void ContinueEncode() { continue_encode_event_.Set(); }
433
434 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
435 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800436 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700437 EXPECT_EQ(timestamp_, timestamp);
438 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
439 }
440
kthelgason2fc52542017-03-03 00:24:41 -0800441 void SetQualityScaling(bool b) {
442 rtc::CritScope lock(&local_crit_sect_);
443 quality_scaling_ = b;
444 }
kthelgasonad9010c2017-02-14 00:46:51 -0800445
sprangfe627f32017-03-29 08:24:59 -0700446 void ForceInitEncodeFailure(bool force_failure) {
447 rtc::CritScope lock(&local_crit_sect_);
448 force_init_encode_failed_ = force_failure;
449 }
450
perkjfa10b552016-10-02 23:45:26 -0700451 private:
perkj26091b12016-09-01 01:17:40 -0700452 int32_t Encode(const VideoFrame& input_image,
453 const CodecSpecificInfo* codec_specific_info,
454 const std::vector<FrameType>* frame_types) override {
455 bool block_encode;
456 {
brandtre78d2662017-01-16 05:57:16 -0800457 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700458 EXPECT_GT(input_image.timestamp(), timestamp_);
459 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
460 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
461
462 timestamp_ = input_image.timestamp();
463 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700464 last_input_width_ = input_image.width();
465 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700466 block_encode = block_next_encode_;
467 block_next_encode_ = false;
468 }
469 int32_t result =
470 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
471 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700472 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700473 return result;
474 }
475
sprangfe627f32017-03-29 08:24:59 -0700476 int32_t InitEncode(const VideoCodec* config,
477 int32_t number_of_cores,
478 size_t max_payload_size) override {
479 int res =
480 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
481 rtc::CritScope lock(&local_crit_sect_);
482 if (config->codecType == kVideoCodecVP8 && config->VP8().tl_factory) {
483 // Simulate setting up temporal layers, in order to validate the life
484 // cycle of these objects.
485 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
486 int num_temporal_layers =
487 std::max<int>(1, config->VP8().numberOfTemporalLayers);
488 for (int i = 0; i < num_streams; ++i) {
489 allocated_temporal_layers_.emplace_back(
490 config->VP8().tl_factory->Create(i, num_temporal_layers, 42));
491 }
492 }
493 if (force_init_encode_failed_)
494 return -1;
495 return res;
496 }
497
brandtre78d2662017-01-16 05:57:16 -0800498 rtc::CriticalSection local_crit_sect_;
sprangfe627f32017-03-29 08:24:59 -0700499 bool block_next_encode_ GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700500 rtc::Event continue_encode_event_;
sprangfe627f32017-03-29 08:24:59 -0700501 uint32_t timestamp_ GUARDED_BY(local_crit_sect_) = 0;
502 int64_t ntp_time_ms_ GUARDED_BY(local_crit_sect_) = 0;
503 int last_input_width_ GUARDED_BY(local_crit_sect_) = 0;
504 int last_input_height_ GUARDED_BY(local_crit_sect_) = 0;
505 bool quality_scaling_ GUARDED_BY(local_crit_sect_) = true;
506 std::vector<std::unique_ptr<TemporalLayers>> allocated_temporal_layers_
507 GUARDED_BY(local_crit_sect_);
508 bool force_init_encode_failed_ GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700509 };
510
Per512ecb32016-09-23 15:52:06 +0200511 class TestSink : public ViEEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700512 public:
513 explicit TestSink(TestEncoder* test_encoder)
514 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
515
perkj26091b12016-09-01 01:17:40 -0700516 void WaitForEncodedFrame(int64_t expected_ntp_time) {
517 uint32_t timestamp = 0;
sprang317005a2017-06-08 07:12:17 -0700518 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700519 {
520 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800521 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700522 }
523 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
524 }
525
sprangb1ca0732017-02-01 08:38:12 -0800526 void WaitForEncodedFrame(uint32_t expected_width,
527 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700528 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
529 CheckLastFrameSizeMathces(expected_width, expected_height);
530 }
531
532 void CheckLastFrameSizeMathces(uint32_t expected_width,
533 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800534 uint32_t width = 0;
535 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800536 {
537 rtc::CritScope lock(&crit_);
538 width = last_width_;
539 height = last_height_;
540 }
541 EXPECT_EQ(expected_height, height);
542 EXPECT_EQ(expected_width, width);
543 }
544
kthelgason2fc52542017-03-03 00:24:41 -0800545 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800546
sprangc5d62e22017-04-02 23:53:04 -0700547 bool WaitForFrame(int64_t timeout_ms) {
548 return encoded_frame_event_.Wait(timeout_ms);
549 }
550
perkj26091b12016-09-01 01:17:40 -0700551 void SetExpectNoFrames() {
552 rtc::CritScope lock(&crit_);
553 expect_frames_ = false;
554 }
555
asaperssonfab67072017-04-04 05:51:49 -0700556 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200557 rtc::CritScope lock(&crit_);
558 return number_of_reconfigurations_;
559 }
560
asaperssonfab67072017-04-04 05:51:49 -0700561 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200562 rtc::CritScope lock(&crit_);
563 return min_transmit_bitrate_bps_;
564 }
565
perkj26091b12016-09-01 01:17:40 -0700566 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700567 Result OnEncodedImage(
568 const EncodedImage& encoded_image,
569 const CodecSpecificInfo* codec_specific_info,
570 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200571 rtc::CritScope lock(&crit_);
572 EXPECT_TRUE(expect_frames_);
sprangb1ca0732017-02-01 08:38:12 -0800573 last_timestamp_ = encoded_image._timeStamp;
574 last_width_ = encoded_image._encodedWidth;
575 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200576 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800577 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200578 }
579
580 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
581 int min_transmit_bitrate_bps) override {
582 rtc::CriticalSection crit_;
583 ++number_of_reconfigurations_;
584 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
585 }
586
perkj26091b12016-09-01 01:17:40 -0700587 rtc::CriticalSection crit_;
588 TestEncoder* test_encoder_;
589 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800590 uint32_t last_timestamp_ = 0;
591 uint32_t last_height_ = 0;
592 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700593 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200594 int number_of_reconfigurations_ = 0;
595 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700596 };
597
598 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100599 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200600 int codec_width_;
601 int codec_height_;
perkj26091b12016-09-01 01:17:40 -0700602 TestEncoder fake_encoder_;
sprangc5d62e22017-04-02 23:53:04 -0700603 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700604 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800605 AdaptingFrameForwarder video_source_;
perkj803d97f2016-11-01 11:45:46 -0700606 std::unique_ptr<ViEEncoderUnderTest> vie_encoder_;
perkj26091b12016-09-01 01:17:40 -0700607};
608
609TEST_F(ViEEncoderTest, EncodeOneFrame) {
perkj26091b12016-09-01 01:17:40 -0700610 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
611 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700612 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang317005a2017-06-08 07:12:17 -0700613 sink_.WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700614 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700615 vie_encoder_->Stop();
616}
617
618TEST_F(ViEEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
619 // Dropped since no target bitrate has been set.
620 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700621 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
622 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700623
perkj26091b12016-09-01 01:17:40 -0700624 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
625
perkja49cbd32016-09-16 07:53:41 -0700626 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang317005a2017-06-08 07:12:17 -0700627 sink_.WaitForEncodedFrame(2);
perkj26091b12016-09-01 01:17:40 -0700628 vie_encoder_->Stop();
629}
630
631TEST_F(ViEEncoderTest, DropsFramesWhenRateSetToZero) {
perkj26091b12016-09-01 01:17:40 -0700632 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700633 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang317005a2017-06-08 07:12:17 -0700634 sink_.WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700635
636 vie_encoder_->OnBitrateUpdated(0, 0, 0);
637 // Dropped since bitrate is zero.
perkja49cbd32016-09-16 07:53:41 -0700638 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkj26091b12016-09-01 01:17:40 -0700639
640 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700641 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
sprang317005a2017-06-08 07:12:17 -0700642 sink_.WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700643 vie_encoder_->Stop();
644}
645
646TEST_F(ViEEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
perkj26091b12016-09-01 01:17:40 -0700647 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700648 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang317005a2017-06-08 07:12:17 -0700649 sink_.WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700650
651 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700652 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700653
perkja49cbd32016-09-16 07:53:41 -0700654 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang317005a2017-06-08 07:12:17 -0700655 sink_.WaitForEncodedFrame(2);
perkj26091b12016-09-01 01:17:40 -0700656 vie_encoder_->Stop();
657}
658
659TEST_F(ViEEncoderTest, DropsFrameAfterStop) {
perkj26091b12016-09-01 01:17:40 -0700660 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
661
perkja49cbd32016-09-16 07:53:41 -0700662 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang317005a2017-06-08 07:12:17 -0700663 sink_.WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700664
665 vie_encoder_->Stop();
666 sink_.SetExpectNoFrames();
667 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700668 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
669 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700670}
671
672TEST_F(ViEEncoderTest, DropsPendingFramesOnSlowEncode) {
perkj26091b12016-09-01 01:17:40 -0700673 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
674
675 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700676 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang317005a2017-06-08 07:12:17 -0700677 sink_.WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700678 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
679 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700680 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
681 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700682 fake_encoder_.ContinueEncode();
sprang317005a2017-06-08 07:12:17 -0700683 sink_.WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700684
685 vie_encoder_->Stop();
686}
687
Per512ecb32016-09-23 15:52:06 +0200688TEST_F(ViEEncoderTest, ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
Per512ecb32016-09-23 15:52:06 +0200689 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100690 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200691
692 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200693 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang317005a2017-06-08 07:12:17 -0700694 sink_.WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100695 // The encoder will have been configured once when the first frame is
696 // received.
697 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200698
699 VideoEncoderConfig video_encoder_config;
perkjfa10b552016-10-02 23:45:26 -0700700 test::FillEncoderConfiguration(1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200701 video_encoder_config.min_transmit_bitrate_bps = 9999;
asapersson5f7226f2016-11-25 04:37:00 -0800702 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
703 kMaxPayloadLength, true /* nack_enabled */);
Per512ecb32016-09-23 15:52:06 +0200704
705 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200706 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang317005a2017-06-08 07:12:17 -0700707 sink_.WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100708 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700709 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700710
711 vie_encoder_->Stop();
712}
713
perkjfa10b552016-10-02 23:45:26 -0700714TEST_F(ViEEncoderTest, FrameResolutionChangeReconfigureEncoder) {
perkjfa10b552016-10-02 23:45:26 -0700715 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
716
717 // Capture a frame and wait for it to synchronize with the encoder thread.
718 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang317005a2017-06-08 07:12:17 -0700719 sink_.WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100720 // The encoder will have been configured once.
721 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700722 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
723 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
724
725 codec_width_ *= 2;
726 codec_height_ *= 2;
727 // Capture a frame with a higher resolution and wait for it to synchronize
728 // with the encoder thread.
729 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang317005a2017-06-08 07:12:17 -0700730 sink_.WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700731 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
732 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100733 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700734
735 vie_encoder_->Stop();
736}
737
asapersson5f7226f2016-11-25 04:37:00 -0800738TEST_F(ViEEncoderTest, Vp8ResilienceIsOffFor1S1TLWithNackEnabled) {
739 const bool kNackEnabled = true;
740 const size_t kNumStreams = 1;
741 const size_t kNumTl = 1;
sprang317005a2017-06-08 07:12:17 -0700742 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800743 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
744
745 // Capture a frame and wait for it to synchronize with the encoder thread.
746 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang317005a2017-06-08 07:12:17 -0700747 sink_.WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800748 // The encoder have been configured once when the first frame is received.
749 EXPECT_EQ(1, sink_.number_of_reconfigurations());
750 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
751 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
752 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
753 // Resilience is off for no temporal layers with nack on.
754 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
755 vie_encoder_->Stop();
756}
757
758TEST_F(ViEEncoderTest, Vp8ResilienceIsOffFor2S1TlWithNackEnabled) {
759 const bool kNackEnabled = true;
760 const size_t kNumStreams = 2;
761 const size_t kNumTl = 1;
sprang317005a2017-06-08 07:12:17 -0700762 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800763 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
764
765 // Capture a frame and wait for it to synchronize with the encoder thread.
766 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang317005a2017-06-08 07:12:17 -0700767 sink_.WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800768 // The encoder have been configured once when the first frame is received.
769 EXPECT_EQ(1, sink_.number_of_reconfigurations());
770 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
771 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
772 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
773 // Resilience is off for no temporal layers and >1 streams with nack on.
774 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
775 vie_encoder_->Stop();
776}
777
778TEST_F(ViEEncoderTest, Vp8ResilienceIsOnFor1S1TLWithNackDisabled) {
779 const bool kNackEnabled = false;
780 const size_t kNumStreams = 1;
781 const size_t kNumTl = 1;
sprang317005a2017-06-08 07:12:17 -0700782 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800783 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
784
785 // Capture a frame and wait for it to synchronize with the encoder thread.
786 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang317005a2017-06-08 07:12:17 -0700787 sink_.WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800788 // The encoder have been configured once when the first frame is received.
789 EXPECT_EQ(1, sink_.number_of_reconfigurations());
790 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
791 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
792 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
793 // Resilience is on for no temporal layers with nack off.
794 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
795 vie_encoder_->Stop();
796}
797
798TEST_F(ViEEncoderTest, Vp8ResilienceIsOnFor1S2TlWithNackEnabled) {
799 const bool kNackEnabled = true;
800 const size_t kNumStreams = 1;
801 const size_t kNumTl = 2;
sprang317005a2017-06-08 07:12:17 -0700802 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800803 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
804
805 // Capture a frame and wait for it to synchronize with the encoder thread.
806 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang317005a2017-06-08 07:12:17 -0700807 sink_.WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800808 // The encoder have been configured once when the first frame is received.
809 EXPECT_EQ(1, sink_.number_of_reconfigurations());
810 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
811 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
812 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
813 // Resilience is on for temporal layers.
814 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
815 vie_encoder_->Stop();
816}
817
perkj803d97f2016-11-01 11:45:46 -0700818TEST_F(ViEEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
819 EXPECT_TRUE(video_source_.has_sinks());
820 test::FrameForwarder new_video_source;
sprangc5d62e22017-04-02 23:53:04 -0700821 vie_encoder_->SetSource(
822 &new_video_source,
823 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -0700824 EXPECT_FALSE(video_source_.has_sinks());
825 EXPECT_TRUE(new_video_source.has_sinks());
826
827 vie_encoder_->Stop();
828}
829
830TEST_F(ViEEncoderTest, SinkWantsRotationApplied) {
831 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
832 vie_encoder_->SetSink(&sink_, true /*rotation_applied*/);
833 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
834 vie_encoder_->Stop();
835}
836
837TEST_F(ViEEncoderTest, SinkWantsFromOveruseDetector) {
asaperssond0de2952017-04-21 01:47:31 -0700838 const int kMaxDowngrades = ViEEncoder::kMaxCpuResolutionDowngrades;
perkj803d97f2016-11-01 11:45:46 -0700839 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
840
asapersson02465b82017-04-10 01:12:52 -0700841 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700842
843 int frame_width = 1280;
844 int frame_height = 720;
845
846 // Trigger CPU overuse kMaxCpuDowngrades times. Every time, ViEEncoder should
847 // request lower resolution.
asaperssond0de2952017-04-21 01:47:31 -0700848 for (int i = 1; i <= kMaxDowngrades; ++i) {
perkj803d97f2016-11-01 11:45:46 -0700849 video_source_.IncomingCapturedFrame(
850 CreateFrame(i, frame_width, frame_height));
sprang317005a2017-06-08 07:12:17 -0700851 sink_.WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -0700852
853 vie_encoder_->TriggerCpuOveruse();
854
sprang84a37592017-02-10 07:04:27 -0800855 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700856 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
perkj803d97f2016-11-01 11:45:46 -0700857 frame_width * frame_height);
asaperssond0de2952017-04-21 01:47:31 -0700858 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
859 EXPECT_EQ(i, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -0700860
861 frame_width /= 2;
862 frame_height /= 2;
863 }
864
kthelgason876222f2016-11-29 01:44:11 -0800865 // Trigger CPU overuse one more time. This should not trigger a request for
perkj803d97f2016-11-01 11:45:46 -0700866 // lower resolution.
867 rtc::VideoSinkWants current_wants = video_source_.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -0700868 video_source_.IncomingCapturedFrame(
869 CreateFrame(kMaxDowngrades + 1, frame_width, frame_height));
sprang317005a2017-06-08 07:12:17 -0700870 sink_.WaitForEncodedFrame(kMaxDowngrades + 1);
perkj803d97f2016-11-01 11:45:46 -0700871 vie_encoder_->TriggerCpuOveruse();
sprang84a37592017-02-10 07:04:27 -0800872 EXPECT_EQ(video_source_.sink_wants().target_pixel_count,
873 current_wants.target_pixel_count);
perkj803d97f2016-11-01 11:45:46 -0700874 EXPECT_EQ(video_source_.sink_wants().max_pixel_count,
875 current_wants.max_pixel_count);
asaperssond0de2952017-04-21 01:47:31 -0700876 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
877 EXPECT_EQ(kMaxDowngrades,
878 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -0700879
880 // Trigger CPU normal use.
881 vie_encoder_->TriggerCpuNormalUsage();
sprang84a37592017-02-10 07:04:27 -0800882 EXPECT_EQ(frame_width * frame_height * 5 / 3,
883 video_source_.sink_wants().target_pixel_count.value_or(0));
884 EXPECT_EQ(frame_width * frame_height * 4,
sprangc5d62e22017-04-02 23:53:04 -0700885 video_source_.sink_wants().max_pixel_count);
asaperssond0de2952017-04-21 01:47:31 -0700886 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
887 EXPECT_EQ(kMaxDowngrades + 1,
888 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -0700889
890 vie_encoder_->Stop();
891}
892
asaperssonf7e294d2017-06-13 23:25:22 -0700893TEST_F(ViEEncoderTest, TestMaxCpuResolutionDowngrades_BalancedMode_NoFpsLimit) {
894 const int kMaxDowngrades = ViEEncoder::kMaxCpuResolutionDowngrades;
895 const int kWidth = 1280;
896 const int kHeight = 720;
897 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
898
899 // Enable kBalanced preference, no initial limitation.
900 AdaptingFrameForwarder source;
901 source.set_adaptation_enabled(true);
902 vie_encoder_->SetSource(&source,
903 VideoSendStream::DegradationPreference::kBalanced);
904 VerifyNoLimitation(source.sink_wants());
905 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
906 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
907
908 // Trigger adapt down kMaxCpuDowngrades times.
909 int t = 1;
910 for (int i = 1; i <= kMaxDowngrades; ++i) {
911 source.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
912 sink_.WaitForEncodedFrame(t++);
913 vie_encoder_->TriggerCpuOveruse();
914 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
915 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
916 EXPECT_EQ(i, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
917 }
918
919 // Trigger adapt down, max cpu downgrades reach, expect no change.
920 rtc::VideoSinkWants last_wants = source.sink_wants();
921 source.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
922 sink_.WaitForEncodedFrame(t++);
923 vie_encoder_->TriggerCpuOveruse();
924 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
925 EXPECT_EQ(last_wants.max_pixel_count, source.sink_wants().max_pixel_count);
926 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
927 EXPECT_EQ(kMaxDowngrades,
928 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
929
930 // Trigger adapt up kMaxCpuDowngrades times.
931 for (int i = 1; i <= kMaxDowngrades; ++i) {
932 source.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
933 sink_.WaitForEncodedFrame(t++);
934 vie_encoder_->TriggerCpuNormalUsage();
935 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
936 EXPECT_GT(source.sink_wants().max_pixel_count, last_wants.max_pixel_count);
937 EXPECT_EQ(kMaxDowngrades + i,
938 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
939 }
940
941 VerifyNoLimitation(source.sink_wants());
942 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
943
944 vie_encoder_->Stop();
945}
sprangc5d62e22017-04-02 23:53:04 -0700946TEST_F(ViEEncoderTest, SinkWantsStoredByDegradationPreference) {
perkj803d97f2016-11-01 11:45:46 -0700947 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -0700948 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700949
sprangc5d62e22017-04-02 23:53:04 -0700950 const int kFrameWidth = 1280;
951 const int kFrameHeight = 720;
952 const int kFrameIntervalMs = 1000 / 30;
953
954 int frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -0700955
kthelgason5e13d412016-12-01 03:59:51 -0800956 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700957 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -0700958 sink_.WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700959 frame_timestamp += kFrameIntervalMs;
960
perkj803d97f2016-11-01 11:45:46 -0700961 // Trigger CPU overuse.
962 vie_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700963 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700964 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -0700965 sink_.WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700966 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -0700967
asapersson0944a802017-04-07 00:57:58 -0700968 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -0700969 // wanted resolution.
970 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
971 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
972 kFrameWidth * kFrameHeight);
973 EXPECT_EQ(std::numeric_limits<int>::max(),
974 video_source_.sink_wants().max_framerate_fps);
975
976 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -0700977 test::FrameForwarder new_video_source;
978 vie_encoder_->SetSource(
979 &new_video_source,
980 VideoSendStream::DegradationPreference::kMaintainResolution);
981
sprangc5d62e22017-04-02 23:53:04 -0700982 // Initially no degradation registered.
asapersson02465b82017-04-10 01:12:52 -0700983 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700984
sprangc5d62e22017-04-02 23:53:04 -0700985 // Force an input frame rate to be available, or the adaptation call won't
986 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -0700987 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -0700988 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -0700989 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -0700990 stats_proxy_->SetMockStats(stats);
991
992 vie_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700993 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700994 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -0700995 sink_.WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700996 frame_timestamp += kFrameIntervalMs;
997
998 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -0800999 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001000 EXPECT_EQ(std::numeric_limits<int>::max(),
1001 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001002 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001003
asapersson02465b82017-04-10 01:12:52 -07001004 // Turn off degradation completely.
sprangc5d62e22017-04-02 23:53:04 -07001005 vie_encoder_->SetSource(
1006 &new_video_source,
1007 VideoSendStream::DegradationPreference::kDegradationDisabled);
asapersson02465b82017-04-10 01:12:52 -07001008 VerifyNoLimitation(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001009
1010 vie_encoder_->TriggerCpuOveruse();
1011 new_video_source.IncomingCapturedFrame(
1012 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07001013 sink_.WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001014 frame_timestamp += kFrameIntervalMs;
1015
1016 // Still no degradation.
asapersson02465b82017-04-10 01:12:52 -07001017 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001018
1019 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
sprangc5d62e22017-04-02 23:53:04 -07001020 vie_encoder_->SetSource(
1021 &new_video_source,
1022 VideoSendStream::DegradationPreference::kMaintainFramerate);
1023 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1024 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001025 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001026 EXPECT_EQ(std::numeric_limits<int>::max(),
1027 new_video_source.sink_wants().max_framerate_fps);
1028
1029 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
1030 vie_encoder_->SetSource(
1031 &new_video_source,
1032 VideoSendStream::DegradationPreference::kMaintainResolution);
1033 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1034 EXPECT_EQ(std::numeric_limits<int>::max(),
1035 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001036 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001037
1038 vie_encoder_->Stop();
1039}
1040
asaperssonfab67072017-04-04 05:51:49 -07001041TEST_F(ViEEncoderTest, StatsTracksQualityAdaptationStats) {
perkj803d97f2016-11-01 11:45:46 -07001042 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1043
asaperssonfab67072017-04-04 05:51:49 -07001044 const int kWidth = 1280;
1045 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001046 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001047 sink_.WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001048 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1049 EXPECT_FALSE(stats.bw_limited_resolution);
1050 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1051
1052 // Trigger adapt down.
1053 vie_encoder_->TriggerQualityLow();
1054 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001055 sink_.WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001056
1057 stats = stats_proxy_->GetStats();
1058 EXPECT_TRUE(stats.bw_limited_resolution);
1059 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1060
1061 // Trigger adapt up.
1062 vie_encoder_->TriggerQualityHigh();
1063 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001064 sink_.WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001065
1066 stats = stats_proxy_->GetStats();
1067 EXPECT_FALSE(stats.bw_limited_resolution);
1068 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1069 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1070
1071 vie_encoder_->Stop();
1072}
1073
1074TEST_F(ViEEncoderTest, StatsTracksCpuAdaptationStats) {
1075 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1076
1077 const int kWidth = 1280;
1078 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001079 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001080 sink_.WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001081 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1082 EXPECT_FALSE(stats.cpu_limited_resolution);
1083 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1084
1085 // Trigger CPU overuse.
1086 vie_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001087 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001088 sink_.WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001089
1090 stats = stats_proxy_->GetStats();
1091 EXPECT_TRUE(stats.cpu_limited_resolution);
1092 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1093
1094 // Trigger CPU normal use.
1095 vie_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001096 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001097 sink_.WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001098
1099 stats = stats_proxy_->GetStats();
1100 EXPECT_FALSE(stats.cpu_limited_resolution);
1101 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001102 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001103
1104 vie_encoder_->Stop();
1105}
1106
kthelgason876222f2016-11-29 01:44:11 -08001107TEST_F(ViEEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
kthelgason876222f2016-11-29 01:44:11 -08001108 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1109
asaperssonfab67072017-04-04 05:51:49 -07001110 const int kWidth = 1280;
1111 const int kHeight = 720;
1112 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001113 sink_.WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001114 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001115 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001116 EXPECT_FALSE(stats.cpu_limited_resolution);
1117 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1118
asaperssonfab67072017-04-04 05:51:49 -07001119 // Trigger CPU overuse.
kthelgason876222f2016-11-29 01:44:11 -08001120 vie_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001121 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001122 sink_.WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001123 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001124 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001125 EXPECT_TRUE(stats.cpu_limited_resolution);
1126 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1127
1128 // Set new source with adaptation still enabled.
1129 test::FrameForwarder new_video_source;
sprangc5d62e22017-04-02 23:53:04 -07001130 vie_encoder_->SetSource(
1131 &new_video_source,
1132 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001133
asaperssonfab67072017-04-04 05:51:49 -07001134 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001135 sink_.WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001136 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001137 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001138 EXPECT_TRUE(stats.cpu_limited_resolution);
1139 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1140
1141 // Set adaptation disabled.
1142 vie_encoder_->SetSource(
1143 &new_video_source,
sprangc5d62e22017-04-02 23:53:04 -07001144 VideoSendStream::DegradationPreference::kDegradationDisabled);
kthelgason876222f2016-11-29 01:44:11 -08001145
asaperssonfab67072017-04-04 05:51:49 -07001146 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001147 sink_.WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001148 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001149 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001150 EXPECT_FALSE(stats.cpu_limited_resolution);
1151 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1152
1153 // Set adaptation back to enabled.
sprangc5d62e22017-04-02 23:53:04 -07001154 vie_encoder_->SetSource(
1155 &new_video_source,
1156 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001157
asaperssonfab67072017-04-04 05:51:49 -07001158 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001159 sink_.WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001160 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001161 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001162 EXPECT_TRUE(stats.cpu_limited_resolution);
1163 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1164
asaperssonfab67072017-04-04 05:51:49 -07001165 // Trigger CPU normal use.
kthelgason876222f2016-11-29 01:44:11 -08001166 vie_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001167 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001168 sink_.WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001169 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001170 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001171 EXPECT_FALSE(stats.cpu_limited_resolution);
1172 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001173 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001174
1175 vie_encoder_->Stop();
1176}
1177
1178TEST_F(ViEEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
kthelgason876222f2016-11-29 01:44:11 -08001179 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1180
asaperssonfab67072017-04-04 05:51:49 -07001181 const int kWidth = 1280;
1182 const int kHeight = 720;
1183 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001184 sink_.WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001185 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001186 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001187 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001188 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001189
1190 // Set new source with adaptation still enabled.
1191 test::FrameForwarder new_video_source;
1192 vie_encoder_->SetSource(&new_video_source,
1193 VideoSendStream::DegradationPreference::kBalanced);
1194
asaperssonfab67072017-04-04 05:51:49 -07001195 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001196 sink_.WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001197 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001198 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001199 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001200 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001201
asaperssonfab67072017-04-04 05:51:49 -07001202 // Trigger adapt down.
kthelgason876222f2016-11-29 01:44:11 -08001203 vie_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001204 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001205 sink_.WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001206 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001207 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001208 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001209 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001210
asaperssonfab67072017-04-04 05:51:49 -07001211 // Set new source with adaptation still enabled.
kthelgason876222f2016-11-29 01:44:11 -08001212 vie_encoder_->SetSource(&new_video_source,
1213 VideoSendStream::DegradationPreference::kBalanced);
1214
asaperssonfab67072017-04-04 05:51:49 -07001215 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001216 sink_.WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001217 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001218 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001219 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001220 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001221
asapersson02465b82017-04-10 01:12:52 -07001222 // Disable resolution scaling.
kthelgason876222f2016-11-29 01:44:11 -08001223 vie_encoder_->SetSource(
1224 &new_video_source,
1225 VideoSendStream::DegradationPreference::kMaintainResolution);
1226
asaperssonfab67072017-04-04 05:51:49 -07001227 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001228 sink_.WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001229 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001230 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001231 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001232 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1233 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001234
1235 vie_encoder_->Stop();
1236}
1237
asapersson36e9eb42017-03-31 05:29:12 -07001238TEST_F(ViEEncoderTest, QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1239 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1240
1241 const int kWidth = 1280;
1242 const int kHeight = 720;
1243 video_source_.set_adaptation_enabled(true);
1244 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001245 sink_.WaitForEncodedFrame(1);
asapersson36e9eb42017-03-31 05:29:12 -07001246 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1247 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1248 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1249
1250 // Trigger adapt down.
1251 vie_encoder_->TriggerQualityLow();
1252 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001253 sink_.WaitForEncodedFrame(2);
asapersson36e9eb42017-03-31 05:29:12 -07001254 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1255 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1256 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1257
1258 // Trigger overuse.
1259 vie_encoder_->TriggerCpuOveruse();
1260 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001261 sink_.WaitForEncodedFrame(3);
asapersson36e9eb42017-03-31 05:29:12 -07001262 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1263 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1264 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1265
1266 // Set source with adaptation still enabled but quality scaler is off.
1267 fake_encoder_.SetQualityScaling(false);
sprangc5d62e22017-04-02 23:53:04 -07001268 vie_encoder_->SetSource(
1269 &video_source_,
1270 VideoSendStream::DegradationPreference::kMaintainFramerate);
asapersson36e9eb42017-03-31 05:29:12 -07001271
1272 video_source_.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001273 sink_.WaitForEncodedFrame(4);
asapersson36e9eb42017-03-31 05:29:12 -07001274 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1275 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1276 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1277
1278 vie_encoder_->Stop();
1279}
1280
asapersson02465b82017-04-10 01:12:52 -07001281TEST_F(ViEEncoderTest, StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
perkj803d97f2016-11-01 11:45:46 -07001282 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1283
asapersson0944a802017-04-07 00:57:58 -07001284 const int kWidth = 1280;
1285 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001286 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001287
asaperssonfab67072017-04-04 05:51:49 -07001288 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001289 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001290 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001291 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001292 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001293 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1294
asapersson02465b82017-04-10 01:12:52 -07001295 // Trigger CPU overuse, should now adapt down.
sprang84a37592017-02-10 07:04:27 -08001296 vie_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001297 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001298 sink_.WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001299 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001300 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001301 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001302 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1303
1304 // Set new source with adaptation still enabled.
1305 test::FrameForwarder new_video_source;
sprangc5d62e22017-04-02 23:53:04 -07001306 vie_encoder_->SetSource(
1307 &new_video_source,
1308 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001309
1310 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001311 CreateFrame(sequence, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001312 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001313 stats = stats_proxy_->GetStats();
1314 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001315 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001316 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1317
sprangc5d62e22017-04-02 23:53:04 -07001318 // Set cpu adaptation by frame dropping.
perkj803d97f2016-11-01 11:45:46 -07001319 vie_encoder_->SetSource(
1320 &new_video_source,
1321 VideoSendStream::DegradationPreference::kMaintainResolution);
1322 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001323 CreateFrame(sequence, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001324 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001325 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001326 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001327 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001328 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001329 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1330
sprangc5d62e22017-04-02 23:53:04 -07001331 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001332 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001333 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1334 mock_stats.input_frame_rate = 30;
1335 stats_proxy_->SetMockStats(mock_stats);
1336 vie_encoder_->TriggerCpuOveruse();
1337 stats_proxy_->ResetMockStats();
1338
1339 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001340 CreateFrame(sequence, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001341 sink_.WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001342
1343 // Framerate now adapted.
1344 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001345 EXPECT_FALSE(stats.cpu_limited_resolution);
1346 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001347 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1348
1349 // Disable CPU adaptation.
1350 vie_encoder_->SetSource(
1351 &new_video_source,
1352 VideoSendStream::DegradationPreference::kDegradationDisabled);
1353 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001354 CreateFrame(sequence, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001355 sink_.WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001356
1357 stats = stats_proxy_->GetStats();
1358 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001359 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001360 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1361
1362 // Try to trigger overuse. Should not succeed.
1363 stats_proxy_->SetMockStats(mock_stats);
1364 vie_encoder_->TriggerCpuOveruse();
1365 stats_proxy_->ResetMockStats();
1366
1367 stats = stats_proxy_->GetStats();
1368 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001369 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001370 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1371
1372 // Switch back the source with resolution adaptation enabled.
1373 vie_encoder_->SetSource(
1374 &video_source_,
1375 VideoSendStream::DegradationPreference::kMaintainFramerate);
asaperssonfab67072017-04-04 05:51:49 -07001376 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001377 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001378 stats = stats_proxy_->GetStats();
1379 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001380 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001381 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001382
1383 // Trigger CPU normal usage.
1384 vie_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001385 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001386 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001387 stats = stats_proxy_->GetStats();
1388 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001389 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001390 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1391
1392 // Back to the source with adaptation off, set it back to maintain-resolution.
1393 vie_encoder_->SetSource(
1394 &new_video_source,
1395 VideoSendStream::DegradationPreference::kMaintainResolution);
1396 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001397 CreateFrame(sequence, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001398 sink_.WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001399 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001400 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001401 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001402 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001403 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1404
1405 // Trigger CPU normal usage.
1406 vie_encoder_->TriggerCpuNormalUsage();
1407 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001408 CreateFrame(sequence, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001409 sink_.WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001410 stats = stats_proxy_->GetStats();
1411 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001412 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001413 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001414 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001415
1416 vie_encoder_->Stop();
1417}
1418
Erik Språng08127a92016-11-16 16:41:30 +01001419TEST_F(ViEEncoderTest, StatsTracksPreferredBitrate) {
Erik Språng08127a92016-11-16 16:41:30 +01001420 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1421
asaperssonfab67072017-04-04 05:51:49 -07001422 const int kWidth = 1280;
1423 const int kHeight = 720;
1424 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001425 sink_.WaitForEncodedFrame(1);
Erik Språng08127a92016-11-16 16:41:30 +01001426
1427 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1428 EXPECT_EQ(video_encoder_config_.max_bitrate_bps,
1429 stats.preferred_media_bitrate_bps);
1430
1431 vie_encoder_->Stop();
1432}
1433
kthelgason876222f2016-11-29 01:44:11 -08001434TEST_F(ViEEncoderTest, ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001435 const int kWidth = 1280;
1436 const int kHeight = 720;
kthelgason876222f2016-11-29 01:44:11 -08001437 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1438
asaperssonfab67072017-04-04 05:51:49 -07001439 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001440 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001441
asaperssonfab67072017-04-04 05:51:49 -07001442 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001443 sink_.WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001444
asaperssonfab67072017-04-04 05:51:49 -07001445 // Trigger scale down.
kthelgason5e13d412016-12-01 03:59:51 -08001446 vie_encoder_->TriggerQualityLow();
1447
asaperssonfab67072017-04-04 05:51:49 -07001448 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001449 sink_.WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001450
kthelgason876222f2016-11-29 01:44:11 -08001451 // Expect a scale down.
1452 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001453 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001454
asapersson02465b82017-04-10 01:12:52 -07001455 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001456 test::FrameForwarder new_video_source;
1457 vie_encoder_->SetSource(
1458 &new_video_source,
1459 VideoSendStream::DegradationPreference::kMaintainResolution);
1460
asaperssonfab67072017-04-04 05:51:49 -07001461 // Trigger scale down.
kthelgason876222f2016-11-29 01:44:11 -08001462 vie_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001463 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001464 sink_.WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001465
asaperssonfab67072017-04-04 05:51:49 -07001466 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001467 EXPECT_EQ(std::numeric_limits<int>::max(),
1468 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001469
asaperssonfab67072017-04-04 05:51:49 -07001470 // Trigger scale up.
kthelgason876222f2016-11-29 01:44:11 -08001471 vie_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001472 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001473 sink_.WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001474
asapersson02465b82017-04-10 01:12:52 -07001475 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001476 EXPECT_EQ(std::numeric_limits<int>::max(),
1477 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001478
1479 vie_encoder_->Stop();
1480}
1481
asapersson02465b82017-04-10 01:12:52 -07001482TEST_F(ViEEncoderTest, SkipsSameAdaptDownRequest_MaintainFramerateMode) {
1483 const int kWidth = 1280;
1484 const int kHeight = 720;
1485 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1486
1487 // Enable kMaintainFramerate preference, no initial limitation.
1488 test::FrameForwarder source;
1489 vie_encoder_->SetSource(
1490 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1491
1492 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001493 sink_.WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001494 VerifyNoLimitation(source.sink_wants());
1495 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1496 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1497
1498 // Trigger adapt down, expect scaled down resolution.
1499 vie_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001500 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001501 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1502 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1503 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1504
1505 // Trigger adapt down for same input resolution, expect no change.
1506 vie_encoder_->TriggerCpuOveruse();
1507 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1508 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1509 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1510
1511 vie_encoder_->Stop();
1512}
1513
asaperssonf7e294d2017-06-13 23:25:22 -07001514TEST_F(ViEEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
1515 const int kWidth = 1280;
1516 const int kHeight = 720;
1517 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1518
1519 // Enable kBalanced preference, no initial limitation.
1520 test::FrameForwarder source;
1521 vie_encoder_->SetSource(&source,
1522 VideoSendStream::DegradationPreference::kBalanced);
1523 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1524 sink_.WaitForEncodedFrame(1);
1525 VerifyNoLimitation(source.sink_wants());
1526
1527 // Trigger adapt down, expect scaled down resolution.
1528 vie_encoder_->TriggerQualityLow();
1529 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1530 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1531 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1532 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1533
1534 // Trigger adapt down for same input resolution, expect no change.
1535 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1536 sink_.WaitForEncodedFrame(2);
1537 vie_encoder_->TriggerQualityLow();
1538 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1539 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1540 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1541
1542 // Trigger adapt down for larger input resolution, expect no change.
1543 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1544 sink_.WaitForEncodedFrame(3);
1545 vie_encoder_->TriggerQualityLow();
1546 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1547 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1548 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1549
1550 vie_encoder_->Stop();
1551}
1552
asapersson02465b82017-04-10 01:12:52 -07001553TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_MaintainFramerateMode) {
1554 const int kWidth = 1280;
1555 const int kHeight = 720;
1556 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1557
1558 // Enable kMaintainFramerate preference, no initial limitation.
1559 test::FrameForwarder source;
1560 vie_encoder_->SetSource(
1561 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1562
1563 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001564 sink_.WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001565 VerifyNoLimitation(source.sink_wants());
1566 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1567 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1568
1569 // Trigger adapt up, expect no change.
1570 vie_encoder_->TriggerCpuNormalUsage();
1571 VerifyNoLimitation(source.sink_wants());
1572 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1573 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1574
1575 vie_encoder_->Stop();
1576}
1577
1578TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_MaintainResolutionMode) {
1579 const int kWidth = 1280;
1580 const int kHeight = 720;
1581 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1582
1583 // Enable kMaintainResolution preference, no initial limitation.
1584 test::FrameForwarder source;
1585 vie_encoder_->SetSource(
1586 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
1587
1588 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001589 sink_.WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001590 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001591 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001592 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1593
1594 // Trigger adapt up, expect no change.
1595 vie_encoder_->TriggerCpuNormalUsage();
1596 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001597 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001598 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1599
1600 vie_encoder_->Stop();
1601}
1602
asaperssonf7e294d2017-06-13 23:25:22 -07001603TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
1604 const int kWidth = 1280;
1605 const int kHeight = 720;
1606 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1607
1608 // Enable kBalanced preference, no initial limitation.
1609 test::FrameForwarder source;
1610 vie_encoder_->SetSource(&source,
1611 VideoSendStream::DegradationPreference::kBalanced);
1612
1613 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1614 sink_.WaitForEncodedFrame(kWidth, kHeight);
1615 VerifyNoLimitation(source.sink_wants());
1616 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1617 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1618 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1619
1620 // Trigger adapt up, expect no change.
1621 vie_encoder_->TriggerQualityHigh();
1622 VerifyNoLimitation(source.sink_wants());
1623 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1624 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1625 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1626
1627 vie_encoder_->Stop();
1628}
1629
asapersson09f05612017-05-15 23:40:18 -07001630TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
1631 const int kWidth = 1280;
1632 const int kHeight = 720;
1633 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1634
1635 // Enable kDegradationDisabled preference, no initial limitation.
1636 test::FrameForwarder source;
1637 vie_encoder_->SetSource(
1638 &source, VideoSendStream::DegradationPreference::kDegradationDisabled);
1639
1640 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1641 sink_.WaitForEncodedFrame(kWidth, kHeight);
1642 VerifyNoLimitation(source.sink_wants());
1643 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1644 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1645 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1646
1647 // Trigger adapt up, expect no change.
1648 vie_encoder_->TriggerQualityHigh();
1649 VerifyNoLimitation(source.sink_wants());
1650 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1651 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1652 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1653
1654 vie_encoder_->Stop();
1655}
1656
asapersson02465b82017-04-10 01:12:52 -07001657TEST_F(ViEEncoderTest, AdaptsResolutionForLowQuality_MaintainFramerateMode) {
1658 const int kWidth = 1280;
1659 const int kHeight = 720;
1660 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1661
1662 // Enable kMaintainFramerate preference, no initial limitation.
1663 AdaptingFrameForwarder source;
1664 source.set_adaptation_enabled(true);
1665 vie_encoder_->SetSource(
1666 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1667
1668 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001669 sink_.WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001670 VerifyNoLimitation(source.sink_wants());
1671 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1672 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1673
1674 // Trigger adapt down, expect scaled down resolution.
1675 vie_encoder_->TriggerQualityLow();
1676 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001677 sink_.WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001678 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001679 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1680 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1681
1682 // Trigger adapt up, expect no restriction.
1683 vie_encoder_->TriggerQualityHigh();
1684 VerifyNoLimitation(source.sink_wants());
1685 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1686 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1687 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1688
1689 vie_encoder_->Stop();
1690}
1691
asapersson09f05612017-05-15 23:40:18 -07001692TEST_F(ViEEncoderTest, AdaptsFramerateForLowQuality_MaintainResolutionMode) {
1693 const int kWidth = 1280;
1694 const int kHeight = 720;
1695 const int kInputFps = 30;
1696 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1697
1698 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1699 stats.input_frame_rate = kInputFps;
1700 stats_proxy_->SetMockStats(stats);
1701
1702 // Expect no scaling to begin with (preference: kMaintainFramerate).
1703 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1704 sink_.WaitForEncodedFrame(1);
1705 VerifyNoLimitation(video_source_.sink_wants());
1706
1707 // Trigger adapt down, expect scaled down resolution.
1708 vie_encoder_->TriggerQualityLow();
1709 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1710 sink_.WaitForEncodedFrame(2);
1711 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1712
1713 // Enable kMaintainResolution preference.
1714 test::FrameForwarder new_video_source;
1715 vie_encoder_->SetSource(
1716 &new_video_source,
1717 VideoSendStream::DegradationPreference::kMaintainResolution);
1718 VerifyNoLimitation(new_video_source.sink_wants());
1719
1720 // Trigger adapt down, expect reduced framerate.
1721 vie_encoder_->TriggerQualityLow();
1722 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1723 sink_.WaitForEncodedFrame(3);
1724 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1725
1726 // Trigger adapt up, expect no restriction.
1727 vie_encoder_->TriggerQualityHigh();
1728 VerifyNoLimitation(new_video_source.sink_wants());
1729
1730 vie_encoder_->Stop();
1731}
1732
asaperssond0de2952017-04-21 01:47:31 -07001733TEST_F(ViEEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
1734 const int kWidth = 1280;
1735 const int kHeight = 720;
1736 const size_t kNumFrames = 10;
1737
kthelgason5e13d412016-12-01 03:59:51 -08001738 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1739
asaperssond0de2952017-04-21 01:47:31 -07001740 // Enable adapter, expected input resolutions when downscaling:
1741 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (min resolution limit)
1742 video_source_.set_adaptation_enabled(true);
1743
1744 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1745 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1746
1747 int downscales = 0;
1748 for (size_t i = 1; i <= kNumFrames; i++) {
1749 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001750 sink_.WaitForEncodedFrame(i);
asaperssond0de2952017-04-21 01:47:31 -07001751
asaperssonfab67072017-04-04 05:51:49 -07001752 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001753 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
kthelgason5e13d412016-12-01 03:59:51 -08001754 vie_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001755 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001756
1757 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1758 ++downscales;
1759
1760 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1761 EXPECT_EQ(downscales,
1762 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1763 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001764 }
asaperssond0de2952017-04-21 01:47:31 -07001765 vie_encoder_->Stop();
1766}
1767
1768TEST_F(ViEEncoderTest,
1769 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1770 const int kWidth = 1280;
1771 const int kHeight = 720;
1772 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1773
1774 // Enable kMaintainFramerate preference, no initial limitation.
1775 AdaptingFrameForwarder source;
1776 source.set_adaptation_enabled(true);
1777 vie_encoder_->SetSource(
1778 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1779
1780 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001781 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001782 VerifyNoLimitation(source.sink_wants());
1783 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1784 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1785
1786 // Trigger adapt down, expect scaled down resolution.
1787 vie_encoder_->TriggerCpuOveruse();
1788 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001789 sink_.WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001790 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001791 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1792 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1793
1794 // Trigger adapt up, expect no restriction.
1795 vie_encoder_->TriggerCpuNormalUsage();
1796 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001797 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001798 VerifyNoLimitation(source.sink_wants());
1799 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1800 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1801
1802 // Trigger adapt down, expect scaled down resolution.
1803 vie_encoder_->TriggerCpuOveruse();
1804 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001805 sink_.WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07001806 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001807 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1808 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1809
1810 // Trigger adapt up, expect no restriction.
1811 vie_encoder_->TriggerCpuNormalUsage();
asapersson09f05612017-05-15 23:40:18 -07001812 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1813 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001814 VerifyNoLimitation(source.sink_wants());
1815 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1816 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1817
1818 vie_encoder_->Stop();
1819}
1820
1821TEST_F(ViEEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07001822 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
1823 const int kWidth = 1280;
1824 const int kHeight = 720;
1825 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1826
1827 // Enable kBalanced preference, no initial limitation.
1828 AdaptingFrameForwarder source;
1829 source.set_adaptation_enabled(true);
1830 vie_encoder_->SetSource(&source,
1831 VideoSendStream::DegradationPreference::kBalanced);
1832
1833 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1834 sink_.WaitForEncodedFrame(kWidth, kHeight);
1835 VerifyNoLimitation(source.sink_wants());
1836 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1837 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1838
1839 // Trigger adapt down, expect scaled down resolution.
1840 vie_encoder_->TriggerQualityLow();
1841 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1842 sink_.WaitForEncodedFrame(2);
1843 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1844 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1845 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1846
1847 // Trigger adapt up, expect no restriction.
1848 vie_encoder_->TriggerQualityHigh();
1849 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1850 sink_.WaitForEncodedFrame(kWidth, kHeight);
1851 VerifyNoLimitation(source.sink_wants());
1852 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1853 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1854
1855 // Trigger adapt down, expect scaled down resolution.
1856 vie_encoder_->TriggerQualityLow();
1857 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
1858 sink_.WaitForEncodedFrame(4);
1859 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1860 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1861 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1862
1863 // Trigger adapt up, expect no restriction.
1864 vie_encoder_->TriggerQualityHigh();
1865 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1866 sink_.WaitForEncodedFrame(kWidth, kHeight);
1867 VerifyNoLimitation(source.sink_wants());
1868 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1869 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1870
1871 vie_encoder_->Stop();
1872}
1873
1874TEST_F(ViEEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001875 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
1876 const int kWidth = 1280;
1877 const int kHeight = 720;
1878 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1879
1880 // Enable kMaintainFramerate preference, no initial limitation.
1881 AdaptingFrameForwarder source;
1882 source.set_adaptation_enabled(true);
1883 vie_encoder_->SetSource(
1884 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1885
1886 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001887 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001888 VerifyNoLimitation(source.sink_wants());
1889 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1890 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1891 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1892 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1893
1894 // Trigger cpu adapt down, expect scaled down resolution (960x540).
1895 vie_encoder_->TriggerCpuOveruse();
1896 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001897 sink_.WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001898 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001899 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1900 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1901 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1902 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1903
1904 // Trigger cpu adapt down, expect scaled down resolution (640x360).
1905 vie_encoder_->TriggerCpuOveruse();
1906 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001907 sink_.WaitForEncodedFrame(3);
asapersson09f05612017-05-15 23:40:18 -07001908 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
1909 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07001910 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1911 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1912 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1913 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1914
1915 // Trigger cpu adapt down, max cpu downgrades reached, expect no change.
1916 vie_encoder_->TriggerCpuOveruse();
1917 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001918 sink_.WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07001919 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07001920 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1921 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1922 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1923 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1924
1925 // Trigger quality adapt down, expect scaled down resolution (480x270).
1926 vie_encoder_->TriggerQualityLow();
1927 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001928 sink_.WaitForEncodedFrame(5);
asapersson09f05612017-05-15 23:40:18 -07001929 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001930 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1931 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1932 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1933 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1934
1935 // Trigger cpu adapt up, expect upscaled resolution (640x360).
1936 vie_encoder_->TriggerCpuNormalUsage();
1937 source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001938 sink_.WaitForEncodedFrame(6);
asapersson09f05612017-05-15 23:40:18 -07001939 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001940 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1941 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1942 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1943 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1944
1945 // Trigger cpu adapt up, expect upscaled resolution (960x540).
1946 vie_encoder_->TriggerCpuNormalUsage();
1947 source.IncomingCapturedFrame(CreateFrame(7, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001948 sink_.WaitForEncodedFrame(7);
asapersson09f05612017-05-15 23:40:18 -07001949 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001950 last_wants = source.sink_wants();
1951 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1952 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1953 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1954 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1955
1956 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
1957 vie_encoder_->TriggerCpuNormalUsage();
1958 source.IncomingCapturedFrame(CreateFrame(8, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001959 sink_.WaitForEncodedFrame(8);
asapersson09f05612017-05-15 23:40:18 -07001960 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07001961 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1962 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1963 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1964 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1965
1966 // Trigger quality adapt up, expect no restriction (1280x720).
1967 vie_encoder_->TriggerQualityHigh();
1968 source.IncomingCapturedFrame(CreateFrame(9, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001969 sink_.WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07001970 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001971 VerifyNoLimitation(source.sink_wants());
1972 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1973 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1974 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1975 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08001976
1977 vie_encoder_->Stop();
1978}
1979
asaperssonf4e44af2017-04-19 02:01:06 -07001980TEST_F(ViEEncoderTest, CpuLimitedHistogramIsReported) {
sprang317005a2017-06-08 07:12:17 -07001981 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001982 const int kWidth = 640;
1983 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07001984
1985 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07001986 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001987 sink_.WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07001988 }
1989
1990 vie_encoder_->TriggerCpuOveruse();
1991 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07001992 video_source_.IncomingCapturedFrame(CreateFrame(
1993 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001994 sink_.WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples +
1995 i);
perkj803d97f2016-11-01 11:45:46 -07001996 }
1997
1998 vie_encoder_->Stop();
sprangf8ee65e2017-02-28 08:49:33 -08001999 vie_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002000 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002001
perkj803d97f2016-11-01 11:45:46 -07002002 EXPECT_EQ(1,
2003 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2004 EXPECT_EQ(
2005 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2006}
2007
asaperssonf4e44af2017-04-19 02:01:06 -07002008TEST_F(ViEEncoderTest, CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2009 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2010 const int kWidth = 640;
2011 const int kHeight = 360;
2012
2013 vie_encoder_->SetSource(
2014 &video_source_,
2015 VideoSendStream::DegradationPreference::kDegradationDisabled);
2016
2017 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2018 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07002019 sink_.WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002020 }
2021
2022 vie_encoder_->Stop();
2023 vie_encoder_.reset();
2024 stats_proxy_.reset();
2025
2026 EXPECT_EQ(0,
2027 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2028}
2029
sprang57c2fff2017-01-16 06:24:02 -08002030TEST_F(ViEEncoderTest, CallsBitrateObserver) {
2031 class MockBitrateObserver : public VideoBitrateAllocationObserver {
2032 public:
2033 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const BitrateAllocation&));
2034 } bitrate_observer;
2035 vie_encoder_->SetBitrateObserver(&bitrate_observer);
2036
2037 const int kDefaultFps = 30;
2038 const BitrateAllocation expected_bitrate =
2039 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002040 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002041
2042 // First called on bitrate updated, then again on first frame.
2043 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2044 .Times(2);
kthelgason2bc68642017-02-07 07:02:22 -08002045 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002046
2047 const int64_t kStartTimeMs = 1;
2048 video_source_.IncomingCapturedFrame(
2049 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang317005a2017-06-08 07:12:17 -07002050 sink_.WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002051
2052 // Not called on second frame.
2053 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2054 .Times(0);
2055 video_source_.IncomingCapturedFrame(
2056 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang317005a2017-06-08 07:12:17 -07002057 sink_.WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002058
2059 // Called after a process interval.
2060 const int64_t kProcessIntervalMs =
2061 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang317005a2017-06-08 07:12:17 -07002062 // TODO(sprang): ViEEncoder should die and/or get injectable clock.
2063 // Sleep for one processing interval plus one frame to avoid flakiness.
2064 SleepMs(kProcessIntervalMs + 1000 / kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002065 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2066 .Times(1);
2067 video_source_.IncomingCapturedFrame(CreateFrame(
2068 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang317005a2017-06-08 07:12:17 -07002069 sink_.WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002070
2071 vie_encoder_->Stop();
2072}
2073
sprangfda496a2017-06-15 04:21:07 -07002074TEST_F(ViEEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2075 const int kFrameWidth = 1280;
2076 const int kFrameHeight = 720;
2077 const int kFramerate = 24;
2078
2079 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2080 test::FrameForwarder source;
2081 vie_encoder_->SetSource(
2082 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2083
2084 // Insert a single frame, triggering initial configuration.
2085 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2086 vie_encoder_->WaitUntilTaskQueueIsIdle();
2087
2088 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2089 kDefaultFramerate);
2090
2091 // Trigger reconfigure encoder (without resetting the entire instance).
2092 VideoEncoderConfig video_encoder_config;
2093 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2094 video_encoder_config.number_of_streams = 1;
2095 video_encoder_config.video_stream_factory =
2096 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2097 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2098 kMaxPayloadLength, false);
2099 vie_encoder_->WaitUntilTaskQueueIsIdle();
2100
2101 // Detector should be updated with fps limit from codec config.
2102 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2103 kFramerate);
2104
2105 // Trigger overuse, max framerate should be reduced.
2106 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2107 stats.input_frame_rate = kFramerate;
2108 stats_proxy_->SetMockStats(stats);
2109 vie_encoder_->TriggerCpuOveruse();
2110 vie_encoder_->WaitUntilTaskQueueIsIdle();
2111 int adapted_framerate =
2112 vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2113 EXPECT_LT(adapted_framerate, kFramerate);
2114
2115 // Trigger underuse, max framerate should go back to codec configured fps.
2116 // Set extra low fps, to make sure it's actually reset, not just incremented.
2117 stats = stats_proxy_->GetStats();
2118 stats.input_frame_rate = adapted_framerate / 2;
2119 stats_proxy_->SetMockStats(stats);
2120 vie_encoder_->TriggerCpuNormalUsage();
2121 vie_encoder_->WaitUntilTaskQueueIsIdle();
2122 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2123 kFramerate);
2124
2125 vie_encoder_->Stop();
2126}
2127
2128TEST_F(ViEEncoderTest, OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2129 const int kFrameWidth = 1280;
2130 const int kFrameHeight = 720;
2131 const int kLowFramerate = 15;
2132 const int kHighFramerate = 25;
2133
2134 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2135 test::FrameForwarder source;
2136 vie_encoder_->SetSource(
2137 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2138
2139 // Trigger initial configuration.
2140 VideoEncoderConfig video_encoder_config;
2141 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2142 video_encoder_config.number_of_streams = 1;
2143 video_encoder_config.video_stream_factory =
2144 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2145 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2146 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2147 kMaxPayloadLength, false);
2148 vie_encoder_->WaitUntilTaskQueueIsIdle();
2149
2150 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2151 kLowFramerate);
2152
2153 // Trigger overuse, max framerate should be reduced.
2154 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2155 stats.input_frame_rate = kLowFramerate;
2156 stats_proxy_->SetMockStats(stats);
2157 vie_encoder_->TriggerCpuOveruse();
2158 vie_encoder_->WaitUntilTaskQueueIsIdle();
2159 int adapted_framerate =
2160 vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2161 EXPECT_LT(adapted_framerate, kLowFramerate);
2162
2163 // Reconfigure the encoder with a new (higher max framerate), max fps should
2164 // still respect the adaptation.
2165 video_encoder_config.video_stream_factory =
2166 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2167 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2168 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2169 kMaxPayloadLength, false);
2170 vie_encoder_->WaitUntilTaskQueueIsIdle();
2171
2172 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2173 adapted_framerate);
2174
2175 // Trigger underuse, max framerate should go back to codec configured fps.
2176 stats = stats_proxy_->GetStats();
2177 stats.input_frame_rate = adapted_framerate;
2178 stats_proxy_->SetMockStats(stats);
2179 vie_encoder_->TriggerCpuNormalUsage();
2180 vie_encoder_->WaitUntilTaskQueueIsIdle();
2181 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2182 kHighFramerate);
2183
2184 vie_encoder_->Stop();
2185}
2186
2187TEST_F(ViEEncoderTest, OveruseDetectorUpdatedOnDegradationPreferenceChange) {
2188 const int kFrameWidth = 1280;
2189 const int kFrameHeight = 720;
2190 const int kFramerate = 24;
2191
2192 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2193 test::FrameForwarder source;
2194 vie_encoder_->SetSource(
2195 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2196
2197 // Trigger initial configuration.
2198 VideoEncoderConfig video_encoder_config;
2199 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2200 video_encoder_config.number_of_streams = 1;
2201 video_encoder_config.video_stream_factory =
2202 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2203 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2204 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2205 kMaxPayloadLength, false);
2206 vie_encoder_->WaitUntilTaskQueueIsIdle();
2207
2208 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2209 kFramerate);
2210
2211 // Trigger overuse, max framerate should be reduced.
2212 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2213 stats.input_frame_rate = kFramerate;
2214 stats_proxy_->SetMockStats(stats);
2215 vie_encoder_->TriggerCpuOveruse();
2216 vie_encoder_->WaitUntilTaskQueueIsIdle();
2217 int adapted_framerate =
2218 vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2219 EXPECT_LT(adapted_framerate, kFramerate);
2220
2221 // Change degradation preference to not enable framerate scaling. Target
2222 // framerate should be changed to codec defined limit.
2223 vie_encoder_->SetSource(
2224 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
2225 vie_encoder_->WaitUntilTaskQueueIsIdle();
2226 EXPECT_EQ(vie_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2227 kFramerate);
2228
2229 vie_encoder_->Stop();
2230}
2231
kthelgason2bc68642017-02-07 07:02:22 -08002232TEST_F(ViEEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002233 const int kTooLowBitrateForFrameSizeBps = 10000;
2234 vie_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
2235 const int kWidth = 640;
2236 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002237
asaperssonfab67072017-04-04 05:51:49 -07002238 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002239
2240 // Expect to drop this frame, the wait should time out.
sprang317005a2017-06-08 07:12:17 -07002241 sink_.ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002242
2243 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002244 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002245
sprangc5d62e22017-04-02 23:53:04 -07002246 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002247
asaperssonfab67072017-04-04 05:51:49 -07002248 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002249 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002250 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002251
2252 // Expect to drop this frame, the wait should time out.
sprang317005a2017-06-08 07:12:17 -07002253 sink_.ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002254
sprangc5d62e22017-04-02 23:53:04 -07002255 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002256
2257 vie_encoder_->Stop();
2258}
2259
asapersson09f05612017-05-15 23:40:18 -07002260TEST_F(ViEEncoderTest, NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002261 const int kTooLowBitrateForFrameSizeBps = 10000;
2262 vie_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
2263 const int kWidth = 640;
2264 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002265
2266 // We expect the n initial frames to get dropped.
2267 int i;
2268 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002269 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07002270 sink_.ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002271 }
2272 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002273 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07002274 sink_.WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002275
2276 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002277 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002278
2279 vie_encoder_->Stop();
2280}
2281
2282TEST_F(ViEEncoderTest, InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002283 const int kWidth = 640;
2284 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002285 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
2286
2287 // Set degradation preference.
2288 vie_encoder_->SetSource(
2289 &video_source_,
2290 VideoSendStream::DegradationPreference::kMaintainResolution);
2291
asaperssonfab67072017-04-04 05:51:49 -07002292 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002293 // Frame should not be dropped, even if it's too large.
sprang317005a2017-06-08 07:12:17 -07002294 sink_.WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002295
2296 vie_encoder_->Stop();
2297}
2298
kthelgason2fc52542017-03-03 00:24:41 -08002299TEST_F(ViEEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002300 const int kWidth = 640;
2301 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002302 fake_encoder_.SetQualityScaling(false);
2303 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002304
kthelgasonb83797b2017-02-14 11:57:25 -08002305 // Force quality scaler reconfiguration by resetting the source.
2306 vie_encoder_->SetSource(&video_source_,
2307 VideoSendStream::DegradationPreference::kBalanced);
kthelgasonad9010c2017-02-14 00:46:51 -08002308
asaperssonfab67072017-04-04 05:51:49 -07002309 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002310 // Frame should not be dropped, even if it's too large.
sprang317005a2017-06-08 07:12:17 -07002311 sink_.WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002312
2313 vie_encoder_->Stop();
2314 fake_encoder_.SetQualityScaling(true);
2315}
2316
asaperssond0de2952017-04-21 01:47:31 -07002317TEST_F(ViEEncoderTest,
2318 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2319 const int kTooSmallWidth = 10;
2320 const int kTooSmallHeight = 10;
2321 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2322
2323 // Enable kMaintainFramerate preference, no initial limitation.
2324 test::FrameForwarder source;
2325 vie_encoder_->SetSource(
2326 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
2327 VerifyNoLimitation(source.sink_wants());
2328 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2329
2330 // Trigger adapt down, too small frame, expect no change.
2331 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang317005a2017-06-08 07:12:17 -07002332 sink_.WaitForEncodedFrame(1);
asaperssond0de2952017-04-21 01:47:31 -07002333 vie_encoder_->TriggerCpuOveruse();
2334 VerifyNoLimitation(source.sink_wants());
2335 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2336 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2337
2338 vie_encoder_->Stop();
2339}
2340
asaperssonf7e294d2017-06-13 23:25:22 -07002341TEST_F(ViEEncoderTest, ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
2342 const int kTooSmallWidth = 10;
2343 const int kTooSmallHeight = 10;
2344 const int kFpsLimit = 7;
2345 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2346
2347 // Enable kBalanced preference, no initial limitation.
2348 test::FrameForwarder source;
2349 vie_encoder_->SetSource(&source,
2350 VideoSendStream::DegradationPreference::kBalanced);
2351 VerifyNoLimitation(source.sink_wants());
2352 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2353 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2354
2355 // Trigger adapt down, expect limited framerate.
2356 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
2357 sink_.WaitForEncodedFrame(1);
2358 vie_encoder_->TriggerQualityLow();
2359 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2360 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2361 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2362 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2363
2364 // Trigger adapt down, too small frame, expect no change.
2365 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
2366 sink_.WaitForEncodedFrame(2);
2367 vie_encoder_->TriggerQualityLow();
2368 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2369 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2370 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2371 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2372
2373 vie_encoder_->Stop();
2374}
2375
asapersson02465b82017-04-10 01:12:52 -07002376TEST_F(ViEEncoderTest, FailingInitEncodeDoesntCauseCrash) {
2377 fake_encoder_.ForceInitEncodeFailure(true);
2378 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang317005a2017-06-08 07:12:17 -07002379 ResetEncoder("VP8", 2, 1, true);
asapersson02465b82017-04-10 01:12:52 -07002380 const int kFrameWidth = 1280;
2381 const int kFrameHeight = 720;
2382 video_source_.IncomingCapturedFrame(
2383 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07002384 sink_.ExpectDroppedFrame();
asapersson02465b82017-04-10 01:12:52 -07002385 vie_encoder_->Stop();
2386}
2387
sprangb1ca0732017-02-01 08:38:12 -08002388// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
asaperssond0de2952017-04-21 01:47:31 -07002389TEST_F(ViEEncoderTest, AdaptsResolutionOnOveruse_MaintainFramerateMode) {
sprangb1ca0732017-02-01 08:38:12 -08002390 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2391
2392 const int kFrameWidth = 1280;
2393 const int kFrameHeight = 720;
2394 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
2395 // requested by ViEEncoder::VideoSourceProxy::RequestResolutionLowerThan().
2396 video_source_.set_adaptation_enabled(true);
2397
2398 video_source_.IncomingCapturedFrame(
2399 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07002400 sink_.WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002401
2402 // Trigger CPU overuse, downscale by 3/4.
2403 vie_encoder_->TriggerCpuOveruse();
2404 video_source_.IncomingCapturedFrame(
2405 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07002406 sink_.WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002407
asaperssonfab67072017-04-04 05:51:49 -07002408 // Trigger CPU normal use, return to original resolution.
sprangb1ca0732017-02-01 08:38:12 -08002409 vie_encoder_->TriggerCpuNormalUsage();
2410 video_source_.IncomingCapturedFrame(
2411 CreateFrame(3, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07002412 sink_.WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002413
2414 vie_encoder_->Stop();
2415}
sprangfe627f32017-03-29 08:24:59 -07002416
asapersson02465b82017-04-10 01:12:52 -07002417TEST_F(ViEEncoderTest, AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprang317005a2017-06-08 07:12:17 -07002418 const int kDefaultFramerateFps = 30;
2419 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kDefaultFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002420 const int kFrameWidth = 1280;
2421 const int kFrameHeight = 720;
sprang317005a2017-06-08 07:12:17 -07002422 rtc::ScopedFakeClock fake_clock;
sprangc5d62e22017-04-02 23:53:04 -07002423
2424 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2425 vie_encoder_->SetSource(
2426 &video_source_,
2427 VideoSendStream::DegradationPreference::kMaintainResolution);
2428 video_source_.set_adaptation_enabled(true);
2429
sprang317005a2017-06-08 07:12:17 -07002430 fake_clock.SetTimeMicros(kFrameIntervalMs * 1000);
2431 int64_t timestamp_ms = kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002432
2433 video_source_.IncomingCapturedFrame(
2434 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07002435 sink_.WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002436
2437 // Try to trigger overuse. No fps estimate available => no effect.
2438 vie_encoder_->TriggerCpuOveruse();
2439
2440 // Insert frames for one second to get a stable estimate.
sprang317005a2017-06-08 07:12:17 -07002441 for (int i = 0; i < kDefaultFramerateFps; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002442 timestamp_ms += kFrameIntervalMs;
sprang317005a2017-06-08 07:12:17 -07002443 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
sprangc5d62e22017-04-02 23:53:04 -07002444 video_source_.IncomingCapturedFrame(
2445 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07002446 sink_.WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002447 }
2448
2449 // Trigger CPU overuse, reduce framerate by 2/3.
2450 vie_encoder_->TriggerCpuOveruse();
2451 int num_frames_dropped = 0;
sprang317005a2017-06-08 07:12:17 -07002452 for (int i = 0; i < kDefaultFramerateFps; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002453 timestamp_ms += kFrameIntervalMs;
sprang317005a2017-06-08 07:12:17 -07002454 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
sprangc5d62e22017-04-02 23:53:04 -07002455 video_source_.IncomingCapturedFrame(
2456 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07002457 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002458 ++num_frames_dropped;
2459 } else {
2460 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2461 }
2462 }
2463
sprang317005a2017-06-08 07:12:17 -07002464 // TODO(sprang): Find where there's rounding errors or stuff causing the
2465 // margin here to be a little larger than we'd like (input fps estimate is
2466 // off) and the frame dropping is a little too aggressive.
2467 const int kErrorMargin = 5;
2468 EXPECT_NEAR(num_frames_dropped,
2469 kDefaultFramerateFps - (kDefaultFramerateFps * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002470 kErrorMargin);
2471
2472 // Trigger CPU overuse, reduce framerate by 2/3 again.
2473 vie_encoder_->TriggerCpuOveruse();
2474 num_frames_dropped = 0;
sprang317005a2017-06-08 07:12:17 -07002475 for (int i = 0; i < kDefaultFramerateFps; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002476 timestamp_ms += kFrameIntervalMs;
sprang317005a2017-06-08 07:12:17 -07002477 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
sprangc5d62e22017-04-02 23:53:04 -07002478 video_source_.IncomingCapturedFrame(
2479 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07002480 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002481 ++num_frames_dropped;
2482 } else {
2483 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2484 }
2485 }
sprang317005a2017-06-08 07:12:17 -07002486 EXPECT_NEAR(num_frames_dropped,
2487 kDefaultFramerateFps - (kDefaultFramerateFps * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002488 kErrorMargin);
2489
2490 // Go back up one step.
2491 vie_encoder_->TriggerCpuNormalUsage();
2492 num_frames_dropped = 0;
sprang317005a2017-06-08 07:12:17 -07002493 for (int i = 0; i < kDefaultFramerateFps; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002494 timestamp_ms += kFrameIntervalMs;
sprang317005a2017-06-08 07:12:17 -07002495 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
sprangc5d62e22017-04-02 23:53:04 -07002496 video_source_.IncomingCapturedFrame(
2497 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07002498 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002499 ++num_frames_dropped;
2500 } else {
2501 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2502 }
2503 }
sprang317005a2017-06-08 07:12:17 -07002504 EXPECT_NEAR(num_frames_dropped,
2505 kDefaultFramerateFps - (kDefaultFramerateFps * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002506 kErrorMargin);
2507
2508 // Go back up to original mode.
2509 vie_encoder_->TriggerCpuNormalUsage();
2510 num_frames_dropped = 0;
sprang317005a2017-06-08 07:12:17 -07002511 for (int i = 0; i < kDefaultFramerateFps; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002512 timestamp_ms += kFrameIntervalMs;
sprang317005a2017-06-08 07:12:17 -07002513 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
sprangc5d62e22017-04-02 23:53:04 -07002514 video_source_.IncomingCapturedFrame(
2515 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07002516 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002517 ++num_frames_dropped;
2518 } else {
2519 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2520 }
2521 }
2522 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2523
2524 vie_encoder_->Stop();
2525}
2526
2527TEST_F(ViEEncoderTest, DoesntAdaptDownPastMinFramerate) {
2528 const int kFramerateFps = 5;
2529 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
2530 const int kMinFpsFrameInterval = rtc::kNumMillisecsPerSec / kMinFramerateFps;
2531 const int kFrameWidth = 1280;
2532 const int kFrameHeight = 720;
2533
sprang317005a2017-06-08 07:12:17 -07002534 rtc::ScopedFakeClock fake_clock;
sprangc5d62e22017-04-02 23:53:04 -07002535 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2536 vie_encoder_->SetSource(
2537 &video_source_,
2538 VideoSendStream::DegradationPreference::kMaintainResolution);
2539 video_source_.set_adaptation_enabled(true);
2540
sprang317005a2017-06-08 07:12:17 -07002541 fake_clock.SetTimeMicros(kFrameIntervalMs * 1000);
2542 int64_t timestamp_ms = kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002543
2544 // Trigger overuse as much as we can.
2545 for (int i = 0; i < ViEEncoder::kMaxCpuResolutionDowngrades; ++i) {
2546 // Insert frames to get a new fps estimate...
2547 for (int j = 0; j < kFramerateFps; ++j) {
2548 video_source_.IncomingCapturedFrame(
2549 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
2550 timestamp_ms += kFrameIntervalMs;
sprang317005a2017-06-08 07:12:17 -07002551 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
sprangc5d62e22017-04-02 23:53:04 -07002552 }
2553 // ...and then try to adapt again.
2554 vie_encoder_->TriggerCpuOveruse();
2555 }
2556
2557 // Drain any frame in the pipeline.
sprang317005a2017-06-08 07:12:17 -07002558 sink_.WaitForFrame(kDefaultTimeoutMs);
sprangc5d62e22017-04-02 23:53:04 -07002559
2560 // Insert frames at min fps, all should go through.
2561 for (int i = 0; i < 10; ++i) {
2562 timestamp_ms += kMinFpsFrameInterval;
sprang317005a2017-06-08 07:12:17 -07002563 fake_clock.AdvanceTimeMicros(kMinFpsFrameInterval * 1000);
sprangc5d62e22017-04-02 23:53:04 -07002564 video_source_.IncomingCapturedFrame(
2565 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07002566 sink_.WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002567 }
asaperssonf7e294d2017-06-13 23:25:22 -07002568
sprangc5d62e22017-04-02 23:53:04 -07002569 vie_encoder_->Stop();
2570}
asaperssonf7e294d2017-06-13 23:25:22 -07002571
2572TEST_F(ViEEncoderTest, AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
2573 const int kWidth = 1280;
2574 const int kHeight = 720;
2575 const int64_t kFrameIntervalMs = 150;
2576 int64_t timestamp_ms = kFrameIntervalMs;
2577 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2578
2579 // Enable kBalanced preference, no initial limitation.
2580 AdaptingFrameForwarder source;
2581 source.set_adaptation_enabled(true);
2582 vie_encoder_->SetSource(&source,
2583 VideoSendStream::DegradationPreference::kBalanced);
2584 timestamp_ms += kFrameIntervalMs;
2585 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2586 sink_.WaitForEncodedFrame(kWidth, kHeight);
2587 VerifyNoLimitation(source.sink_wants());
2588 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2589 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2590 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2591
2592 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
2593 vie_encoder_->TriggerQualityLow();
2594 timestamp_ms += kFrameIntervalMs;
2595 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2596 sink_.WaitForEncodedFrame(timestamp_ms);
2597 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2598 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2599 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2600 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2601
2602 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
2603 vie_encoder_->TriggerQualityLow();
2604 timestamp_ms += kFrameIntervalMs;
2605 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2606 sink_.WaitForEncodedFrame(timestamp_ms);
2607 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2608 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2609 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2610 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2611
2612 // Trigger adapt down, expect reduced fps (640x360@15fps).
2613 vie_encoder_->TriggerQualityLow();
2614 timestamp_ms += kFrameIntervalMs;
2615 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2616 sink_.WaitForEncodedFrame(timestamp_ms);
2617 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2618 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2619 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2620 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2621
2622 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
2623 vie_encoder_->TriggerQualityLow();
2624 timestamp_ms += kFrameIntervalMs;
2625 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2626 sink_.WaitForEncodedFrame(timestamp_ms);
2627 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2628 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2629 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2630 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2631
2632 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
2633 vie_encoder_->TriggerQualityLow();
2634 timestamp_ms += kFrameIntervalMs;
2635 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2636 sink_.WaitForEncodedFrame(timestamp_ms);
2637 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2638 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2639 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2640 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2641
2642 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
2643 vie_encoder_->TriggerQualityLow();
2644 timestamp_ms += kFrameIntervalMs;
2645 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2646 sink_.WaitForEncodedFrame(timestamp_ms);
2647 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2648 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2649 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2650 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2651
2652 // Trigger adapt down, expect reduced fps (320x180@7fps).
2653 vie_encoder_->TriggerQualityLow();
2654 timestamp_ms += kFrameIntervalMs;
2655 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2656 sink_.WaitForEncodedFrame(timestamp_ms);
2657 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2658 rtc::VideoSinkWants last_wants = source.sink_wants();
2659 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2660 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2661 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2662
2663 // Trigger adapt down, min resolution reached, expect no change.
2664 vie_encoder_->TriggerQualityLow();
2665 timestamp_ms += kFrameIntervalMs;
2666 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2667 sink_.WaitForEncodedFrame(timestamp_ms);
2668 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2669 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2670 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2671 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2672
2673 // Trigger adapt down, expect expect increased fps (320x180@10fps).
2674 vie_encoder_->TriggerQualityHigh();
2675 timestamp_ms += kFrameIntervalMs;
2676 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2677 sink_.WaitForEncodedFrame(timestamp_ms);
2678 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2679 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2680 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2681 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2682
2683 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
2684 vie_encoder_->TriggerQualityHigh();
2685 timestamp_ms += kFrameIntervalMs;
2686 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2687 sink_.WaitForEncodedFrame(timestamp_ms);
2688 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2689 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2690 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2691 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2692
2693 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
2694 vie_encoder_->TriggerQualityHigh();
2695 timestamp_ms += kFrameIntervalMs;
2696 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2697 sink_.WaitForEncodedFrame(timestamp_ms);
2698 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2699 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2700 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2701 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2702
2703 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
2704 vie_encoder_->TriggerQualityHigh();
2705 timestamp_ms += kFrameIntervalMs;
2706 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2707 sink_.WaitForEncodedFrame(timestamp_ms);
2708 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2709 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2710 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2711 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2712
2713 // Trigger adapt up, expect increased fps (640x360@30fps).
2714 vie_encoder_->TriggerQualityHigh();
2715 timestamp_ms += kFrameIntervalMs;
2716 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2717 sink_.WaitForEncodedFrame(timestamp_ms);
2718 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2719 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2720 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2721 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2722
2723 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
2724 vie_encoder_->TriggerQualityHigh();
2725 timestamp_ms += kFrameIntervalMs;
2726 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2727 sink_.WaitForEncodedFrame(timestamp_ms);
2728 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2729 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2730 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2731 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2732
2733 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
2734 vie_encoder_->TriggerQualityHigh();
2735 timestamp_ms += kFrameIntervalMs;
2736 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2737 sink_.WaitForEncodedFrame(kWidth, kHeight);
2738 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2739 VerifyNoLimitation(source.sink_wants());
2740 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2741 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2742 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2743
2744 // Trigger adapt up, expect no change.
2745 vie_encoder_->TriggerQualityHigh();
2746 VerifyNoLimitation(source.sink_wants());
2747 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2748
2749 vie_encoder_->Stop();
2750}
2751
2752TEST_F(ViEEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
2753 const int kWidth = 1280;
2754 const int kHeight = 720;
2755 const int64_t kFrameIntervalMs = 150;
2756 int64_t timestamp_ms = kFrameIntervalMs;
2757 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2758
2759 // Enable kBalanced preference, no initial limitation.
2760 AdaptingFrameForwarder source;
2761 source.set_adaptation_enabled(true);
2762 vie_encoder_->SetSource(&source,
2763 VideoSendStream::DegradationPreference::kBalanced);
2764 timestamp_ms += kFrameIntervalMs;
2765 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2766 sink_.WaitForEncodedFrame(kWidth, kHeight);
2767 VerifyNoLimitation(source.sink_wants());
2768 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2769 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2770 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2771 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2772 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2773 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2774
2775 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
2776 vie_encoder_->TriggerCpuOveruse();
2777 timestamp_ms += kFrameIntervalMs;
2778 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2779 sink_.WaitForEncodedFrame(timestamp_ms);
2780 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2781 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2782 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2783 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2784 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2785 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2786 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2787
2788 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
2789 vie_encoder_->TriggerCpuOveruse();
2790 timestamp_ms += kFrameIntervalMs;
2791 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2792 sink_.WaitForEncodedFrame(timestamp_ms);
2793 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2794 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2795 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2796 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2797 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2798 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2799 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2800
2801 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
2802 vie_encoder_->TriggerQualityLow();
2803 timestamp_ms += kFrameIntervalMs;
2804 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2805 sink_.WaitForEncodedFrame(timestamp_ms);
2806 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2807 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2808 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2809 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2810 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2811 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2812 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2813
2814 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
2815 vie_encoder_->TriggerCpuNormalUsage();
2816 timestamp_ms += kFrameIntervalMs;
2817 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2818 sink_.WaitForEncodedFrame(timestamp_ms);
2819 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2820 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2821 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2822 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2823 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2824 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2825 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2826
2827 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
2828 vie_encoder_->TriggerQualityHigh();
2829 timestamp_ms += kFrameIntervalMs;
2830 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2831 sink_.WaitForEncodedFrame(timestamp_ms);
2832 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2833 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2834 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2835 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2836 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2837 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2838 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2839
2840 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
2841 vie_encoder_->TriggerCpuNormalUsage();
2842 timestamp_ms += kFrameIntervalMs;
2843 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2844 sink_.WaitForEncodedFrame(kWidth, kHeight);
2845 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2846 VerifyNoLimitation(source.sink_wants());
2847 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2848 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2849 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2850 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2851 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2852 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2853
2854 // Trigger adapt up, expect no change.
2855 vie_encoder_->TriggerQualityHigh();
2856 VerifyNoLimitation(source.sink_wants());
2857 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2858 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2859
2860 vie_encoder_->Stop();
2861}
2862
2863TEST_F(ViEEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
2864 const int kWidth = 640;
2865 const int kHeight = 360;
2866 const int kFpsLimit = 15;
2867 const int64_t kFrameIntervalMs = 150;
2868 int64_t timestamp_ms = kFrameIntervalMs;
2869 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2870
2871 // Enable kBalanced preference, no initial limitation.
2872 AdaptingFrameForwarder source;
2873 source.set_adaptation_enabled(true);
2874 vie_encoder_->SetSource(&source,
2875 VideoSendStream::DegradationPreference::kBalanced);
2876 timestamp_ms += kFrameIntervalMs;
2877 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2878 sink_.WaitForEncodedFrame(kWidth, kHeight);
2879 VerifyNoLimitation(source.sink_wants());
2880 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2881 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2882 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2883 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2884 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2885 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2886
2887 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
2888 vie_encoder_->TriggerCpuOveruse();
2889 timestamp_ms += kFrameIntervalMs;
2890 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2891 sink_.WaitForEncodedFrame(timestamp_ms);
2892 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2893 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2894 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2895 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2896 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2897 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2898 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2899
2900 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
2901 vie_encoder_->TriggerQualityLow();
2902 timestamp_ms += kFrameIntervalMs;
2903 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2904 sink_.WaitForEncodedFrame(timestamp_ms);
2905 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2906 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2907 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2908 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2909 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2910 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2911 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2912
2913 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
2914 vie_encoder_->TriggerCpuNormalUsage();
2915 timestamp_ms += kFrameIntervalMs;
2916 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2917 sink_.WaitForEncodedFrame(timestamp_ms);
2918 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2919 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2920 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2921 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2922 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2923 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2924 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2925
2926 // Trigger quality adapt up, expect increased fps (640x360@30fps).
2927 vie_encoder_->TriggerQualityHigh();
2928 timestamp_ms += kFrameIntervalMs;
2929 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2930 sink_.WaitForEncodedFrame(timestamp_ms);
2931 VerifyNoLimitation(source.sink_wants());
2932 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2933 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2934 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2935 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2936 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2937 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2938
2939 // Trigger adapt up, expect no change.
2940 vie_encoder_->TriggerQualityHigh();
2941 VerifyNoLimitation(source.sink_wants());
2942 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2943 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2944
2945 vie_encoder_->Stop();
2946}
2947
ilnik6b826ef2017-06-16 06:53:48 -07002948TEST_F(ViEEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
2949 // Simulates simulcast behavior and makes highest stream resolutions divisible
2950 // by 4.
2951 class CroppingVideoStreamFactory
2952 : public VideoEncoderConfig::VideoStreamFactoryInterface {
2953 public:
2954 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
2955 int framerate)
2956 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
2957 EXPECT_GT(num_temporal_layers, 0u);
2958 EXPECT_GT(framerate, 0);
2959 }
2960
2961 private:
2962 std::vector<VideoStream> CreateEncoderStreams(
2963 int width,
2964 int height,
2965 const VideoEncoderConfig& encoder_config) override {
2966 std::vector<VideoStream> streams =
2967 test::CreateVideoStreams(width - width % 4, height - height % 4,
2968 encoder_config);
2969 for (VideoStream& stream : streams) {
2970 stream.temporal_layer_thresholds_bps.resize(num_temporal_layers_ - 1);
2971 stream.max_framerate = framerate_;
2972 }
2973 return streams;
2974 }
2975
2976 const size_t num_temporal_layers_;
2977 const int framerate_;
2978 };
2979
2980 const int kFrameWidth = 1920;
2981 const int kFrameHeight = 1080;
2982 // 3/4 of 1920.
2983 const int kAdaptedFrameWidth = 1440;
2984 // 3/4 of 1080 rounded down to multiple of 4.
2985 const int kAdaptedFrameHeight = 808;
2986 const int kFramerate = 24;
2987
2988 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2989 // Trigger reconfigure encoder (without resetting the entire instance).
2990 VideoEncoderConfig video_encoder_config;
2991 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2992 video_encoder_config.number_of_streams = 1;
2993 video_encoder_config.video_stream_factory =
2994 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
2995 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2996 kMaxPayloadLength, false);
2997 vie_encoder_->WaitUntilTaskQueueIsIdle();
2998
2999 video_source_.set_adaptation_enabled(true);
3000
3001 video_source_.IncomingCapturedFrame(
3002 CreateFrame(1, kFrameWidth, kFrameHeight));
3003 sink_.WaitForEncodedFrame(kFrameWidth, kFrameHeight);
3004
3005 // Trigger CPU overuse, downscale by 3/4.
3006 vie_encoder_->TriggerCpuOveruse();
3007 video_source_.IncomingCapturedFrame(
3008 CreateFrame(2, kFrameWidth, kFrameHeight));
3009 sink_.WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
3010
3011 vie_encoder_->Stop();
3012}
3013
3014
perkj26091b12016-09-01 01:17:40 -07003015} // namespace webrtc