blob: eb39bf7c4d909b40861500c0174e7f7740ece200 [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,
260 bool nack_enabled) {
261 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;
perkja49cbd32016-09-16 07:53:41 -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));
perkj26091b12016-09-01 01:17:40 -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));
perkj26091b12016-09-01 01:17:40 -0700545 sink_.WaitForEncodedFrame(2);
546 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));
perkj26091b12016-09-01 01:17:40 -0700552 sink_.WaitForEncodedFrame(1);
553
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));
perkj26091b12016-09-01 01:17:40 -0700560 sink_.WaitForEncodedFrame(3);
561 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));
perkj26091b12016-09-01 01:17:40 -0700567 sink_.WaitForEncodedFrame(1);
568
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));
perkj26091b12016-09-01 01:17:40 -0700573 sink_.WaitForEncodedFrame(2);
574 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));
perkj26091b12016-09-01 01:17:40 -0700581 sink_.WaitForEncodedFrame(1);
582
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));
perkj26091b12016-09-01 01:17:40 -0700595 sink_.WaitForEncodedFrame(1);
596 // 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();
601 sink_.WaitForEncodedFrame(3);
602
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));
Per512ecb32016-09-23 15:52:06 +0200612 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));
Per512ecb32016-09-23 15:52:06 +0200625 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));
637 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));
648 sink_.WaitForEncodedFrame(2);
649 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;
asaperssona90799d2016-12-09 02:35:20 -0800660 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));
665 sink_.WaitForEncodedFrame(1);
666 // 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;
asaperssona90799d2016-12-09 02:35:20 -0800680 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));
685 sink_.WaitForEncodedFrame(1);
686 // 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;
asaperssona90799d2016-12-09 02:35:20 -0800700 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));
705 sink_.WaitForEncodedFrame(1);
706 // 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;
asaperssona90799d2016-12-09 02:35:20 -0800720 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));
725 sink_.WaitForEncodedFrame(1);
726 // 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));
769 sink_.WaitForEncodedFrame(i);
770
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));
788 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));
823 sink_.WaitForEncodedFrame(frame_timestamp);
824 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));
830 sink_.WaitForEncodedFrame(frame_timestamp);
831 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));
860 sink_.WaitForEncodedFrame(frame_timestamp);
861 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));
878 sink_.WaitForEncodedFrame(frame_timestamp);
879 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));
912 sink_.WaitForEncodedFrame(1);
913 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));
920 sink_.WaitForEncodedFrame(2);
921
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));
929 sink_.WaitForEncodedFrame(3);
930
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));
perkj803d97f2016-11-01 11:45:46 -0700945 sink_.WaitForEncodedFrame(1);
946 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));
perkj803d97f2016-11-01 11:45:46 -0700953 sink_.WaitForEncodedFrame(2);
954
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));
perkj803d97f2016-11-01 11:45:46 -0700962 sink_.WaitForEncodedFrame(3);
963
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));
kthelgason876222f2016-11-29 01:44:11 -0800978 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));
kthelgason876222f2016-11-29 01:44:11 -0800987 sink_.WaitForEncodedFrame(2);
988 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));
kthelgason876222f2016-11-29 01:44:11 -08001000 sink_.WaitForEncodedFrame(3);
1001 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));
kthelgason876222f2016-11-29 01:44:11 -08001012 sink_.WaitForEncodedFrame(4);
1013 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));
kthelgason876222f2016-11-29 01:44:11 -08001024 sink_.WaitForEncodedFrame(5);
1025 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));
kthelgason876222f2016-11-29 01:44:11 -08001033 sink_.WaitForEncodedFrame(6);
1034 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));
kthelgason876222f2016-11-29 01:44:11 -08001049 sink_.WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001050 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1051 EXPECT_FALSE(stats.cpu_limited_resolution);
1052 EXPECT_FALSE(stats.bw_limited_resolution);
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));
kthelgason876222f2016-11-29 01:44:11 -08001061 sink_.WaitForEncodedFrame(2);
1062 stats = stats_proxy_->GetStats();
1063 EXPECT_FALSE(stats.cpu_limited_resolution);
1064 EXPECT_FALSE(stats.bw_limited_resolution);
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));
kthelgason876222f2016-11-29 01:44:11 -08001070 sink_.WaitForEncodedFrame(3);
1071 stats = stats_proxy_->GetStats();
1072 EXPECT_FALSE(stats.cpu_limited_resolution);
1073 EXPECT_TRUE(stats.bw_limited_resolution);
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));
kthelgason876222f2016-11-29 01:44:11 -08001081 sink_.WaitForEncodedFrame(4);
1082 stats = stats_proxy_->GetStats();
1083 EXPECT_FALSE(stats.cpu_limited_resolution);
1084 EXPECT_TRUE(stats.bw_limited_resolution);
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));
kthelgason876222f2016-11-29 01:44:11 -08001093 sink_.WaitForEncodedFrame(5);
1094 stats = stats_proxy_->GetStats();
1095 EXPECT_FALSE(stats.cpu_limited_resolution);
1096 EXPECT_FALSE(stats.bw_limited_resolution);
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));
1110 sink_.WaitForEncodedFrame(1);
1111 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));
1118 sink_.WaitForEncodedFrame(2);
1119 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));
1126 sink_.WaitForEncodedFrame(3);
1127 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));
1138 sink_.WaitForEncodedFrame(4);
1139 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));
sprang84a37592017-02-10 07:04:27 -08001154 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);
1157 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1158
asapersson02465b82017-04-10 01:12:52 -07001159 // Trigger CPU overuse, should now adapt down.
sprang84a37592017-02-10 07:04:27 -08001160 vie_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001161 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang84a37592017-02-10 07:04:27 -08001162 sink_.WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001163 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001164 EXPECT_TRUE(stats.cpu_limited_resolution);
1165 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1166
1167 // Set new source with adaptation still enabled.
1168 test::FrameForwarder new_video_source;
sprangc5d62e22017-04-02 23:53:04 -07001169 vie_encoder_->SetSource(
1170 &new_video_source,
1171 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001172
1173 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001174 CreateFrame(sequence, kWidth, kHeight));
sprang84a37592017-02-10 07:04:27 -08001175 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001176 stats = stats_proxy_->GetStats();
1177 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001178 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001179 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1180
sprangc5d62e22017-04-02 23:53:04 -07001181 // Set cpu adaptation by frame dropping.
perkj803d97f2016-11-01 11:45:46 -07001182 vie_encoder_->SetSource(
1183 &new_video_source,
1184 VideoSendStream::DegradationPreference::kMaintainResolution);
1185 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001186 CreateFrame(sequence, kWidth, kHeight));
sprang84a37592017-02-10 07:04:27 -08001187 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001188 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001189 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001190 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001191 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001192 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1193
sprangc5d62e22017-04-02 23:53:04 -07001194 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001195 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001196 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1197 mock_stats.input_frame_rate = 30;
1198 stats_proxy_->SetMockStats(mock_stats);
1199 vie_encoder_->TriggerCpuOveruse();
1200 stats_proxy_->ResetMockStats();
1201
1202 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001203 CreateFrame(sequence, kWidth, kHeight));
sprangc5d62e22017-04-02 23:53:04 -07001204 sink_.WaitForEncodedFrame(sequence++);
1205
1206 // Framerate now adapted.
1207 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001208 EXPECT_FALSE(stats.cpu_limited_resolution);
1209 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001210 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1211
1212 // Disable CPU adaptation.
1213 vie_encoder_->SetSource(
1214 &new_video_source,
1215 VideoSendStream::DegradationPreference::kDegradationDisabled);
1216 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001217 CreateFrame(sequence, kWidth, kHeight));
sprangc5d62e22017-04-02 23:53:04 -07001218 sink_.WaitForEncodedFrame(sequence++);
1219
1220 stats = stats_proxy_->GetStats();
1221 EXPECT_FALSE(stats.cpu_limited_resolution);
1222 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1223
1224 // Try to trigger overuse. Should not succeed.
1225 stats_proxy_->SetMockStats(mock_stats);
1226 vie_encoder_->TriggerCpuOveruse();
1227 stats_proxy_->ResetMockStats();
1228
1229 stats = stats_proxy_->GetStats();
1230 EXPECT_FALSE(stats.cpu_limited_resolution);
1231 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1232
1233 // Switch back the source with resolution adaptation enabled.
1234 vie_encoder_->SetSource(
1235 &video_source_,
1236 VideoSendStream::DegradationPreference::kMaintainFramerate);
asaperssonfab67072017-04-04 05:51:49 -07001237 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang84a37592017-02-10 07:04:27 -08001238 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001239 stats = stats_proxy_->GetStats();
1240 EXPECT_TRUE(stats.cpu_limited_resolution);
sprangc5d62e22017-04-02 23:53:04 -07001241 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001242
1243 // Trigger CPU normal usage.
1244 vie_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001245 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang84a37592017-02-10 07:04:27 -08001246 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001247 stats = stats_proxy_->GetStats();
1248 EXPECT_FALSE(stats.cpu_limited_resolution);
sprangc5d62e22017-04-02 23:53:04 -07001249 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1250
1251 // Back to the source with adaptation off, set it back to maintain-resolution.
1252 vie_encoder_->SetSource(
1253 &new_video_source,
1254 VideoSendStream::DegradationPreference::kMaintainResolution);
1255 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001256 CreateFrame(sequence, kWidth, kHeight));
sprangc5d62e22017-04-02 23:53:04 -07001257 sink_.WaitForEncodedFrame(sequence++);
1258 stats = stats_proxy_->GetStats();
1259 // Disabled, since we previously switched the source too disabled.
1260 EXPECT_FALSE(stats.cpu_limited_resolution);
1261 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1262
1263 // Trigger CPU normal usage.
1264 vie_encoder_->TriggerCpuNormalUsage();
1265 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001266 CreateFrame(sequence, kWidth, kHeight));
sprangc5d62e22017-04-02 23:53:04 -07001267 sink_.WaitForEncodedFrame(sequence++);
1268 stats = stats_proxy_->GetStats();
1269 EXPECT_FALSE(stats.cpu_limited_resolution);
1270 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001271 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001272
1273 vie_encoder_->Stop();
1274}
1275
Erik Språng08127a92016-11-16 16:41:30 +01001276TEST_F(ViEEncoderTest, StatsTracksPreferredBitrate) {
Erik Språng08127a92016-11-16 16:41:30 +01001277 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1278
asaperssonfab67072017-04-04 05:51:49 -07001279 const int kWidth = 1280;
1280 const int kHeight = 720;
1281 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
Erik Språng08127a92016-11-16 16:41:30 +01001282 sink_.WaitForEncodedFrame(1);
1283
1284 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1285 EXPECT_EQ(video_encoder_config_.max_bitrate_bps,
1286 stats.preferred_media_bitrate_bps);
1287
1288 vie_encoder_->Stop();
1289}
1290
kthelgason876222f2016-11-29 01:44:11 -08001291TEST_F(ViEEncoderTest, ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001292 const int kWidth = 1280;
1293 const int kHeight = 720;
kthelgason876222f2016-11-29 01:44:11 -08001294 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1295
asaperssonfab67072017-04-04 05:51:49 -07001296 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001297 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001298
asaperssonfab67072017-04-04 05:51:49 -07001299 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -08001300 sink_.WaitForEncodedFrame(1);
1301
asaperssonfab67072017-04-04 05:51:49 -07001302 // Trigger scale down.
kthelgason5e13d412016-12-01 03:59:51 -08001303 vie_encoder_->TriggerQualityLow();
1304
asaperssonfab67072017-04-04 05:51:49 -07001305 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
kthelgason5e13d412016-12-01 03:59:51 -08001306 sink_.WaitForEncodedFrame(2);
1307
kthelgason876222f2016-11-29 01:44:11 -08001308 // Expect a scale down.
1309 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001310 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001311
asapersson02465b82017-04-10 01:12:52 -07001312 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001313 test::FrameForwarder new_video_source;
1314 vie_encoder_->SetSource(
1315 &new_video_source,
1316 VideoSendStream::DegradationPreference::kMaintainResolution);
1317
asaperssonfab67072017-04-04 05:51:49 -07001318 // Trigger scale down.
kthelgason876222f2016-11-29 01:44:11 -08001319 vie_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001320 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
kthelgason5e13d412016-12-01 03:59:51 -08001321 sink_.WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001322
asaperssonfab67072017-04-04 05:51:49 -07001323 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001324 EXPECT_EQ(std::numeric_limits<int>::max(),
1325 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001326
asaperssonfab67072017-04-04 05:51:49 -07001327 // Trigger scale up.
kthelgason876222f2016-11-29 01:44:11 -08001328 vie_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001329 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
kthelgason5e13d412016-12-01 03:59:51 -08001330 sink_.WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001331
asapersson02465b82017-04-10 01:12:52 -07001332 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001333 EXPECT_EQ(std::numeric_limits<int>::max(),
1334 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001335
1336 vie_encoder_->Stop();
1337}
1338
asapersson02465b82017-04-10 01:12:52 -07001339TEST_F(ViEEncoderTest, SkipsSameAdaptDownRequest_MaintainFramerateMode) {
1340 const int kWidth = 1280;
1341 const int kHeight = 720;
1342 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1343
1344 // Enable kMaintainFramerate preference, no initial limitation.
1345 test::FrameForwarder source;
1346 vie_encoder_->SetSource(
1347 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1348
1349 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1350 sink_.WaitForEncodedFrame(1);
1351 VerifyNoLimitation(source.sink_wants());
1352 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1353 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1354
1355 // Trigger adapt down, expect scaled down resolution.
1356 vie_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001357 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001358 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1359 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1360 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1361
1362 // Trigger adapt down for same input resolution, expect no change.
1363 vie_encoder_->TriggerCpuOveruse();
1364 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1365 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1366 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1367
1368 vie_encoder_->Stop();
1369}
1370
1371TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_MaintainFramerateMode) {
1372 const int kWidth = 1280;
1373 const int kHeight = 720;
1374 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1375
1376 // Enable kMaintainFramerate preference, no initial limitation.
1377 test::FrameForwarder source;
1378 vie_encoder_->SetSource(
1379 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1380
1381 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1382 sink_.WaitForEncodedFrame(kWidth, kHeight);
1383 VerifyNoLimitation(source.sink_wants());
1384 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1385 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1386
1387 // Trigger adapt up, expect no change.
1388 vie_encoder_->TriggerCpuNormalUsage();
1389 VerifyNoLimitation(source.sink_wants());
1390 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1391 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1392
1393 vie_encoder_->Stop();
1394}
1395
1396TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_MaintainResolutionMode) {
1397 const int kWidth = 1280;
1398 const int kHeight = 720;
1399 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1400
1401 // Enable kMaintainResolution preference, no initial limitation.
1402 test::FrameForwarder source;
1403 vie_encoder_->SetSource(
1404 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
1405
1406 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1407 sink_.WaitForEncodedFrame(kWidth, kHeight);
1408 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001409 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001410 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1411
1412 // Trigger adapt up, expect no change.
1413 vie_encoder_->TriggerCpuNormalUsage();
1414 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001415 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001416 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1417
1418 vie_encoder_->Stop();
1419}
1420
asapersson09f05612017-05-15 23:40:18 -07001421TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
1422 const int kWidth = 1280;
1423 const int kHeight = 720;
1424 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1425
1426 // Enable kDegradationDisabled preference, no initial limitation.
1427 test::FrameForwarder source;
1428 vie_encoder_->SetSource(
1429 &source, VideoSendStream::DegradationPreference::kDegradationDisabled);
1430
1431 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1432 sink_.WaitForEncodedFrame(kWidth, kHeight);
1433 VerifyNoLimitation(source.sink_wants());
1434 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1435 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1436 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1437
1438 // Trigger adapt up, expect no change.
1439 vie_encoder_->TriggerQualityHigh();
1440 VerifyNoLimitation(source.sink_wants());
1441 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1442 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1443 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1444
1445 vie_encoder_->Stop();
1446}
1447
asapersson02465b82017-04-10 01:12:52 -07001448TEST_F(ViEEncoderTest, AdaptsResolutionForLowQuality_MaintainFramerateMode) {
1449 const int kWidth = 1280;
1450 const int kHeight = 720;
1451 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1452
1453 // Enable kMaintainFramerate preference, no initial limitation.
1454 AdaptingFrameForwarder source;
1455 source.set_adaptation_enabled(true);
1456 vie_encoder_->SetSource(
1457 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1458
1459 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1460 sink_.WaitForEncodedFrame(1);
1461 VerifyNoLimitation(source.sink_wants());
1462 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1463 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1464
1465 // Trigger adapt down, expect scaled down resolution.
1466 vie_encoder_->TriggerQualityLow();
1467 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1468 sink_.WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001469 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001470 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1471 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1472
1473 // Trigger adapt up, expect no restriction.
1474 vie_encoder_->TriggerQualityHigh();
1475 VerifyNoLimitation(source.sink_wants());
1476 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1477 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1478 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1479
1480 vie_encoder_->Stop();
1481}
1482
asapersson09f05612017-05-15 23:40:18 -07001483TEST_F(ViEEncoderTest, AdaptsFramerateForLowQuality_MaintainResolutionMode) {
1484 const int kWidth = 1280;
1485 const int kHeight = 720;
1486 const int kInputFps = 30;
1487 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1488
1489 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1490 stats.input_frame_rate = kInputFps;
1491 stats_proxy_->SetMockStats(stats);
1492
1493 // Expect no scaling to begin with (preference: kMaintainFramerate).
1494 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1495 sink_.WaitForEncodedFrame(1);
1496 VerifyNoLimitation(video_source_.sink_wants());
1497
1498 // Trigger adapt down, expect scaled down resolution.
1499 vie_encoder_->TriggerQualityLow();
1500 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1501 sink_.WaitForEncodedFrame(2);
1502 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1503
1504 // Enable kMaintainResolution preference.
1505 test::FrameForwarder new_video_source;
1506 vie_encoder_->SetSource(
1507 &new_video_source,
1508 VideoSendStream::DegradationPreference::kMaintainResolution);
1509 VerifyNoLimitation(new_video_source.sink_wants());
1510
1511 // Trigger adapt down, expect reduced framerate.
1512 vie_encoder_->TriggerQualityLow();
1513 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1514 sink_.WaitForEncodedFrame(3);
1515 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1516
1517 // Trigger adapt up, expect no restriction.
1518 vie_encoder_->TriggerQualityHigh();
1519 VerifyNoLimitation(new_video_source.sink_wants());
1520
1521 vie_encoder_->Stop();
1522}
1523
asaperssond0de2952017-04-21 01:47:31 -07001524TEST_F(ViEEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
1525 const int kWidth = 1280;
1526 const int kHeight = 720;
1527 const size_t kNumFrames = 10;
1528
kthelgason5e13d412016-12-01 03:59:51 -08001529 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1530
asaperssond0de2952017-04-21 01:47:31 -07001531 // Enable adapter, expected input resolutions when downscaling:
1532 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (min resolution limit)
1533 video_source_.set_adaptation_enabled(true);
1534
1535 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1536 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1537
1538 int downscales = 0;
1539 for (size_t i = 1; i <= kNumFrames; i++) {
1540 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
kthelgason5e13d412016-12-01 03:59:51 -08001541 sink_.WaitForEncodedFrame(i);
asaperssond0de2952017-04-21 01:47:31 -07001542
asaperssonfab67072017-04-04 05:51:49 -07001543 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001544 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
kthelgason5e13d412016-12-01 03:59:51 -08001545 vie_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001546 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001547
1548 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1549 ++downscales;
1550
1551 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1552 EXPECT_EQ(downscales,
1553 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1554 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001555 }
asaperssond0de2952017-04-21 01:47:31 -07001556 vie_encoder_->Stop();
1557}
1558
1559TEST_F(ViEEncoderTest,
1560 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1561 const int kWidth = 1280;
1562 const int kHeight = 720;
1563 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1564
1565 // Enable kMaintainFramerate preference, no initial limitation.
1566 AdaptingFrameForwarder source;
1567 source.set_adaptation_enabled(true);
1568 vie_encoder_->SetSource(
1569 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1570
1571 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
asapersson09f05612017-05-15 23:40:18 -07001572 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001573 VerifyNoLimitation(source.sink_wants());
1574 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1575 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1576
1577 // Trigger adapt down, expect scaled down resolution.
1578 vie_encoder_->TriggerCpuOveruse();
1579 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1580 sink_.WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001581 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001582 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1583 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1584
1585 // Trigger adapt up, expect no restriction.
1586 vie_encoder_->TriggerCpuNormalUsage();
1587 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
asapersson09f05612017-05-15 23:40:18 -07001588 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001589 VerifyNoLimitation(source.sink_wants());
1590 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1591 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1592
1593 // Trigger adapt down, expect scaled down resolution.
1594 vie_encoder_->TriggerCpuOveruse();
1595 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
1596 sink_.WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07001597 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001598 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1599 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1600
1601 // Trigger adapt up, expect no restriction.
1602 vie_encoder_->TriggerCpuNormalUsage();
asapersson09f05612017-05-15 23:40:18 -07001603 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1604 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001605 VerifyNoLimitation(source.sink_wants());
1606 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1607 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1608
1609 vie_encoder_->Stop();
1610}
1611
1612TEST_F(ViEEncoderTest,
1613 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
1614 const int kWidth = 1280;
1615 const int kHeight = 720;
1616 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1617
1618 // Enable kMaintainFramerate preference, no initial limitation.
1619 AdaptingFrameForwarder source;
1620 source.set_adaptation_enabled(true);
1621 vie_encoder_->SetSource(
1622 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1623
1624 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1625 sink_.WaitForEncodedFrame(kWidth, kHeight);
1626 VerifyNoLimitation(source.sink_wants());
1627 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1628 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1629 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1630 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1631
1632 // Trigger cpu adapt down, expect scaled down resolution (960x540).
1633 vie_encoder_->TriggerCpuOveruse();
1634 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1635 sink_.WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001636 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001637 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1638 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1639 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1640 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1641
1642 // Trigger cpu adapt down, expect scaled down resolution (640x360).
1643 vie_encoder_->TriggerCpuOveruse();
1644 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1645 sink_.WaitForEncodedFrame(3);
asapersson09f05612017-05-15 23:40:18 -07001646 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
1647 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07001648 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1649 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1650 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1651 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1652
1653 // Trigger cpu adapt down, max cpu downgrades reached, expect no change.
1654 vie_encoder_->TriggerCpuOveruse();
1655 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
1656 sink_.WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07001657 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07001658 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1659 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1660 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1661 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1662
1663 // Trigger quality adapt down, expect scaled down resolution (480x270).
1664 vie_encoder_->TriggerQualityLow();
1665 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1666 sink_.WaitForEncodedFrame(5);
asapersson09f05612017-05-15 23:40:18 -07001667 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001668 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1669 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1670 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1671 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1672
1673 // Trigger cpu adapt up, expect upscaled resolution (640x360).
1674 vie_encoder_->TriggerCpuNormalUsage();
1675 source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
1676 sink_.WaitForEncodedFrame(6);
asapersson09f05612017-05-15 23:40:18 -07001677 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001678 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1679 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1680 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1681 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1682
1683 // Trigger cpu adapt up, expect upscaled resolution (960x540).
1684 vie_encoder_->TriggerCpuNormalUsage();
1685 source.IncomingCapturedFrame(CreateFrame(7, kWidth, kHeight));
1686 sink_.WaitForEncodedFrame(7);
asapersson09f05612017-05-15 23:40:18 -07001687 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001688 last_wants = source.sink_wants();
1689 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1690 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1691 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1692 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1693
1694 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
1695 vie_encoder_->TriggerCpuNormalUsage();
1696 source.IncomingCapturedFrame(CreateFrame(8, kWidth, kHeight));
1697 sink_.WaitForEncodedFrame(8);
asapersson09f05612017-05-15 23:40:18 -07001698 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07001699 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1700 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1701 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1702 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1703
1704 // Trigger quality adapt up, expect no restriction (1280x720).
1705 vie_encoder_->TriggerQualityHigh();
1706 source.IncomingCapturedFrame(CreateFrame(9, kWidth, kHeight));
1707 sink_.WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07001708 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001709 VerifyNoLimitation(source.sink_wants());
1710 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1711 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1712 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1713 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08001714
1715 vie_encoder_->Stop();
1716}
1717
asaperssonf4e44af2017-04-19 02:01:06 -07001718TEST_F(ViEEncoderTest, CpuLimitedHistogramIsReported) {
perkj803d97f2016-11-01 11:45:46 -07001719 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001720 const int kWidth = 640;
1721 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07001722
1723 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07001724 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
perkj803d97f2016-11-01 11:45:46 -07001725 sink_.WaitForEncodedFrame(i);
1726 }
1727
1728 vie_encoder_->TriggerCpuOveruse();
1729 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07001730 video_source_.IncomingCapturedFrame(CreateFrame(
1731 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
perkj803d97f2016-11-01 11:45:46 -07001732 sink_.WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples +
1733 i);
1734 }
1735
1736 vie_encoder_->Stop();
sprangf8ee65e2017-02-28 08:49:33 -08001737 vie_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07001738 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08001739
perkj803d97f2016-11-01 11:45:46 -07001740 EXPECT_EQ(1,
1741 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
1742 EXPECT_EQ(
1743 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
1744}
1745
asaperssonf4e44af2017-04-19 02:01:06 -07001746TEST_F(ViEEncoderTest, CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
1747 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1748 const int kWidth = 640;
1749 const int kHeight = 360;
1750
1751 vie_encoder_->SetSource(
1752 &video_source_,
1753 VideoSendStream::DegradationPreference::kDegradationDisabled);
1754
1755 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
1756 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
1757 sink_.WaitForEncodedFrame(i);
1758 }
1759
1760 vie_encoder_->Stop();
1761 vie_encoder_.reset();
1762 stats_proxy_.reset();
1763
1764 EXPECT_EQ(0,
1765 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
1766}
1767
sprang57c2fff2017-01-16 06:24:02 -08001768TEST_F(ViEEncoderTest, CallsBitrateObserver) {
1769 class MockBitrateObserver : public VideoBitrateAllocationObserver {
1770 public:
1771 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const BitrateAllocation&));
1772 } bitrate_observer;
1773 vie_encoder_->SetBitrateObserver(&bitrate_observer);
1774
1775 const int kDefaultFps = 30;
1776 const BitrateAllocation expected_bitrate =
1777 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08001778 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08001779
1780 // First called on bitrate updated, then again on first frame.
1781 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
1782 .Times(2);
kthelgason2bc68642017-02-07 07:02:22 -08001783 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08001784
1785 const int64_t kStartTimeMs = 1;
1786 video_source_.IncomingCapturedFrame(
1787 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
1788 sink_.WaitForEncodedFrame(kStartTimeMs);
1789
1790 // Not called on second frame.
1791 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
1792 .Times(0);
1793 video_source_.IncomingCapturedFrame(
1794 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
1795 sink_.WaitForEncodedFrame(kStartTimeMs + 1);
1796
1797 // Called after a process interval.
1798 const int64_t kProcessIntervalMs =
1799 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
1800 // TODO(sprang): ViEEncoder should die and/or get injectable clock.
1801 // Sleep for one processing interval plus one frame to avoid flakiness.
1802 SleepMs(kProcessIntervalMs + 1000 / kDefaultFps);
1803 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
1804 .Times(1);
1805 video_source_.IncomingCapturedFrame(CreateFrame(
1806 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
1807 sink_.WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
1808
1809 vie_encoder_->Stop();
1810}
1811
kthelgason2bc68642017-02-07 07:02:22 -08001812TEST_F(ViEEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07001813 const int kTooLowBitrateForFrameSizeBps = 10000;
1814 vie_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
1815 const int kWidth = 640;
1816 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08001817
asaperssonfab67072017-04-04 05:51:49 -07001818 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08001819
1820 // Expect to drop this frame, the wait should time out.
1821 sink_.ExpectDroppedFrame();
1822
1823 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07001824 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08001825
sprangc5d62e22017-04-02 23:53:04 -07001826 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08001827
asaperssonfab67072017-04-04 05:51:49 -07001828 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08001829 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001830 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08001831
1832 // Expect to drop this frame, the wait should time out.
1833 sink_.ExpectDroppedFrame();
1834
sprangc5d62e22017-04-02 23:53:04 -07001835 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08001836
1837 vie_encoder_->Stop();
1838}
1839
asapersson09f05612017-05-15 23:40:18 -07001840TEST_F(ViEEncoderTest, NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07001841 const int kTooLowBitrateForFrameSizeBps = 10000;
1842 vie_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
1843 const int kWidth = 640;
1844 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08001845
1846 // We expect the n initial frames to get dropped.
1847 int i;
1848 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07001849 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08001850 sink_.ExpectDroppedFrame();
1851 }
1852 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07001853 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08001854 sink_.WaitForEncodedFrame(i);
1855
1856 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07001857 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08001858
1859 vie_encoder_->Stop();
1860}
1861
1862TEST_F(ViEEncoderTest, InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07001863 const int kWidth = 640;
1864 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08001865 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
1866
1867 // Set degradation preference.
1868 vie_encoder_->SetSource(
1869 &video_source_,
1870 VideoSendStream::DegradationPreference::kMaintainResolution);
1871
asaperssonfab67072017-04-04 05:51:49 -07001872 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08001873 // Frame should not be dropped, even if it's too large.
1874 sink_.WaitForEncodedFrame(1);
1875
1876 vie_encoder_->Stop();
1877}
1878
kthelgason2fc52542017-03-03 00:24:41 -08001879TEST_F(ViEEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07001880 const int kWidth = 640;
1881 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08001882 fake_encoder_.SetQualityScaling(false);
1883 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001884
kthelgasonb83797b2017-02-14 11:57:25 -08001885 // Force quality scaler reconfiguration by resetting the source.
1886 vie_encoder_->SetSource(&video_source_,
1887 VideoSendStream::DegradationPreference::kBalanced);
kthelgasonad9010c2017-02-14 00:46:51 -08001888
asaperssonfab67072017-04-04 05:51:49 -07001889 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08001890 // Frame should not be dropped, even if it's too large.
1891 sink_.WaitForEncodedFrame(1);
1892
1893 vie_encoder_->Stop();
1894 fake_encoder_.SetQualityScaling(true);
1895}
1896
asaperssond0de2952017-04-21 01:47:31 -07001897TEST_F(ViEEncoderTest,
1898 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
1899 const int kTooSmallWidth = 10;
1900 const int kTooSmallHeight = 10;
1901 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1902
1903 // Enable kMaintainFramerate preference, no initial limitation.
1904 test::FrameForwarder source;
1905 vie_encoder_->SetSource(
1906 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1907 VerifyNoLimitation(source.sink_wants());
1908 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1909
1910 // Trigger adapt down, too small frame, expect no change.
1911 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
1912 sink_.WaitForEncodedFrame(1);
1913 vie_encoder_->TriggerCpuOveruse();
1914 VerifyNoLimitation(source.sink_wants());
1915 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1916 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1917
1918 vie_encoder_->Stop();
1919}
1920
asapersson02465b82017-04-10 01:12:52 -07001921TEST_F(ViEEncoderTest, FailingInitEncodeDoesntCauseCrash) {
1922 fake_encoder_.ForceInitEncodeFailure(true);
1923 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1924 ResetEncoder("VP8", 2, 1, true);
1925 const int kFrameWidth = 1280;
1926 const int kFrameHeight = 720;
1927 video_source_.IncomingCapturedFrame(
1928 CreateFrame(1, kFrameWidth, kFrameHeight));
1929 sink_.ExpectDroppedFrame();
1930 vie_encoder_->Stop();
1931}
1932
sprangb1ca0732017-02-01 08:38:12 -08001933// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
asaperssond0de2952017-04-21 01:47:31 -07001934TEST_F(ViEEncoderTest, AdaptsResolutionOnOveruse_MaintainFramerateMode) {
sprangb1ca0732017-02-01 08:38:12 -08001935 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1936
1937 const int kFrameWidth = 1280;
1938 const int kFrameHeight = 720;
1939 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
1940 // requested by ViEEncoder::VideoSourceProxy::RequestResolutionLowerThan().
1941 video_source_.set_adaptation_enabled(true);
1942
1943 video_source_.IncomingCapturedFrame(
1944 CreateFrame(1, kFrameWidth, kFrameHeight));
1945 sink_.WaitForEncodedFrame(kFrameWidth, kFrameHeight);
1946
1947 // Trigger CPU overuse, downscale by 3/4.
1948 vie_encoder_->TriggerCpuOveruse();
1949 video_source_.IncomingCapturedFrame(
1950 CreateFrame(2, kFrameWidth, kFrameHeight));
1951 sink_.WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
1952
asaperssonfab67072017-04-04 05:51:49 -07001953 // Trigger CPU normal use, return to original resolution.
sprangb1ca0732017-02-01 08:38:12 -08001954 vie_encoder_->TriggerCpuNormalUsage();
1955 video_source_.IncomingCapturedFrame(
1956 CreateFrame(3, kFrameWidth, kFrameHeight));
1957 sink_.WaitForEncodedFrame(kFrameWidth, kFrameHeight);
1958
1959 vie_encoder_->Stop();
1960}
sprangfe627f32017-03-29 08:24:59 -07001961
asapersson02465b82017-04-10 01:12:52 -07001962TEST_F(ViEEncoderTest, AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07001963 const int kDefaultFramerateFps = 30;
1964 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kDefaultFramerateFps;
1965 const int kFrameWidth = 1280;
1966 const int kFrameHeight = 720;
1967 rtc::ScopedFakeClock fake_clock;
1968
1969 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1970 vie_encoder_->SetSource(
1971 &video_source_,
1972 VideoSendStream::DegradationPreference::kMaintainResolution);
1973 video_source_.set_adaptation_enabled(true);
1974
1975 fake_clock.SetTimeMicros(kFrameIntervalMs * 1000);
1976 int64_t timestamp_ms = kFrameIntervalMs;
1977
1978 video_source_.IncomingCapturedFrame(
1979 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1980 sink_.WaitForEncodedFrame(timestamp_ms);
1981
1982 // Try to trigger overuse. No fps estimate available => no effect.
1983 vie_encoder_->TriggerCpuOveruse();
1984
1985 // Insert frames for one second to get a stable estimate.
1986 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1987 timestamp_ms += kFrameIntervalMs;
1988 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1989 video_source_.IncomingCapturedFrame(
1990 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1991 sink_.WaitForEncodedFrame(timestamp_ms);
1992 }
1993
1994 // Trigger CPU overuse, reduce framerate by 2/3.
1995 vie_encoder_->TriggerCpuOveruse();
1996 int num_frames_dropped = 0;
1997 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1998 timestamp_ms += kFrameIntervalMs;
1999 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
2000 video_source_.IncomingCapturedFrame(
2001 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
2002 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
2003 ++num_frames_dropped;
2004 } else {
2005 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2006 }
2007 }
2008
2009 // TODO(sprang): Find where there's rounding errors or stuff causing the
2010 // margin here to be a little larger than we'd like (input fps estimate is
2011 // off) and the frame dropping is a little too aggressive.
2012 const int kErrorMargin = 5;
2013 EXPECT_NEAR(num_frames_dropped,
2014 kDefaultFramerateFps - (kDefaultFramerateFps * 2 / 3),
2015 kErrorMargin);
2016
2017 // Trigger CPU overuse, reduce framerate by 2/3 again.
2018 vie_encoder_->TriggerCpuOveruse();
2019 num_frames_dropped = 0;
2020 for (int i = 0; i < kDefaultFramerateFps; ++i) {
2021 timestamp_ms += kFrameIntervalMs;
2022 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
2023 video_source_.IncomingCapturedFrame(
2024 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
2025 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
2026 ++num_frames_dropped;
2027 } else {
2028 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2029 }
2030 }
2031 EXPECT_NEAR(num_frames_dropped,
2032 kDefaultFramerateFps - (kDefaultFramerateFps * 4 / 9),
2033 kErrorMargin);
2034
2035 // Go back up one step.
2036 vie_encoder_->TriggerCpuNormalUsage();
2037 num_frames_dropped = 0;
2038 for (int i = 0; i < kDefaultFramerateFps; ++i) {
2039 timestamp_ms += kFrameIntervalMs;
2040 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
2041 video_source_.IncomingCapturedFrame(
2042 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
2043 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
2044 ++num_frames_dropped;
2045 } else {
2046 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2047 }
2048 }
2049 EXPECT_NEAR(num_frames_dropped,
2050 kDefaultFramerateFps - (kDefaultFramerateFps * 2 / 3),
2051 kErrorMargin);
2052
2053 // Go back up to original mode.
2054 vie_encoder_->TriggerCpuNormalUsage();
2055 num_frames_dropped = 0;
2056 for (int i = 0; i < kDefaultFramerateFps; ++i) {
2057 timestamp_ms += kFrameIntervalMs;
2058 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
2059 video_source_.IncomingCapturedFrame(
2060 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
2061 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
2062 ++num_frames_dropped;
2063 } else {
2064 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2065 }
2066 }
2067 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2068
2069 vie_encoder_->Stop();
2070}
2071
2072TEST_F(ViEEncoderTest, DoesntAdaptDownPastMinFramerate) {
2073 const int kFramerateFps = 5;
2074 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
2075 const int kMinFpsFrameInterval = rtc::kNumMillisecsPerSec / kMinFramerateFps;
2076 const int kFrameWidth = 1280;
2077 const int kFrameHeight = 720;
2078
2079 rtc::ScopedFakeClock fake_clock;
2080 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2081 vie_encoder_->SetSource(
2082 &video_source_,
2083 VideoSendStream::DegradationPreference::kMaintainResolution);
2084 video_source_.set_adaptation_enabled(true);
2085
2086 fake_clock.SetTimeMicros(kFrameIntervalMs * 1000);
2087 int64_t timestamp_ms = kFrameIntervalMs;
2088
2089 // Trigger overuse as much as we can.
2090 for (int i = 0; i < ViEEncoder::kMaxCpuResolutionDowngrades; ++i) {
2091 // Insert frames to get a new fps estimate...
2092 for (int j = 0; j < kFramerateFps; ++j) {
2093 video_source_.IncomingCapturedFrame(
2094 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
2095 timestamp_ms += kFrameIntervalMs;
2096 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
2097 }
2098 // ...and then try to adapt again.
2099 vie_encoder_->TriggerCpuOveruse();
2100 }
2101
2102 // Drain any frame in the pipeline.
2103 sink_.WaitForFrame(kDefaultTimeoutMs);
2104
2105 // Insert frames at min fps, all should go through.
2106 for (int i = 0; i < 10; ++i) {
2107 timestamp_ms += kMinFpsFrameInterval;
2108 fake_clock.AdvanceTimeMicros(kMinFpsFrameInterval * 1000);
2109 video_source_.IncomingCapturedFrame(
2110 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
2111 sink_.WaitForEncodedFrame(timestamp_ms);
2112 }
2113 vie_encoder_->Stop();
2114}
perkj26091b12016-09-01 01:17:40 -07002115} // namespace webrtc