blob: 7a54fbe925f2fe75fe277b1d0cf4d6781ca29532 [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;
asapersson5f7226f2016-11-25 04:37:00 -080051
perkj803d97f2016-11-01 11:45:46 -070052class TestBuffer : public webrtc::I420Buffer {
53 public:
54 TestBuffer(rtc::Event* event, int width, int height)
55 : I420Buffer(width, height), event_(event) {}
56
57 private:
58 friend class rtc::RefCountedObject<TestBuffer>;
59 ~TestBuffer() override {
60 if (event_)
61 event_->Set();
62 }
63 rtc::Event* const event_;
64};
65
66class ViEEncoderUnderTest : public ViEEncoder {
67 public:
kthelgason876222f2016-11-29 01:44:11 -080068 ViEEncoderUnderTest(SendStatisticsProxy* stats_proxy,
69 const VideoSendStream::Config::EncoderSettings& settings)
perkj803d97f2016-11-01 11:45:46 -070070 : ViEEncoder(1 /* number_of_cores */,
71 stats_proxy,
72 settings,
73 nullptr /* pre_encode_callback */,
74 nullptr /* encoder_timing */) {}
75
sprangb1ca0732017-02-01 08:38:12 -080076 void PostTaskAndWait(bool down, AdaptReason reason) {
perkj803d97f2016-11-01 11:45:46 -070077 rtc::Event event(false, false);
kthelgason876222f2016-11-29 01:44:11 -080078 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -080079 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -070080 event.Set();
81 });
perkj070ba852017-02-16 15:46:27 -080082 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -070083 }
84
kthelgason2fc52542017-03-03 00:24:41 -080085 // This is used as a synchronisation mechanism, to make sure that the
86 // encoder queue is not blocked before we start sending it frames.
87 void WaitUntilTaskQueueIsIdle() {
88 rtc::Event event(false, false);
89 encoder_queue()->PostTask([&event] {
90 event.Set();
91 });
92 ASSERT_TRUE(event.Wait(5000));
93 }
94
sprangb1ca0732017-02-01 08:38:12 -080095 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -080096
sprangb1ca0732017-02-01 08:38:12 -080097 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -080098
sprangb1ca0732017-02-01 08:38:12 -080099 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800100
sprangb1ca0732017-02-01 08:38:12 -0800101 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
perkj803d97f2016-11-01 11:45:46 -0700102};
103
asapersson5f7226f2016-11-25 04:37:00 -0800104class VideoStreamFactory
105 : public VideoEncoderConfig::VideoStreamFactoryInterface {
106 public:
107 explicit VideoStreamFactory(size_t num_temporal_layers)
108 : num_temporal_layers_(num_temporal_layers) {
109 EXPECT_GT(num_temporal_layers, 0u);
110 }
111
112 private:
113 std::vector<VideoStream> CreateEncoderStreams(
114 int width,
115 int height,
116 const VideoEncoderConfig& encoder_config) override {
117 std::vector<VideoStream> streams =
118 test::CreateVideoStreams(width, height, encoder_config);
119 for (VideoStream& stream : streams) {
120 stream.temporal_layer_thresholds_bps.resize(num_temporal_layers_ - 1);
121 }
122 return streams;
123 }
124 const size_t num_temporal_layers_;
125};
126
sprangb1ca0732017-02-01 08:38:12 -0800127class AdaptingFrameForwarder : public test::FrameForwarder {
128 public:
129 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700130 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800131
132 void set_adaptation_enabled(bool enabled) {
133 rtc::CritScope cs(&crit_);
134 adaptation_enabled_ = enabled;
135 }
136
asaperssonfab67072017-04-04 05:51:49 -0700137 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800138 rtc::CritScope cs(&crit_);
139 return adaptation_enabled_;
140 }
141
asapersson09f05612017-05-15 23:40:18 -0700142 rtc::VideoSinkWants last_wants() const {
143 rtc::CritScope cs(&crit_);
144 return last_wants_;
145 }
146
sprangb1ca0732017-02-01 08:38:12 -0800147 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
148 int cropped_width = 0;
149 int cropped_height = 0;
150 int out_width = 0;
151 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700152 if (adaption_enabled()) {
153 if (adapter_.AdaptFrameResolution(
154 video_frame.width(), video_frame.height(),
155 video_frame.timestamp_us() * 1000, &cropped_width,
156 &cropped_height, &out_width, &out_height)) {
157 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
158 nullptr, out_width, out_height),
159 99, 99, kVideoRotation_0);
160 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
161 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
162 }
sprangb1ca0732017-02-01 08:38:12 -0800163 } else {
164 test::FrameForwarder::IncomingCapturedFrame(video_frame);
165 }
166 }
167
168 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
169 const rtc::VideoSinkWants& wants) override {
170 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700171 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700172 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
173 wants.max_pixel_count,
174 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800175 test::FrameForwarder::AddOrUpdateSink(sink, wants);
176 }
sprangb1ca0732017-02-01 08:38:12 -0800177 cricket::VideoAdapter adapter_;
178 bool adaptation_enabled_ GUARDED_BY(crit_);
asapersson09f05612017-05-15 23:40:18 -0700179 rtc::VideoSinkWants last_wants_ GUARDED_BY(crit_);
sprangb1ca0732017-02-01 08:38:12 -0800180};
sprangc5d62e22017-04-02 23:53:04 -0700181
182class MockableSendStatisticsProxy : public SendStatisticsProxy {
183 public:
184 MockableSendStatisticsProxy(Clock* clock,
185 const VideoSendStream::Config& config,
186 VideoEncoderConfig::ContentType content_type)
187 : SendStatisticsProxy(clock, config, content_type) {}
188
189 VideoSendStream::Stats GetStats() override {
190 rtc::CritScope cs(&lock_);
191 if (mock_stats_)
192 return *mock_stats_;
193 return SendStatisticsProxy::GetStats();
194 }
195
196 void SetMockStats(const VideoSendStream::Stats& stats) {
197 rtc::CritScope cs(&lock_);
198 mock_stats_.emplace(stats);
199 }
200
201 void ResetMockStats() {
202 rtc::CritScope cs(&lock_);
203 mock_stats_.reset();
204 }
205
206 private:
207 rtc::CriticalSection lock_;
208 rtc::Optional<VideoSendStream::Stats> mock_stats_ GUARDED_BY(lock_);
209};
210
perkj803d97f2016-11-01 11:45:46 -0700211} // namespace
212
perkj26091b12016-09-01 01:17:40 -0700213class ViEEncoderTest : public ::testing::Test {
214 public:
215 static const int kDefaultTimeoutMs = 30 * 1000;
216
217 ViEEncoderTest()
218 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700219 codec_width_(320),
220 codec_height_(240),
perkj26091b12016-09-01 01:17:40 -0700221 fake_encoder_(),
sprangc5d62e22017-04-02 23:53:04 -0700222 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700223 Clock::GetRealTimeClock(),
224 video_send_config_,
225 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700226 sink_(&fake_encoder_) {}
227
228 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700229 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700230 video_send_config_ = VideoSendStream::Config(nullptr);
231 video_send_config_.encoder_settings.encoder = &fake_encoder_;
232 video_send_config_.encoder_settings.payload_name = "FAKE";
233 video_send_config_.encoder_settings.payload_type = 125;
234
Per512ecb32016-09-23 15:52:06 +0200235 VideoEncoderConfig video_encoder_config;
perkjfa10b552016-10-02 23:45:26 -0700236 test::FillEncoderConfiguration(1, &video_encoder_config);
Erik Språng08127a92016-11-16 16:41:30 +0100237 video_encoder_config_ = video_encoder_config.Copy();
asapersson5f7226f2016-11-25 04:37:00 -0800238 ConfigureEncoder(std::move(video_encoder_config), true /* nack_enabled */);
239 }
240
241 void ConfigureEncoder(VideoEncoderConfig video_encoder_config,
242 bool nack_enabled) {
243 if (vie_encoder_)
244 vie_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700245 vie_encoder_.reset(new ViEEncoderUnderTest(
246 stats_proxy_.get(), video_send_config_.encoder_settings));
247 vie_encoder_->SetSink(&sink_, false /* rotation_applied */);
sprangc5d62e22017-04-02 23:53:04 -0700248 vie_encoder_->SetSource(
249 &video_source_,
250 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason2bc68642017-02-07 07:02:22 -0800251 vie_encoder_->SetStartBitrate(kTargetBitrateBps);
asapersson5f7226f2016-11-25 04:37:00 -0800252 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
253 kMaxPayloadLength, nack_enabled);
kthelgason2fc52542017-03-03 00:24:41 -0800254 vie_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800255 }
256
257 void ResetEncoder(const std::string& payload_name,
258 size_t num_streams,
259 size_t num_temporal_layers,
sprang317005a2017-06-08 07:12:17 -0700260 bool nack_enabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800261 video_send_config_.encoder_settings.payload_name = payload_name;
262
263 VideoEncoderConfig video_encoder_config;
264 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800265 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800266 video_encoder_config.video_stream_factory =
267 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers);
268 ConfigureEncoder(std::move(video_encoder_config), nack_enabled);
perkj26091b12016-09-01 01:17:40 -0700269 }
270
sprang57c2fff2017-01-16 06:24:02 -0800271 VideoFrame CreateFrame(int64_t ntp_time_ms,
272 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200273 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
274 destruction_event, codec_width_, codec_height_),
275 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800276 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700277 return frame;
278 }
279
sprang57c2fff2017-01-16 06:24:02 -0800280 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700281 VideoFrame frame(
282 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
283 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800284 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700285 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700286 return frame;
287 }
288
asapersson02465b82017-04-10 01:12:52 -0700289 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700290 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700291 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
292 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700293 }
294
asapersson09f05612017-05-15 23:40:18 -0700295 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
296 const rtc::VideoSinkWants& wants2) {
297 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
298 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
299 }
300
301 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
302 const rtc::VideoSinkWants& wants2) {
303 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
304 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
305 EXPECT_GT(wants1.max_pixel_count, 0);
306 }
307
308 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
309 const rtc::VideoSinkWants& wants2) {
310 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
311 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
312 }
313
314 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
315 int pixel_count) {
316 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700317 EXPECT_LT(wants.max_pixel_count, pixel_count);
318 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700319 }
320
321 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
322 EXPECT_LT(wants.max_framerate_fps, fps);
323 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
324 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700325 }
326
perkj26091b12016-09-01 01:17:40 -0700327 class TestEncoder : public test::FakeEncoder {
328 public:
329 TestEncoder()
330 : FakeEncoder(Clock::GetRealTimeClock()),
331 continue_encode_event_(false, false) {}
332
asaperssonfab67072017-04-04 05:51:49 -0700333 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800334 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700335 return config_;
336 }
337
338 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800339 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700340 block_next_encode_ = true;
341 }
342
kthelgason876222f2016-11-29 01:44:11 -0800343 VideoEncoder::ScalingSettings GetScalingSettings() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800344 rtc::CritScope lock(&local_crit_sect_);
kthelgasonad9010c2017-02-14 00:46:51 -0800345 if (quality_scaling_)
346 return VideoEncoder::ScalingSettings(true, 1, 2);
347 return VideoEncoder::ScalingSettings(false);
kthelgason876222f2016-11-29 01:44:11 -0800348 }
349
perkjfa10b552016-10-02 23:45:26 -0700350 void ContinueEncode() { continue_encode_event_.Set(); }
351
352 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
353 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800354 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700355 EXPECT_EQ(timestamp_, timestamp);
356 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
357 }
358
kthelgason2fc52542017-03-03 00:24:41 -0800359 void SetQualityScaling(bool b) {
360 rtc::CritScope lock(&local_crit_sect_);
361 quality_scaling_ = b;
362 }
kthelgasonad9010c2017-02-14 00:46:51 -0800363
sprangfe627f32017-03-29 08:24:59 -0700364 void ForceInitEncodeFailure(bool force_failure) {
365 rtc::CritScope lock(&local_crit_sect_);
366 force_init_encode_failed_ = force_failure;
367 }
368
perkjfa10b552016-10-02 23:45:26 -0700369 private:
perkj26091b12016-09-01 01:17:40 -0700370 int32_t Encode(const VideoFrame& input_image,
371 const CodecSpecificInfo* codec_specific_info,
372 const std::vector<FrameType>* frame_types) override {
373 bool block_encode;
374 {
brandtre78d2662017-01-16 05:57:16 -0800375 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700376 EXPECT_GT(input_image.timestamp(), timestamp_);
377 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
378 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
379
380 timestamp_ = input_image.timestamp();
381 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700382 last_input_width_ = input_image.width();
383 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700384 block_encode = block_next_encode_;
385 block_next_encode_ = false;
386 }
387 int32_t result =
388 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
389 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700390 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700391 return result;
392 }
393
sprangfe627f32017-03-29 08:24:59 -0700394 int32_t InitEncode(const VideoCodec* config,
395 int32_t number_of_cores,
396 size_t max_payload_size) override {
397 int res =
398 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
399 rtc::CritScope lock(&local_crit_sect_);
400 if (config->codecType == kVideoCodecVP8 && config->VP8().tl_factory) {
401 // Simulate setting up temporal layers, in order to validate the life
402 // cycle of these objects.
403 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
404 int num_temporal_layers =
405 std::max<int>(1, config->VP8().numberOfTemporalLayers);
406 for (int i = 0; i < num_streams; ++i) {
407 allocated_temporal_layers_.emplace_back(
408 config->VP8().tl_factory->Create(i, num_temporal_layers, 42));
409 }
410 }
411 if (force_init_encode_failed_)
412 return -1;
413 return res;
414 }
415
brandtre78d2662017-01-16 05:57:16 -0800416 rtc::CriticalSection local_crit_sect_;
sprangfe627f32017-03-29 08:24:59 -0700417 bool block_next_encode_ GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700418 rtc::Event continue_encode_event_;
sprangfe627f32017-03-29 08:24:59 -0700419 uint32_t timestamp_ GUARDED_BY(local_crit_sect_) = 0;
420 int64_t ntp_time_ms_ GUARDED_BY(local_crit_sect_) = 0;
421 int last_input_width_ GUARDED_BY(local_crit_sect_) = 0;
422 int last_input_height_ GUARDED_BY(local_crit_sect_) = 0;
423 bool quality_scaling_ GUARDED_BY(local_crit_sect_) = true;
424 std::vector<std::unique_ptr<TemporalLayers>> allocated_temporal_layers_
425 GUARDED_BY(local_crit_sect_);
426 bool force_init_encode_failed_ GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700427 };
428
Per512ecb32016-09-23 15:52:06 +0200429 class TestSink : public ViEEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700430 public:
431 explicit TestSink(TestEncoder* test_encoder)
432 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
433
perkj26091b12016-09-01 01:17:40 -0700434 void WaitForEncodedFrame(int64_t expected_ntp_time) {
435 uint32_t timestamp = 0;
sprang317005a2017-06-08 07:12:17 -0700436 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700437 {
438 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800439 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700440 }
441 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
442 }
443
sprangb1ca0732017-02-01 08:38:12 -0800444 void WaitForEncodedFrame(uint32_t expected_width,
445 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700446 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
447 CheckLastFrameSizeMathces(expected_width, expected_height);
448 }
449
450 void CheckLastFrameSizeMathces(uint32_t expected_width,
451 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800452 uint32_t width = 0;
453 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800454 {
455 rtc::CritScope lock(&crit_);
456 width = last_width_;
457 height = last_height_;
458 }
459 EXPECT_EQ(expected_height, height);
460 EXPECT_EQ(expected_width, width);
461 }
462
kthelgason2fc52542017-03-03 00:24:41 -0800463 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800464
sprangc5d62e22017-04-02 23:53:04 -0700465 bool WaitForFrame(int64_t timeout_ms) {
466 return encoded_frame_event_.Wait(timeout_ms);
467 }
468
perkj26091b12016-09-01 01:17:40 -0700469 void SetExpectNoFrames() {
470 rtc::CritScope lock(&crit_);
471 expect_frames_ = false;
472 }
473
asaperssonfab67072017-04-04 05:51:49 -0700474 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200475 rtc::CritScope lock(&crit_);
476 return number_of_reconfigurations_;
477 }
478
asaperssonfab67072017-04-04 05:51:49 -0700479 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200480 rtc::CritScope lock(&crit_);
481 return min_transmit_bitrate_bps_;
482 }
483
perkj26091b12016-09-01 01:17:40 -0700484 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700485 Result OnEncodedImage(
486 const EncodedImage& encoded_image,
487 const CodecSpecificInfo* codec_specific_info,
488 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200489 rtc::CritScope lock(&crit_);
490 EXPECT_TRUE(expect_frames_);
sprangb1ca0732017-02-01 08:38:12 -0800491 last_timestamp_ = encoded_image._timeStamp;
492 last_width_ = encoded_image._encodedWidth;
493 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200494 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800495 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200496 }
497
498 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
499 int min_transmit_bitrate_bps) override {
500 rtc::CriticalSection crit_;
501 ++number_of_reconfigurations_;
502 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
503 }
504
perkj26091b12016-09-01 01:17:40 -0700505 rtc::CriticalSection crit_;
506 TestEncoder* test_encoder_;
507 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800508 uint32_t last_timestamp_ = 0;
509 uint32_t last_height_ = 0;
510 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700511 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200512 int number_of_reconfigurations_ = 0;
513 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700514 };
515
516 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100517 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200518 int codec_width_;
519 int codec_height_;
perkj26091b12016-09-01 01:17:40 -0700520 TestEncoder fake_encoder_;
sprangc5d62e22017-04-02 23:53:04 -0700521 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700522 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800523 AdaptingFrameForwarder video_source_;
perkj803d97f2016-11-01 11:45:46 -0700524 std::unique_ptr<ViEEncoderUnderTest> vie_encoder_;
perkj26091b12016-09-01 01:17:40 -0700525};
526
527TEST_F(ViEEncoderTest, EncodeOneFrame) {
perkj26091b12016-09-01 01:17:40 -0700528 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
529 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700530 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang317005a2017-06-08 07:12:17 -0700531 sink_.WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700532 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700533 vie_encoder_->Stop();
534}
535
536TEST_F(ViEEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
537 // Dropped since no target bitrate has been set.
538 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700539 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
540 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700541
perkj26091b12016-09-01 01:17:40 -0700542 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
543
perkja49cbd32016-09-16 07:53:41 -0700544 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang317005a2017-06-08 07:12:17 -0700545 sink_.WaitForEncodedFrame(2);
perkj26091b12016-09-01 01:17:40 -0700546 vie_encoder_->Stop();
547}
548
549TEST_F(ViEEncoderTest, DropsFramesWhenRateSetToZero) {
perkj26091b12016-09-01 01:17:40 -0700550 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700551 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang317005a2017-06-08 07:12:17 -0700552 sink_.WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700553
554 vie_encoder_->OnBitrateUpdated(0, 0, 0);
555 // Dropped since bitrate is zero.
perkja49cbd32016-09-16 07:53:41 -0700556 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkj26091b12016-09-01 01:17:40 -0700557
558 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700559 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
sprang317005a2017-06-08 07:12:17 -0700560 sink_.WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700561 vie_encoder_->Stop();
562}
563
564TEST_F(ViEEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
perkj26091b12016-09-01 01:17:40 -0700565 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700566 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang317005a2017-06-08 07:12:17 -0700567 sink_.WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700568
569 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700570 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700571
perkja49cbd32016-09-16 07:53:41 -0700572 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang317005a2017-06-08 07:12:17 -0700573 sink_.WaitForEncodedFrame(2);
perkj26091b12016-09-01 01:17:40 -0700574 vie_encoder_->Stop();
575}
576
577TEST_F(ViEEncoderTest, DropsFrameAfterStop) {
perkj26091b12016-09-01 01:17:40 -0700578 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
579
perkja49cbd32016-09-16 07:53:41 -0700580 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang317005a2017-06-08 07:12:17 -0700581 sink_.WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700582
583 vie_encoder_->Stop();
584 sink_.SetExpectNoFrames();
585 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700586 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
587 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700588}
589
590TEST_F(ViEEncoderTest, DropsPendingFramesOnSlowEncode) {
perkj26091b12016-09-01 01:17:40 -0700591 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
592
593 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700594 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang317005a2017-06-08 07:12:17 -0700595 sink_.WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700596 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
597 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700598 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
599 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700600 fake_encoder_.ContinueEncode();
sprang317005a2017-06-08 07:12:17 -0700601 sink_.WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700602
603 vie_encoder_->Stop();
604}
605
Per512ecb32016-09-23 15:52:06 +0200606TEST_F(ViEEncoderTest, ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
Per512ecb32016-09-23 15:52:06 +0200607 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100608 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200609
610 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200611 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang317005a2017-06-08 07:12:17 -0700612 sink_.WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100613 // The encoder will have been configured once when the first frame is
614 // received.
615 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200616
617 VideoEncoderConfig video_encoder_config;
perkjfa10b552016-10-02 23:45:26 -0700618 test::FillEncoderConfiguration(1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200619 video_encoder_config.min_transmit_bitrate_bps = 9999;
asapersson5f7226f2016-11-25 04:37:00 -0800620 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
621 kMaxPayloadLength, true /* nack_enabled */);
Per512ecb32016-09-23 15:52:06 +0200622
623 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200624 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang317005a2017-06-08 07:12:17 -0700625 sink_.WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100626 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700627 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700628
629 vie_encoder_->Stop();
630}
631
perkjfa10b552016-10-02 23:45:26 -0700632TEST_F(ViEEncoderTest, FrameResolutionChangeReconfigureEncoder) {
perkjfa10b552016-10-02 23:45:26 -0700633 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
634
635 // Capture a frame and wait for it to synchronize with the encoder thread.
636 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang317005a2017-06-08 07:12:17 -0700637 sink_.WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100638 // The encoder will have been configured once.
639 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700640 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
641 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
642
643 codec_width_ *= 2;
644 codec_height_ *= 2;
645 // Capture a frame with a higher resolution and wait for it to synchronize
646 // with the encoder thread.
647 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang317005a2017-06-08 07:12:17 -0700648 sink_.WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700649 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
650 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100651 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700652
653 vie_encoder_->Stop();
654}
655
asapersson5f7226f2016-11-25 04:37:00 -0800656TEST_F(ViEEncoderTest, Vp8ResilienceIsOffFor1S1TLWithNackEnabled) {
657 const bool kNackEnabled = true;
658 const size_t kNumStreams = 1;
659 const size_t kNumTl = 1;
sprang317005a2017-06-08 07:12:17 -0700660 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800661 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
662
663 // Capture a frame and wait for it to synchronize with the encoder thread.
664 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang317005a2017-06-08 07:12:17 -0700665 sink_.WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800666 // The encoder have been configured once when the first frame is received.
667 EXPECT_EQ(1, sink_.number_of_reconfigurations());
668 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
669 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
670 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
671 // Resilience is off for no temporal layers with nack on.
672 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
673 vie_encoder_->Stop();
674}
675
676TEST_F(ViEEncoderTest, Vp8ResilienceIsOffFor2S1TlWithNackEnabled) {
677 const bool kNackEnabled = true;
678 const size_t kNumStreams = 2;
679 const size_t kNumTl = 1;
sprang317005a2017-06-08 07:12:17 -0700680 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800681 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
682
683 // Capture a frame and wait for it to synchronize with the encoder thread.
684 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang317005a2017-06-08 07:12:17 -0700685 sink_.WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800686 // The encoder have been configured once when the first frame is received.
687 EXPECT_EQ(1, sink_.number_of_reconfigurations());
688 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
689 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
690 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
691 // Resilience is off for no temporal layers and >1 streams with nack on.
692 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
693 vie_encoder_->Stop();
694}
695
696TEST_F(ViEEncoderTest, Vp8ResilienceIsOnFor1S1TLWithNackDisabled) {
697 const bool kNackEnabled = false;
698 const size_t kNumStreams = 1;
699 const size_t kNumTl = 1;
sprang317005a2017-06-08 07:12:17 -0700700 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800701 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
702
703 // Capture a frame and wait for it to synchronize with the encoder thread.
704 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang317005a2017-06-08 07:12:17 -0700705 sink_.WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800706 // The encoder have been configured once when the first frame is received.
707 EXPECT_EQ(1, sink_.number_of_reconfigurations());
708 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
709 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
710 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
711 // Resilience is on for no temporal layers with nack off.
712 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
713 vie_encoder_->Stop();
714}
715
716TEST_F(ViEEncoderTest, Vp8ResilienceIsOnFor1S2TlWithNackEnabled) {
717 const bool kNackEnabled = true;
718 const size_t kNumStreams = 1;
719 const size_t kNumTl = 2;
sprang317005a2017-06-08 07:12:17 -0700720 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800721 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
722
723 // Capture a frame and wait for it to synchronize with the encoder thread.
724 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang317005a2017-06-08 07:12:17 -0700725 sink_.WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800726 // The encoder have been configured once when the first frame is received.
727 EXPECT_EQ(1, sink_.number_of_reconfigurations());
728 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
729 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
730 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
731 // Resilience is on for temporal layers.
732 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
733 vie_encoder_->Stop();
734}
735
perkj803d97f2016-11-01 11:45:46 -0700736TEST_F(ViEEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
737 EXPECT_TRUE(video_source_.has_sinks());
738 test::FrameForwarder new_video_source;
sprangc5d62e22017-04-02 23:53:04 -0700739 vie_encoder_->SetSource(
740 &new_video_source,
741 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -0700742 EXPECT_FALSE(video_source_.has_sinks());
743 EXPECT_TRUE(new_video_source.has_sinks());
744
745 vie_encoder_->Stop();
746}
747
748TEST_F(ViEEncoderTest, SinkWantsRotationApplied) {
749 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
750 vie_encoder_->SetSink(&sink_, true /*rotation_applied*/);
751 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
752 vie_encoder_->Stop();
753}
754
755TEST_F(ViEEncoderTest, SinkWantsFromOveruseDetector) {
asaperssond0de2952017-04-21 01:47:31 -0700756 const int kMaxDowngrades = ViEEncoder::kMaxCpuResolutionDowngrades;
perkj803d97f2016-11-01 11:45:46 -0700757 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
758
asapersson02465b82017-04-10 01:12:52 -0700759 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700760
761 int frame_width = 1280;
762 int frame_height = 720;
763
764 // Trigger CPU overuse kMaxCpuDowngrades times. Every time, ViEEncoder should
765 // request lower resolution.
asaperssond0de2952017-04-21 01:47:31 -0700766 for (int i = 1; i <= kMaxDowngrades; ++i) {
perkj803d97f2016-11-01 11:45:46 -0700767 video_source_.IncomingCapturedFrame(
768 CreateFrame(i, frame_width, frame_height));
sprang317005a2017-06-08 07:12:17 -0700769 sink_.WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -0700770
771 vie_encoder_->TriggerCpuOveruse();
772
sprang84a37592017-02-10 07:04:27 -0800773 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700774 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
perkj803d97f2016-11-01 11:45:46 -0700775 frame_width * frame_height);
asaperssond0de2952017-04-21 01:47:31 -0700776 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
777 EXPECT_EQ(i, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -0700778
779 frame_width /= 2;
780 frame_height /= 2;
781 }
782
kthelgason876222f2016-11-29 01:44:11 -0800783 // Trigger CPU overuse one more time. This should not trigger a request for
perkj803d97f2016-11-01 11:45:46 -0700784 // lower resolution.
785 rtc::VideoSinkWants current_wants = video_source_.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -0700786 video_source_.IncomingCapturedFrame(
787 CreateFrame(kMaxDowngrades + 1, frame_width, frame_height));
sprang317005a2017-06-08 07:12:17 -0700788 sink_.WaitForEncodedFrame(kMaxDowngrades + 1);
perkj803d97f2016-11-01 11:45:46 -0700789 vie_encoder_->TriggerCpuOveruse();
sprang84a37592017-02-10 07:04:27 -0800790 EXPECT_EQ(video_source_.sink_wants().target_pixel_count,
791 current_wants.target_pixel_count);
perkj803d97f2016-11-01 11:45:46 -0700792 EXPECT_EQ(video_source_.sink_wants().max_pixel_count,
793 current_wants.max_pixel_count);
asaperssond0de2952017-04-21 01:47:31 -0700794 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
795 EXPECT_EQ(kMaxDowngrades,
796 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -0700797
798 // Trigger CPU normal use.
799 vie_encoder_->TriggerCpuNormalUsage();
sprang84a37592017-02-10 07:04:27 -0800800 EXPECT_EQ(frame_width * frame_height * 5 / 3,
801 video_source_.sink_wants().target_pixel_count.value_or(0));
802 EXPECT_EQ(frame_width * frame_height * 4,
sprangc5d62e22017-04-02 23:53:04 -0700803 video_source_.sink_wants().max_pixel_count);
asaperssond0de2952017-04-21 01:47:31 -0700804 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
805 EXPECT_EQ(kMaxDowngrades + 1,
806 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -0700807
808 vie_encoder_->Stop();
809}
810
sprangc5d62e22017-04-02 23:53:04 -0700811TEST_F(ViEEncoderTest, SinkWantsStoredByDegradationPreference) {
perkj803d97f2016-11-01 11:45:46 -0700812 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -0700813 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700814
sprangc5d62e22017-04-02 23:53:04 -0700815 const int kFrameWidth = 1280;
816 const int kFrameHeight = 720;
817 const int kFrameIntervalMs = 1000 / 30;
818
819 int frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -0700820
kthelgason5e13d412016-12-01 03:59:51 -0800821 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700822 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -0700823 sink_.WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700824 frame_timestamp += kFrameIntervalMs;
825
perkj803d97f2016-11-01 11:45:46 -0700826 // Trigger CPU overuse.
827 vie_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700828 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700829 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -0700830 sink_.WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700831 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -0700832
asapersson0944a802017-04-07 00:57:58 -0700833 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -0700834 // wanted resolution.
835 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
836 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
837 kFrameWidth * kFrameHeight);
838 EXPECT_EQ(std::numeric_limits<int>::max(),
839 video_source_.sink_wants().max_framerate_fps);
840
841 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -0700842 test::FrameForwarder new_video_source;
843 vie_encoder_->SetSource(
844 &new_video_source,
845 VideoSendStream::DegradationPreference::kMaintainResolution);
846
sprangc5d62e22017-04-02 23:53:04 -0700847 // Initially no degradation registered.
asapersson02465b82017-04-10 01:12:52 -0700848 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700849
sprangc5d62e22017-04-02 23:53:04 -0700850 // Force an input frame rate to be available, or the adaptation call won't
851 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -0700852 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -0700853 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -0700854 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -0700855 stats_proxy_->SetMockStats(stats);
856
857 vie_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700858 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700859 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -0700860 sink_.WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700861 frame_timestamp += kFrameIntervalMs;
862
863 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -0800864 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700865 EXPECT_EQ(std::numeric_limits<int>::max(),
866 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700867 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -0700868
asapersson02465b82017-04-10 01:12:52 -0700869 // Turn off degradation completely.
sprangc5d62e22017-04-02 23:53:04 -0700870 vie_encoder_->SetSource(
871 &new_video_source,
872 VideoSendStream::DegradationPreference::kDegradationDisabled);
asapersson02465b82017-04-10 01:12:52 -0700873 VerifyNoLimitation(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -0700874
875 vie_encoder_->TriggerCpuOveruse();
876 new_video_source.IncomingCapturedFrame(
877 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -0700878 sink_.WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700879 frame_timestamp += kFrameIntervalMs;
880
881 // Still no degradation.
asapersson02465b82017-04-10 01:12:52 -0700882 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700883
884 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
sprangc5d62e22017-04-02 23:53:04 -0700885 vie_encoder_->SetSource(
886 &new_video_source,
887 VideoSendStream::DegradationPreference::kMaintainFramerate);
888 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
889 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -0800890 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700891 EXPECT_EQ(std::numeric_limits<int>::max(),
892 new_video_source.sink_wants().max_framerate_fps);
893
894 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
895 vie_encoder_->SetSource(
896 &new_video_source,
897 VideoSendStream::DegradationPreference::kMaintainResolution);
898 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
899 EXPECT_EQ(std::numeric_limits<int>::max(),
900 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700901 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -0700902
903 vie_encoder_->Stop();
904}
905
asaperssonfab67072017-04-04 05:51:49 -0700906TEST_F(ViEEncoderTest, StatsTracksQualityAdaptationStats) {
perkj803d97f2016-11-01 11:45:46 -0700907 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
908
asaperssonfab67072017-04-04 05:51:49 -0700909 const int kWidth = 1280;
910 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -0700911 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -0700912 sink_.WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -0700913 VideoSendStream::Stats stats = stats_proxy_->GetStats();
914 EXPECT_FALSE(stats.bw_limited_resolution);
915 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
916
917 // Trigger adapt down.
918 vie_encoder_->TriggerQualityLow();
919 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -0700920 sink_.WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -0700921
922 stats = stats_proxy_->GetStats();
923 EXPECT_TRUE(stats.bw_limited_resolution);
924 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
925
926 // Trigger adapt up.
927 vie_encoder_->TriggerQualityHigh();
928 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -0700929 sink_.WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -0700930
931 stats = stats_proxy_->GetStats();
932 EXPECT_FALSE(stats.bw_limited_resolution);
933 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
934 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
935
936 vie_encoder_->Stop();
937}
938
939TEST_F(ViEEncoderTest, StatsTracksCpuAdaptationStats) {
940 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
941
942 const int kWidth = 1280;
943 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -0700944 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -0700945 sink_.WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -0700946 VideoSendStream::Stats stats = stats_proxy_->GetStats();
947 EXPECT_FALSE(stats.cpu_limited_resolution);
948 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
949
950 // Trigger CPU overuse.
951 vie_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -0700952 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -0700953 sink_.WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -0700954
955 stats = stats_proxy_->GetStats();
956 EXPECT_TRUE(stats.cpu_limited_resolution);
957 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
958
959 // Trigger CPU normal use.
960 vie_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -0700961 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -0700962 sink_.WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -0700963
964 stats = stats_proxy_->GetStats();
965 EXPECT_FALSE(stats.cpu_limited_resolution);
966 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -0700967 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -0700968
969 vie_encoder_->Stop();
970}
971
kthelgason876222f2016-11-29 01:44:11 -0800972TEST_F(ViEEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
kthelgason876222f2016-11-29 01:44:11 -0800973 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
974
asaperssonfab67072017-04-04 05:51:49 -0700975 const int kWidth = 1280;
976 const int kHeight = 720;
977 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -0700978 sink_.WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -0800979 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -0700980 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -0800981 EXPECT_FALSE(stats.cpu_limited_resolution);
982 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
983
asaperssonfab67072017-04-04 05:51:49 -0700984 // Trigger CPU overuse.
kthelgason876222f2016-11-29 01:44:11 -0800985 vie_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -0700986 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -0700987 sink_.WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -0800988 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -0700989 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -0800990 EXPECT_TRUE(stats.cpu_limited_resolution);
991 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
992
993 // Set new source with adaptation still enabled.
994 test::FrameForwarder new_video_source;
sprangc5d62e22017-04-02 23:53:04 -0700995 vie_encoder_->SetSource(
996 &new_video_source,
997 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -0800998
asaperssonfab67072017-04-04 05:51:49 -0700999 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001000 sink_.WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001001 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001002 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001003 EXPECT_TRUE(stats.cpu_limited_resolution);
1004 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1005
1006 // Set adaptation disabled.
1007 vie_encoder_->SetSource(
1008 &new_video_source,
sprangc5d62e22017-04-02 23:53:04 -07001009 VideoSendStream::DegradationPreference::kDegradationDisabled);
kthelgason876222f2016-11-29 01:44:11 -08001010
asaperssonfab67072017-04-04 05:51:49 -07001011 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001012 sink_.WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001013 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001014 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001015 EXPECT_FALSE(stats.cpu_limited_resolution);
1016 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1017
1018 // Set adaptation back to enabled.
sprangc5d62e22017-04-02 23:53:04 -07001019 vie_encoder_->SetSource(
1020 &new_video_source,
1021 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001022
asaperssonfab67072017-04-04 05:51:49 -07001023 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001024 sink_.WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001025 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001026 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001027 EXPECT_TRUE(stats.cpu_limited_resolution);
1028 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1029
asaperssonfab67072017-04-04 05:51:49 -07001030 // Trigger CPU normal use.
kthelgason876222f2016-11-29 01:44:11 -08001031 vie_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001032 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001033 sink_.WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001034 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001035 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001036 EXPECT_FALSE(stats.cpu_limited_resolution);
1037 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001038 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001039
1040 vie_encoder_->Stop();
1041}
1042
1043TEST_F(ViEEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
kthelgason876222f2016-11-29 01:44:11 -08001044 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1045
asaperssonfab67072017-04-04 05:51:49 -07001046 const int kWidth = 1280;
1047 const int kHeight = 720;
1048 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001049 sink_.WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001050 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001051 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001052 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001053 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001054
1055 // Set new source with adaptation still enabled.
1056 test::FrameForwarder new_video_source;
1057 vie_encoder_->SetSource(&new_video_source,
1058 VideoSendStream::DegradationPreference::kBalanced);
1059
asaperssonfab67072017-04-04 05:51:49 -07001060 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001061 sink_.WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001062 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001063 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001064 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001065 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001066
asaperssonfab67072017-04-04 05:51:49 -07001067 // Trigger adapt down.
kthelgason876222f2016-11-29 01:44:11 -08001068 vie_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001069 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001070 sink_.WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001071 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001072 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001073 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001074 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001075
asaperssonfab67072017-04-04 05:51:49 -07001076 // Set new source with adaptation still enabled.
kthelgason876222f2016-11-29 01:44:11 -08001077 vie_encoder_->SetSource(&new_video_source,
1078 VideoSendStream::DegradationPreference::kBalanced);
1079
asaperssonfab67072017-04-04 05:51:49 -07001080 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001081 sink_.WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001082 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001083 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001084 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001085 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001086
asapersson02465b82017-04-10 01:12:52 -07001087 // Disable resolution scaling.
kthelgason876222f2016-11-29 01:44:11 -08001088 vie_encoder_->SetSource(
1089 &new_video_source,
1090 VideoSendStream::DegradationPreference::kMaintainResolution);
1091
asaperssonfab67072017-04-04 05:51:49 -07001092 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001093 sink_.WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001094 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001095 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001096 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001097 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1098 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001099
1100 vie_encoder_->Stop();
1101}
1102
asapersson36e9eb42017-03-31 05:29:12 -07001103TEST_F(ViEEncoderTest, QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1104 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1105
1106 const int kWidth = 1280;
1107 const int kHeight = 720;
1108 video_source_.set_adaptation_enabled(true);
1109 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001110 sink_.WaitForEncodedFrame(1);
asapersson36e9eb42017-03-31 05:29:12 -07001111 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1112 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1113 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1114
1115 // Trigger adapt down.
1116 vie_encoder_->TriggerQualityLow();
1117 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001118 sink_.WaitForEncodedFrame(2);
asapersson36e9eb42017-03-31 05:29:12 -07001119 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1120 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1121 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1122
1123 // Trigger overuse.
1124 vie_encoder_->TriggerCpuOveruse();
1125 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001126 sink_.WaitForEncodedFrame(3);
asapersson36e9eb42017-03-31 05:29:12 -07001127 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1128 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1129 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1130
1131 // Set source with adaptation still enabled but quality scaler is off.
1132 fake_encoder_.SetQualityScaling(false);
sprangc5d62e22017-04-02 23:53:04 -07001133 vie_encoder_->SetSource(
1134 &video_source_,
1135 VideoSendStream::DegradationPreference::kMaintainFramerate);
asapersson36e9eb42017-03-31 05:29:12 -07001136
1137 video_source_.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001138 sink_.WaitForEncodedFrame(4);
asapersson36e9eb42017-03-31 05:29:12 -07001139 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1140 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1141 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1142
1143 vie_encoder_->Stop();
1144}
1145
asapersson02465b82017-04-10 01:12:52 -07001146TEST_F(ViEEncoderTest, StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
perkj803d97f2016-11-01 11:45:46 -07001147 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1148
asapersson0944a802017-04-07 00:57:58 -07001149 const int kWidth = 1280;
1150 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001151 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001152
asaperssonfab67072017-04-04 05:51:49 -07001153 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001154 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001155 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001156 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001157 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001158 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1159
asapersson02465b82017-04-10 01:12:52 -07001160 // Trigger CPU overuse, should now adapt down.
sprang84a37592017-02-10 07:04:27 -08001161 vie_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001162 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001163 sink_.WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001164 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001165 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001166 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001167 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1168
1169 // Set new source with adaptation still enabled.
1170 test::FrameForwarder new_video_source;
sprangc5d62e22017-04-02 23:53:04 -07001171 vie_encoder_->SetSource(
1172 &new_video_source,
1173 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001174
1175 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001176 CreateFrame(sequence, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001177 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001178 stats = stats_proxy_->GetStats();
1179 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001180 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001181 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1182
sprangc5d62e22017-04-02 23:53:04 -07001183 // Set cpu adaptation by frame dropping.
perkj803d97f2016-11-01 11:45:46 -07001184 vie_encoder_->SetSource(
1185 &new_video_source,
1186 VideoSendStream::DegradationPreference::kMaintainResolution);
1187 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001188 CreateFrame(sequence, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001189 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001190 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001191 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001192 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001193 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001194 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1195
sprangc5d62e22017-04-02 23:53:04 -07001196 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001197 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001198 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1199 mock_stats.input_frame_rate = 30;
1200 stats_proxy_->SetMockStats(mock_stats);
1201 vie_encoder_->TriggerCpuOveruse();
1202 stats_proxy_->ResetMockStats();
1203
1204 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001205 CreateFrame(sequence, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001206 sink_.WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001207
1208 // Framerate now adapted.
1209 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001210 EXPECT_FALSE(stats.cpu_limited_resolution);
1211 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001212 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1213
1214 // Disable CPU adaptation.
1215 vie_encoder_->SetSource(
1216 &new_video_source,
1217 VideoSendStream::DegradationPreference::kDegradationDisabled);
1218 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001219 CreateFrame(sequence, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001220 sink_.WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001221
1222 stats = stats_proxy_->GetStats();
1223 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001224 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001225 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1226
1227 // Try to trigger overuse. Should not succeed.
1228 stats_proxy_->SetMockStats(mock_stats);
1229 vie_encoder_->TriggerCpuOveruse();
1230 stats_proxy_->ResetMockStats();
1231
1232 stats = stats_proxy_->GetStats();
1233 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001234 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001235 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1236
1237 // Switch back the source with resolution adaptation enabled.
1238 vie_encoder_->SetSource(
1239 &video_source_,
1240 VideoSendStream::DegradationPreference::kMaintainFramerate);
asaperssonfab67072017-04-04 05:51:49 -07001241 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001242 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001243 stats = stats_proxy_->GetStats();
1244 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001245 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001246 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001247
1248 // Trigger CPU normal usage.
1249 vie_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001250 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001251 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001252 stats = stats_proxy_->GetStats();
1253 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001254 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001255 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1256
1257 // Back to the source with adaptation off, set it back to maintain-resolution.
1258 vie_encoder_->SetSource(
1259 &new_video_source,
1260 VideoSendStream::DegradationPreference::kMaintainResolution);
1261 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001262 CreateFrame(sequence, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001263 sink_.WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001264 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001265 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001266 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001267 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001268 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1269
1270 // Trigger CPU normal usage.
1271 vie_encoder_->TriggerCpuNormalUsage();
1272 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001273 CreateFrame(sequence, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001274 sink_.WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001275 stats = stats_proxy_->GetStats();
1276 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001277 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001278 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001279 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001280
1281 vie_encoder_->Stop();
1282}
1283
Erik Språng08127a92016-11-16 16:41:30 +01001284TEST_F(ViEEncoderTest, StatsTracksPreferredBitrate) {
Erik Språng08127a92016-11-16 16:41:30 +01001285 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1286
asaperssonfab67072017-04-04 05:51:49 -07001287 const int kWidth = 1280;
1288 const int kHeight = 720;
1289 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001290 sink_.WaitForEncodedFrame(1);
Erik Språng08127a92016-11-16 16:41:30 +01001291
1292 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1293 EXPECT_EQ(video_encoder_config_.max_bitrate_bps,
1294 stats.preferred_media_bitrate_bps);
1295
1296 vie_encoder_->Stop();
1297}
1298
kthelgason876222f2016-11-29 01:44:11 -08001299TEST_F(ViEEncoderTest, ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001300 const int kWidth = 1280;
1301 const int kHeight = 720;
kthelgason876222f2016-11-29 01:44:11 -08001302 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1303
asaperssonfab67072017-04-04 05:51:49 -07001304 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001305 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001306
asaperssonfab67072017-04-04 05:51:49 -07001307 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001308 sink_.WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001309
asaperssonfab67072017-04-04 05:51:49 -07001310 // Trigger scale down.
kthelgason5e13d412016-12-01 03:59:51 -08001311 vie_encoder_->TriggerQualityLow();
1312
asaperssonfab67072017-04-04 05:51:49 -07001313 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001314 sink_.WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001315
kthelgason876222f2016-11-29 01:44:11 -08001316 // Expect a scale down.
1317 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001318 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001319
asapersson02465b82017-04-10 01:12:52 -07001320 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001321 test::FrameForwarder new_video_source;
1322 vie_encoder_->SetSource(
1323 &new_video_source,
1324 VideoSendStream::DegradationPreference::kMaintainResolution);
1325
asaperssonfab67072017-04-04 05:51:49 -07001326 // Trigger scale down.
kthelgason876222f2016-11-29 01:44:11 -08001327 vie_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001328 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001329 sink_.WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001330
asaperssonfab67072017-04-04 05:51:49 -07001331 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001332 EXPECT_EQ(std::numeric_limits<int>::max(),
1333 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001334
asaperssonfab67072017-04-04 05:51:49 -07001335 // Trigger scale up.
kthelgason876222f2016-11-29 01:44:11 -08001336 vie_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001337 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001338 sink_.WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001339
asapersson02465b82017-04-10 01:12:52 -07001340 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001341 EXPECT_EQ(std::numeric_limits<int>::max(),
1342 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001343
1344 vie_encoder_->Stop();
1345}
1346
asapersson02465b82017-04-10 01:12:52 -07001347TEST_F(ViEEncoderTest, SkipsSameAdaptDownRequest_MaintainFramerateMode) {
1348 const int kWidth = 1280;
1349 const int kHeight = 720;
1350 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1351
1352 // Enable kMaintainFramerate preference, no initial limitation.
1353 test::FrameForwarder source;
1354 vie_encoder_->SetSource(
1355 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1356
1357 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001358 sink_.WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001359 VerifyNoLimitation(source.sink_wants());
1360 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1361 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1362
1363 // Trigger adapt down, expect scaled down resolution.
1364 vie_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001365 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001366 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1367 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1368 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1369
1370 // Trigger adapt down for same input resolution, expect no change.
1371 vie_encoder_->TriggerCpuOveruse();
1372 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1373 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1374 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1375
1376 vie_encoder_->Stop();
1377}
1378
1379TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_MaintainFramerateMode) {
1380 const int kWidth = 1280;
1381 const int kHeight = 720;
1382 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1383
1384 // Enable kMaintainFramerate preference, no initial limitation.
1385 test::FrameForwarder source;
1386 vie_encoder_->SetSource(
1387 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1388
1389 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001390 sink_.WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001391 VerifyNoLimitation(source.sink_wants());
1392 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1393 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1394
1395 // Trigger adapt up, expect no change.
1396 vie_encoder_->TriggerCpuNormalUsage();
1397 VerifyNoLimitation(source.sink_wants());
1398 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1399 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1400
1401 vie_encoder_->Stop();
1402}
1403
1404TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_MaintainResolutionMode) {
1405 const int kWidth = 1280;
1406 const int kHeight = 720;
1407 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1408
1409 // Enable kMaintainResolution preference, no initial limitation.
1410 test::FrameForwarder source;
1411 vie_encoder_->SetSource(
1412 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
1413
1414 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001415 sink_.WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001416 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001417 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001418 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1419
1420 // Trigger adapt up, expect no change.
1421 vie_encoder_->TriggerCpuNormalUsage();
1422 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001423 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001424 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1425
1426 vie_encoder_->Stop();
1427}
1428
asapersson09f05612017-05-15 23:40:18 -07001429TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
1430 const int kWidth = 1280;
1431 const int kHeight = 720;
1432 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1433
1434 // Enable kDegradationDisabled preference, no initial limitation.
1435 test::FrameForwarder source;
1436 vie_encoder_->SetSource(
1437 &source, VideoSendStream::DegradationPreference::kDegradationDisabled);
1438
1439 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1440 sink_.WaitForEncodedFrame(kWidth, kHeight);
1441 VerifyNoLimitation(source.sink_wants());
1442 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1443 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1444 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1445
1446 // Trigger adapt up, expect no change.
1447 vie_encoder_->TriggerQualityHigh();
1448 VerifyNoLimitation(source.sink_wants());
1449 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1450 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1451 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1452
1453 vie_encoder_->Stop();
1454}
1455
asapersson02465b82017-04-10 01:12:52 -07001456TEST_F(ViEEncoderTest, AdaptsResolutionForLowQuality_MaintainFramerateMode) {
1457 const int kWidth = 1280;
1458 const int kHeight = 720;
1459 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1460
1461 // Enable kMaintainFramerate preference, no initial limitation.
1462 AdaptingFrameForwarder source;
1463 source.set_adaptation_enabled(true);
1464 vie_encoder_->SetSource(
1465 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1466
1467 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001468 sink_.WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001469 VerifyNoLimitation(source.sink_wants());
1470 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1471 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1472
1473 // Trigger adapt down, expect scaled down resolution.
1474 vie_encoder_->TriggerQualityLow();
1475 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001476 sink_.WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001477 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001478 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1479 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1480
1481 // Trigger adapt up, expect no restriction.
1482 vie_encoder_->TriggerQualityHigh();
1483 VerifyNoLimitation(source.sink_wants());
1484 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1485 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1486 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1487
1488 vie_encoder_->Stop();
1489}
1490
asapersson09f05612017-05-15 23:40:18 -07001491TEST_F(ViEEncoderTest, AdaptsFramerateForLowQuality_MaintainResolutionMode) {
1492 const int kWidth = 1280;
1493 const int kHeight = 720;
1494 const int kInputFps = 30;
1495 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1496
1497 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1498 stats.input_frame_rate = kInputFps;
1499 stats_proxy_->SetMockStats(stats);
1500
1501 // Expect no scaling to begin with (preference: kMaintainFramerate).
1502 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1503 sink_.WaitForEncodedFrame(1);
1504 VerifyNoLimitation(video_source_.sink_wants());
1505
1506 // Trigger adapt down, expect scaled down resolution.
1507 vie_encoder_->TriggerQualityLow();
1508 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1509 sink_.WaitForEncodedFrame(2);
1510 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1511
1512 // Enable kMaintainResolution preference.
1513 test::FrameForwarder new_video_source;
1514 vie_encoder_->SetSource(
1515 &new_video_source,
1516 VideoSendStream::DegradationPreference::kMaintainResolution);
1517 VerifyNoLimitation(new_video_source.sink_wants());
1518
1519 // Trigger adapt down, expect reduced framerate.
1520 vie_encoder_->TriggerQualityLow();
1521 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1522 sink_.WaitForEncodedFrame(3);
1523 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1524
1525 // Trigger adapt up, expect no restriction.
1526 vie_encoder_->TriggerQualityHigh();
1527 VerifyNoLimitation(new_video_source.sink_wants());
1528
1529 vie_encoder_->Stop();
1530}
1531
asaperssond0de2952017-04-21 01:47:31 -07001532TEST_F(ViEEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
1533 const int kWidth = 1280;
1534 const int kHeight = 720;
1535 const size_t kNumFrames = 10;
1536
kthelgason5e13d412016-12-01 03:59:51 -08001537 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1538
asaperssond0de2952017-04-21 01:47:31 -07001539 // Enable adapter, expected input resolutions when downscaling:
1540 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (min resolution limit)
1541 video_source_.set_adaptation_enabled(true);
1542
1543 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1544 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1545
1546 int downscales = 0;
1547 for (size_t i = 1; i <= kNumFrames; i++) {
1548 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001549 sink_.WaitForEncodedFrame(i);
asaperssond0de2952017-04-21 01:47:31 -07001550
asaperssonfab67072017-04-04 05:51:49 -07001551 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001552 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
kthelgason5e13d412016-12-01 03:59:51 -08001553 vie_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001554 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001555
1556 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1557 ++downscales;
1558
1559 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1560 EXPECT_EQ(downscales,
1561 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1562 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001563 }
asaperssond0de2952017-04-21 01:47:31 -07001564 vie_encoder_->Stop();
1565}
1566
1567TEST_F(ViEEncoderTest,
1568 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1569 const int kWidth = 1280;
1570 const int kHeight = 720;
1571 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1572
1573 // Enable kMaintainFramerate preference, no initial limitation.
1574 AdaptingFrameForwarder source;
1575 source.set_adaptation_enabled(true);
1576 vie_encoder_->SetSource(
1577 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1578
1579 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001580 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001581 VerifyNoLimitation(source.sink_wants());
1582 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1583 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1584
1585 // Trigger adapt down, expect scaled down resolution.
1586 vie_encoder_->TriggerCpuOveruse();
1587 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001588 sink_.WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001589 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001590 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1591 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1592
1593 // Trigger adapt up, expect no restriction.
1594 vie_encoder_->TriggerCpuNormalUsage();
1595 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001596 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001597 VerifyNoLimitation(source.sink_wants());
1598 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1599 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1600
1601 // Trigger adapt down, expect scaled down resolution.
1602 vie_encoder_->TriggerCpuOveruse();
1603 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001604 sink_.WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07001605 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001606 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1607 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1608
1609 // Trigger adapt up, expect no restriction.
1610 vie_encoder_->TriggerCpuNormalUsage();
asapersson09f05612017-05-15 23:40:18 -07001611 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1612 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001613 VerifyNoLimitation(source.sink_wants());
1614 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1615 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1616
1617 vie_encoder_->Stop();
1618}
1619
1620TEST_F(ViEEncoderTest,
1621 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
1622 const int kWidth = 1280;
1623 const int kHeight = 720;
1624 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1625
1626 // Enable kMaintainFramerate preference, no initial limitation.
1627 AdaptingFrameForwarder source;
1628 source.set_adaptation_enabled(true);
1629 vie_encoder_->SetSource(
1630 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1631
1632 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001633 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001634 VerifyNoLimitation(source.sink_wants());
1635 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1636 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1637 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1638 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1639
1640 // Trigger cpu adapt down, expect scaled down resolution (960x540).
1641 vie_encoder_->TriggerCpuOveruse();
1642 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001643 sink_.WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001644 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001645 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1646 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1647 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1648 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1649
1650 // Trigger cpu adapt down, expect scaled down resolution (640x360).
1651 vie_encoder_->TriggerCpuOveruse();
1652 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001653 sink_.WaitForEncodedFrame(3);
asapersson09f05612017-05-15 23:40:18 -07001654 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
1655 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07001656 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1657 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1658 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1659 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1660
1661 // Trigger cpu adapt down, max cpu downgrades reached, expect no change.
1662 vie_encoder_->TriggerCpuOveruse();
1663 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001664 sink_.WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07001665 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07001666 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1667 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1668 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1669 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1670
1671 // Trigger quality adapt down, expect scaled down resolution (480x270).
1672 vie_encoder_->TriggerQualityLow();
1673 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001674 sink_.WaitForEncodedFrame(5);
asapersson09f05612017-05-15 23:40:18 -07001675 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001676 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1677 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1678 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1679 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1680
1681 // Trigger cpu adapt up, expect upscaled resolution (640x360).
1682 vie_encoder_->TriggerCpuNormalUsage();
1683 source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001684 sink_.WaitForEncodedFrame(6);
asapersson09f05612017-05-15 23:40:18 -07001685 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001686 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1687 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1688 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1689 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1690
1691 // Trigger cpu adapt up, expect upscaled resolution (960x540).
1692 vie_encoder_->TriggerCpuNormalUsage();
1693 source.IncomingCapturedFrame(CreateFrame(7, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001694 sink_.WaitForEncodedFrame(7);
asapersson09f05612017-05-15 23:40:18 -07001695 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001696 last_wants = source.sink_wants();
1697 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1698 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1699 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1700 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1701
1702 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
1703 vie_encoder_->TriggerCpuNormalUsage();
1704 source.IncomingCapturedFrame(CreateFrame(8, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001705 sink_.WaitForEncodedFrame(8);
asapersson09f05612017-05-15 23:40:18 -07001706 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07001707 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1708 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1709 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1710 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1711
1712 // Trigger quality adapt up, expect no restriction (1280x720).
1713 vie_encoder_->TriggerQualityHigh();
1714 source.IncomingCapturedFrame(CreateFrame(9, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001715 sink_.WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07001716 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001717 VerifyNoLimitation(source.sink_wants());
1718 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1719 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1720 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1721 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08001722
1723 vie_encoder_->Stop();
1724}
1725
asaperssonf4e44af2017-04-19 02:01:06 -07001726TEST_F(ViEEncoderTest, CpuLimitedHistogramIsReported) {
sprang317005a2017-06-08 07:12:17 -07001727 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001728 const int kWidth = 640;
1729 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07001730
1731 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07001732 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001733 sink_.WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07001734 }
1735
1736 vie_encoder_->TriggerCpuOveruse();
1737 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07001738 video_source_.IncomingCapturedFrame(CreateFrame(
1739 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001740 sink_.WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples +
1741 i);
perkj803d97f2016-11-01 11:45:46 -07001742 }
1743
1744 vie_encoder_->Stop();
sprangf8ee65e2017-02-28 08:49:33 -08001745 vie_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07001746 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08001747
perkj803d97f2016-11-01 11:45:46 -07001748 EXPECT_EQ(1,
1749 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
1750 EXPECT_EQ(
1751 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
1752}
1753
asaperssonf4e44af2017-04-19 02:01:06 -07001754TEST_F(ViEEncoderTest, CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
1755 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1756 const int kWidth = 640;
1757 const int kHeight = 360;
1758
1759 vie_encoder_->SetSource(
1760 &video_source_,
1761 VideoSendStream::DegradationPreference::kDegradationDisabled);
1762
1763 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
1764 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001765 sink_.WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07001766 }
1767
1768 vie_encoder_->Stop();
1769 vie_encoder_.reset();
1770 stats_proxy_.reset();
1771
1772 EXPECT_EQ(0,
1773 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
1774}
1775
sprang57c2fff2017-01-16 06:24:02 -08001776TEST_F(ViEEncoderTest, CallsBitrateObserver) {
1777 class MockBitrateObserver : public VideoBitrateAllocationObserver {
1778 public:
1779 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const BitrateAllocation&));
1780 } bitrate_observer;
1781 vie_encoder_->SetBitrateObserver(&bitrate_observer);
1782
1783 const int kDefaultFps = 30;
1784 const BitrateAllocation expected_bitrate =
1785 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08001786 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08001787
1788 // First called on bitrate updated, then again on first frame.
1789 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
1790 .Times(2);
kthelgason2bc68642017-02-07 07:02:22 -08001791 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08001792
1793 const int64_t kStartTimeMs = 1;
1794 video_source_.IncomingCapturedFrame(
1795 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang317005a2017-06-08 07:12:17 -07001796 sink_.WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08001797
1798 // Not called on second frame.
1799 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
1800 .Times(0);
1801 video_source_.IncomingCapturedFrame(
1802 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang317005a2017-06-08 07:12:17 -07001803 sink_.WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08001804
1805 // Called after a process interval.
1806 const int64_t kProcessIntervalMs =
1807 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang317005a2017-06-08 07:12:17 -07001808 // TODO(sprang): ViEEncoder should die and/or get injectable clock.
1809 // Sleep for one processing interval plus one frame to avoid flakiness.
1810 SleepMs(kProcessIntervalMs + 1000 / kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08001811 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
1812 .Times(1);
1813 video_source_.IncomingCapturedFrame(CreateFrame(
1814 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang317005a2017-06-08 07:12:17 -07001815 sink_.WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08001816
1817 vie_encoder_->Stop();
1818}
1819
kthelgason2bc68642017-02-07 07:02:22 -08001820TEST_F(ViEEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07001821 const int kTooLowBitrateForFrameSizeBps = 10000;
1822 vie_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
1823 const int kWidth = 640;
1824 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08001825
asaperssonfab67072017-04-04 05:51:49 -07001826 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08001827
1828 // Expect to drop this frame, the wait should time out.
sprang317005a2017-06-08 07:12:17 -07001829 sink_.ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08001830
1831 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07001832 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08001833
sprangc5d62e22017-04-02 23:53:04 -07001834 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08001835
asaperssonfab67072017-04-04 05:51:49 -07001836 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08001837 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001838 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08001839
1840 // Expect to drop this frame, the wait should time out.
sprang317005a2017-06-08 07:12:17 -07001841 sink_.ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08001842
sprangc5d62e22017-04-02 23:53:04 -07001843 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08001844
1845 vie_encoder_->Stop();
1846}
1847
asapersson09f05612017-05-15 23:40:18 -07001848TEST_F(ViEEncoderTest, NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07001849 const int kTooLowBitrateForFrameSizeBps = 10000;
1850 vie_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
1851 const int kWidth = 640;
1852 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08001853
1854 // We expect the n initial frames to get dropped.
1855 int i;
1856 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07001857 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001858 sink_.ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08001859 }
1860 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07001861 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang317005a2017-06-08 07:12:17 -07001862 sink_.WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08001863
1864 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07001865 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08001866
1867 vie_encoder_->Stop();
1868}
1869
1870TEST_F(ViEEncoderTest, InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07001871 const int kWidth = 640;
1872 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08001873 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
1874
1875 // Set degradation preference.
1876 vie_encoder_->SetSource(
1877 &video_source_,
1878 VideoSendStream::DegradationPreference::kMaintainResolution);
1879
asaperssonfab67072017-04-04 05:51:49 -07001880 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08001881 // Frame should not be dropped, even if it's too large.
sprang317005a2017-06-08 07:12:17 -07001882 sink_.WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08001883
1884 vie_encoder_->Stop();
1885}
1886
kthelgason2fc52542017-03-03 00:24:41 -08001887TEST_F(ViEEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07001888 const int kWidth = 640;
1889 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08001890 fake_encoder_.SetQualityScaling(false);
1891 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001892
kthelgasonb83797b2017-02-14 11:57:25 -08001893 // Force quality scaler reconfiguration by resetting the source.
1894 vie_encoder_->SetSource(&video_source_,
1895 VideoSendStream::DegradationPreference::kBalanced);
kthelgasonad9010c2017-02-14 00:46:51 -08001896
asaperssonfab67072017-04-04 05:51:49 -07001897 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08001898 // Frame should not be dropped, even if it's too large.
sprang317005a2017-06-08 07:12:17 -07001899 sink_.WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08001900
1901 vie_encoder_->Stop();
1902 fake_encoder_.SetQualityScaling(true);
1903}
1904
asaperssond0de2952017-04-21 01:47:31 -07001905TEST_F(ViEEncoderTest,
1906 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
1907 const int kTooSmallWidth = 10;
1908 const int kTooSmallHeight = 10;
1909 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1910
1911 // Enable kMaintainFramerate preference, no initial limitation.
1912 test::FrameForwarder source;
1913 vie_encoder_->SetSource(
1914 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1915 VerifyNoLimitation(source.sink_wants());
1916 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1917
1918 // Trigger adapt down, too small frame, expect no change.
1919 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang317005a2017-06-08 07:12:17 -07001920 sink_.WaitForEncodedFrame(1);
asaperssond0de2952017-04-21 01:47:31 -07001921 vie_encoder_->TriggerCpuOveruse();
1922 VerifyNoLimitation(source.sink_wants());
1923 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1924 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1925
1926 vie_encoder_->Stop();
1927}
1928
asapersson02465b82017-04-10 01:12:52 -07001929TEST_F(ViEEncoderTest, FailingInitEncodeDoesntCauseCrash) {
1930 fake_encoder_.ForceInitEncodeFailure(true);
1931 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang317005a2017-06-08 07:12:17 -07001932 ResetEncoder("VP8", 2, 1, true);
asapersson02465b82017-04-10 01:12:52 -07001933 const int kFrameWidth = 1280;
1934 const int kFrameHeight = 720;
1935 video_source_.IncomingCapturedFrame(
1936 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07001937 sink_.ExpectDroppedFrame();
asapersson02465b82017-04-10 01:12:52 -07001938 vie_encoder_->Stop();
1939}
1940
sprangb1ca0732017-02-01 08:38:12 -08001941// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
asaperssond0de2952017-04-21 01:47:31 -07001942TEST_F(ViEEncoderTest, AdaptsResolutionOnOveruse_MaintainFramerateMode) {
sprangb1ca0732017-02-01 08:38:12 -08001943 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1944
1945 const int kFrameWidth = 1280;
1946 const int kFrameHeight = 720;
1947 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
1948 // requested by ViEEncoder::VideoSourceProxy::RequestResolutionLowerThan().
1949 video_source_.set_adaptation_enabled(true);
1950
1951 video_source_.IncomingCapturedFrame(
1952 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07001953 sink_.WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08001954
1955 // Trigger CPU overuse, downscale by 3/4.
1956 vie_encoder_->TriggerCpuOveruse();
1957 video_source_.IncomingCapturedFrame(
1958 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07001959 sink_.WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08001960
asaperssonfab67072017-04-04 05:51:49 -07001961 // Trigger CPU normal use, return to original resolution.
sprangb1ca0732017-02-01 08:38:12 -08001962 vie_encoder_->TriggerCpuNormalUsage();
1963 video_source_.IncomingCapturedFrame(
1964 CreateFrame(3, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07001965 sink_.WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08001966
1967 vie_encoder_->Stop();
1968}
sprangfe627f32017-03-29 08:24:59 -07001969
asapersson02465b82017-04-10 01:12:52 -07001970TEST_F(ViEEncoderTest, AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprang317005a2017-06-08 07:12:17 -07001971 const int kDefaultFramerateFps = 30;
1972 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kDefaultFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07001973 const int kFrameWidth = 1280;
1974 const int kFrameHeight = 720;
sprang317005a2017-06-08 07:12:17 -07001975 rtc::ScopedFakeClock fake_clock;
sprangc5d62e22017-04-02 23:53:04 -07001976
1977 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1978 vie_encoder_->SetSource(
1979 &video_source_,
1980 VideoSendStream::DegradationPreference::kMaintainResolution);
1981 video_source_.set_adaptation_enabled(true);
1982
sprang317005a2017-06-08 07:12:17 -07001983 fake_clock.SetTimeMicros(kFrameIntervalMs * 1000);
1984 int64_t timestamp_ms = kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07001985
1986 video_source_.IncomingCapturedFrame(
1987 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07001988 sink_.WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07001989
1990 // Try to trigger overuse. No fps estimate available => no effect.
1991 vie_encoder_->TriggerCpuOveruse();
1992
1993 // Insert frames for one second to get a stable estimate.
sprang317005a2017-06-08 07:12:17 -07001994 for (int i = 0; i < kDefaultFramerateFps; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07001995 timestamp_ms += kFrameIntervalMs;
sprang317005a2017-06-08 07:12:17 -07001996 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
sprangc5d62e22017-04-02 23:53:04 -07001997 video_source_.IncomingCapturedFrame(
1998 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07001999 sink_.WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002000 }
2001
2002 // Trigger CPU overuse, reduce framerate by 2/3.
2003 vie_encoder_->TriggerCpuOveruse();
2004 int num_frames_dropped = 0;
sprang317005a2017-06-08 07:12:17 -07002005 for (int i = 0; i < kDefaultFramerateFps; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002006 timestamp_ms += kFrameIntervalMs;
sprang317005a2017-06-08 07:12:17 -07002007 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
sprangc5d62e22017-04-02 23:53:04 -07002008 video_source_.IncomingCapturedFrame(
2009 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07002010 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002011 ++num_frames_dropped;
2012 } else {
2013 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2014 }
2015 }
2016
sprang317005a2017-06-08 07:12:17 -07002017 // TODO(sprang): Find where there's rounding errors or stuff causing the
2018 // margin here to be a little larger than we'd like (input fps estimate is
2019 // off) and the frame dropping is a little too aggressive.
2020 const int kErrorMargin = 5;
2021 EXPECT_NEAR(num_frames_dropped,
2022 kDefaultFramerateFps - (kDefaultFramerateFps * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002023 kErrorMargin);
2024
2025 // Trigger CPU overuse, reduce framerate by 2/3 again.
2026 vie_encoder_->TriggerCpuOveruse();
2027 num_frames_dropped = 0;
sprang317005a2017-06-08 07:12:17 -07002028 for (int i = 0; i < kDefaultFramerateFps; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002029 timestamp_ms += kFrameIntervalMs;
sprang317005a2017-06-08 07:12:17 -07002030 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
sprangc5d62e22017-04-02 23:53:04 -07002031 video_source_.IncomingCapturedFrame(
2032 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07002033 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002034 ++num_frames_dropped;
2035 } else {
2036 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2037 }
2038 }
sprang317005a2017-06-08 07:12:17 -07002039 EXPECT_NEAR(num_frames_dropped,
2040 kDefaultFramerateFps - (kDefaultFramerateFps * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002041 kErrorMargin);
2042
2043 // Go back up one step.
2044 vie_encoder_->TriggerCpuNormalUsage();
2045 num_frames_dropped = 0;
sprang317005a2017-06-08 07:12:17 -07002046 for (int i = 0; i < kDefaultFramerateFps; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002047 timestamp_ms += kFrameIntervalMs;
sprang317005a2017-06-08 07:12:17 -07002048 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
sprangc5d62e22017-04-02 23:53:04 -07002049 video_source_.IncomingCapturedFrame(
2050 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07002051 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002052 ++num_frames_dropped;
2053 } else {
2054 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2055 }
2056 }
sprang317005a2017-06-08 07:12:17 -07002057 EXPECT_NEAR(num_frames_dropped,
2058 kDefaultFramerateFps - (kDefaultFramerateFps * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002059 kErrorMargin);
2060
2061 // Go back up to original mode.
2062 vie_encoder_->TriggerCpuNormalUsage();
2063 num_frames_dropped = 0;
sprang317005a2017-06-08 07:12:17 -07002064 for (int i = 0; i < kDefaultFramerateFps; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002065 timestamp_ms += kFrameIntervalMs;
sprang317005a2017-06-08 07:12:17 -07002066 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
sprangc5d62e22017-04-02 23:53:04 -07002067 video_source_.IncomingCapturedFrame(
2068 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07002069 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002070 ++num_frames_dropped;
2071 } else {
2072 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2073 }
2074 }
2075 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2076
2077 vie_encoder_->Stop();
2078}
2079
2080TEST_F(ViEEncoderTest, DoesntAdaptDownPastMinFramerate) {
2081 const int kFramerateFps = 5;
2082 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
2083 const int kMinFpsFrameInterval = rtc::kNumMillisecsPerSec / kMinFramerateFps;
2084 const int kFrameWidth = 1280;
2085 const int kFrameHeight = 720;
2086
sprang317005a2017-06-08 07:12:17 -07002087 rtc::ScopedFakeClock fake_clock;
sprangc5d62e22017-04-02 23:53:04 -07002088 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2089 vie_encoder_->SetSource(
2090 &video_source_,
2091 VideoSendStream::DegradationPreference::kMaintainResolution);
2092 video_source_.set_adaptation_enabled(true);
2093
sprang317005a2017-06-08 07:12:17 -07002094 fake_clock.SetTimeMicros(kFrameIntervalMs * 1000);
2095 int64_t timestamp_ms = kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002096
2097 // Trigger overuse as much as we can.
2098 for (int i = 0; i < ViEEncoder::kMaxCpuResolutionDowngrades; ++i) {
2099 // Insert frames to get a new fps estimate...
2100 for (int j = 0; j < kFramerateFps; ++j) {
2101 video_source_.IncomingCapturedFrame(
2102 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
2103 timestamp_ms += kFrameIntervalMs;
sprang317005a2017-06-08 07:12:17 -07002104 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
sprangc5d62e22017-04-02 23:53:04 -07002105 }
2106 // ...and then try to adapt again.
2107 vie_encoder_->TriggerCpuOveruse();
2108 }
2109
2110 // Drain any frame in the pipeline.
sprang317005a2017-06-08 07:12:17 -07002111 sink_.WaitForFrame(kDefaultTimeoutMs);
sprangc5d62e22017-04-02 23:53:04 -07002112
2113 // Insert frames at min fps, all should go through.
2114 for (int i = 0; i < 10; ++i) {
2115 timestamp_ms += kMinFpsFrameInterval;
sprang317005a2017-06-08 07:12:17 -07002116 fake_clock.AdvanceTimeMicros(kMinFpsFrameInterval * 1000);
sprangc5d62e22017-04-02 23:53:04 -07002117 video_source_.IncomingCapturedFrame(
2118 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang317005a2017-06-08 07:12:17 -07002119 sink_.WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002120 }
2121 vie_encoder_->Stop();
2122}
perkj26091b12016-09-01 01:17:40 -07002123} // namespace webrtc