blob: d2f46e68059781aa3deea36ff94395649607fd13 [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
142 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
143 int cropped_width = 0;
144 int cropped_height = 0;
145 int out_width = 0;
146 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700147 if (adaption_enabled()) {
148 if (adapter_.AdaptFrameResolution(
149 video_frame.width(), video_frame.height(),
150 video_frame.timestamp_us() * 1000, &cropped_width,
151 &cropped_height, &out_width, &out_height)) {
152 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
153 nullptr, out_width, out_height),
154 99, 99, kVideoRotation_0);
155 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
156 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
157 }
sprangb1ca0732017-02-01 08:38:12 -0800158 } else {
159 test::FrameForwarder::IncomingCapturedFrame(video_frame);
160 }
161 }
162
163 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
164 const rtc::VideoSinkWants& wants) override {
165 rtc::CritScope cs(&crit_);
sprangc5d62e22017-04-02 23:53:04 -0700166 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
167 wants.max_pixel_count,
168 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800169 test::FrameForwarder::AddOrUpdateSink(sink, wants);
170 }
171
172 cricket::VideoAdapter adapter_;
173 bool adaptation_enabled_ GUARDED_BY(crit_);
174};
sprangc5d62e22017-04-02 23:53:04 -0700175
176class MockableSendStatisticsProxy : public SendStatisticsProxy {
177 public:
178 MockableSendStatisticsProxy(Clock* clock,
179 const VideoSendStream::Config& config,
180 VideoEncoderConfig::ContentType content_type)
181 : SendStatisticsProxy(clock, config, content_type) {}
182
183 VideoSendStream::Stats GetStats() override {
184 rtc::CritScope cs(&lock_);
185 if (mock_stats_)
186 return *mock_stats_;
187 return SendStatisticsProxy::GetStats();
188 }
189
190 void SetMockStats(const VideoSendStream::Stats& stats) {
191 rtc::CritScope cs(&lock_);
192 mock_stats_.emplace(stats);
193 }
194
195 void ResetMockStats() {
196 rtc::CritScope cs(&lock_);
197 mock_stats_.reset();
198 }
199
200 private:
201 rtc::CriticalSection lock_;
202 rtc::Optional<VideoSendStream::Stats> mock_stats_ GUARDED_BY(lock_);
203};
204
perkj803d97f2016-11-01 11:45:46 -0700205} // namespace
206
perkj26091b12016-09-01 01:17:40 -0700207class ViEEncoderTest : public ::testing::Test {
208 public:
209 static const int kDefaultTimeoutMs = 30 * 1000;
210
211 ViEEncoderTest()
212 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700213 codec_width_(320),
214 codec_height_(240),
perkj26091b12016-09-01 01:17:40 -0700215 fake_encoder_(),
sprangc5d62e22017-04-02 23:53:04 -0700216 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700217 Clock::GetRealTimeClock(),
218 video_send_config_,
219 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700220 sink_(&fake_encoder_) {}
221
222 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700223 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700224 video_send_config_ = VideoSendStream::Config(nullptr);
225 video_send_config_.encoder_settings.encoder = &fake_encoder_;
226 video_send_config_.encoder_settings.payload_name = "FAKE";
227 video_send_config_.encoder_settings.payload_type = 125;
228
Per512ecb32016-09-23 15:52:06 +0200229 VideoEncoderConfig video_encoder_config;
perkjfa10b552016-10-02 23:45:26 -0700230 test::FillEncoderConfiguration(1, &video_encoder_config);
Erik Språng08127a92016-11-16 16:41:30 +0100231 video_encoder_config_ = video_encoder_config.Copy();
asapersson5f7226f2016-11-25 04:37:00 -0800232 ConfigureEncoder(std::move(video_encoder_config), true /* nack_enabled */);
233 }
234
235 void ConfigureEncoder(VideoEncoderConfig video_encoder_config,
236 bool nack_enabled) {
237 if (vie_encoder_)
238 vie_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700239 vie_encoder_.reset(new ViEEncoderUnderTest(
240 stats_proxy_.get(), video_send_config_.encoder_settings));
241 vie_encoder_->SetSink(&sink_, false /* rotation_applied */);
sprangc5d62e22017-04-02 23:53:04 -0700242 vie_encoder_->SetSource(
243 &video_source_,
244 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason2bc68642017-02-07 07:02:22 -0800245 vie_encoder_->SetStartBitrate(kTargetBitrateBps);
asapersson5f7226f2016-11-25 04:37:00 -0800246 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
247 kMaxPayloadLength, nack_enabled);
kthelgason2fc52542017-03-03 00:24:41 -0800248 vie_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800249 }
250
251 void ResetEncoder(const std::string& payload_name,
252 size_t num_streams,
253 size_t num_temporal_layers,
254 bool nack_enabled) {
255 video_send_config_.encoder_settings.payload_name = payload_name;
256
257 VideoEncoderConfig video_encoder_config;
258 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800259 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800260 video_encoder_config.video_stream_factory =
261 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers);
262 ConfigureEncoder(std::move(video_encoder_config), nack_enabled);
perkj26091b12016-09-01 01:17:40 -0700263 }
264
sprang57c2fff2017-01-16 06:24:02 -0800265 VideoFrame CreateFrame(int64_t ntp_time_ms,
266 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200267 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
268 destruction_event, codec_width_, codec_height_),
269 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800270 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700271 return frame;
272 }
273
sprang57c2fff2017-01-16 06:24:02 -0800274 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700275 VideoFrame frame(
276 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
277 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800278 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700279 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700280 return frame;
281 }
282
asapersson02465b82017-04-10 01:12:52 -0700283 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
284 EXPECT_FALSE(wants.target_pixel_count);
285 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
286 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
287 }
288
289 void VerifyResolutionLimitationLessThan(const rtc::VideoSinkWants& wants,
290 int pixel_count) {
291 EXPECT_LT(wants.max_pixel_count, pixel_count);
292 EXPECT_GT(wants.max_pixel_count, 0);
293 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
294 }
295
perkj26091b12016-09-01 01:17:40 -0700296 class TestEncoder : public test::FakeEncoder {
297 public:
298 TestEncoder()
299 : FakeEncoder(Clock::GetRealTimeClock()),
300 continue_encode_event_(false, false) {}
301
asaperssonfab67072017-04-04 05:51:49 -0700302 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800303 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700304 return config_;
305 }
306
307 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800308 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700309 block_next_encode_ = true;
310 }
311
kthelgason876222f2016-11-29 01:44:11 -0800312 VideoEncoder::ScalingSettings GetScalingSettings() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800313 rtc::CritScope lock(&local_crit_sect_);
kthelgasonad9010c2017-02-14 00:46:51 -0800314 if (quality_scaling_)
315 return VideoEncoder::ScalingSettings(true, 1, 2);
316 return VideoEncoder::ScalingSettings(false);
kthelgason876222f2016-11-29 01:44:11 -0800317 }
318
perkjfa10b552016-10-02 23:45:26 -0700319 void ContinueEncode() { continue_encode_event_.Set(); }
320
321 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
322 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800323 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700324 EXPECT_EQ(timestamp_, timestamp);
325 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
326 }
327
kthelgason2fc52542017-03-03 00:24:41 -0800328 void SetQualityScaling(bool b) {
329 rtc::CritScope lock(&local_crit_sect_);
330 quality_scaling_ = b;
331 }
kthelgasonad9010c2017-02-14 00:46:51 -0800332
sprangfe627f32017-03-29 08:24:59 -0700333 void ForceInitEncodeFailure(bool force_failure) {
334 rtc::CritScope lock(&local_crit_sect_);
335 force_init_encode_failed_ = force_failure;
336 }
337
perkjfa10b552016-10-02 23:45:26 -0700338 private:
perkj26091b12016-09-01 01:17:40 -0700339 int32_t Encode(const VideoFrame& input_image,
340 const CodecSpecificInfo* codec_specific_info,
341 const std::vector<FrameType>* frame_types) override {
342 bool block_encode;
343 {
brandtre78d2662017-01-16 05:57:16 -0800344 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700345 EXPECT_GT(input_image.timestamp(), timestamp_);
346 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
347 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
348
349 timestamp_ = input_image.timestamp();
350 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700351 last_input_width_ = input_image.width();
352 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700353 block_encode = block_next_encode_;
354 block_next_encode_ = false;
355 }
356 int32_t result =
357 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
358 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700359 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700360 return result;
361 }
362
sprangfe627f32017-03-29 08:24:59 -0700363 int32_t InitEncode(const VideoCodec* config,
364 int32_t number_of_cores,
365 size_t max_payload_size) override {
366 int res =
367 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
368 rtc::CritScope lock(&local_crit_sect_);
369 if (config->codecType == kVideoCodecVP8 && config->VP8().tl_factory) {
370 // Simulate setting up temporal layers, in order to validate the life
371 // cycle of these objects.
372 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
373 int num_temporal_layers =
374 std::max<int>(1, config->VP8().numberOfTemporalLayers);
375 for (int i = 0; i < num_streams; ++i) {
376 allocated_temporal_layers_.emplace_back(
377 config->VP8().tl_factory->Create(i, num_temporal_layers, 42));
378 }
379 }
380 if (force_init_encode_failed_)
381 return -1;
382 return res;
383 }
384
brandtre78d2662017-01-16 05:57:16 -0800385 rtc::CriticalSection local_crit_sect_;
sprangfe627f32017-03-29 08:24:59 -0700386 bool block_next_encode_ GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700387 rtc::Event continue_encode_event_;
sprangfe627f32017-03-29 08:24:59 -0700388 uint32_t timestamp_ GUARDED_BY(local_crit_sect_) = 0;
389 int64_t ntp_time_ms_ GUARDED_BY(local_crit_sect_) = 0;
390 int last_input_width_ GUARDED_BY(local_crit_sect_) = 0;
391 int last_input_height_ GUARDED_BY(local_crit_sect_) = 0;
392 bool quality_scaling_ GUARDED_BY(local_crit_sect_) = true;
393 std::vector<std::unique_ptr<TemporalLayers>> allocated_temporal_layers_
394 GUARDED_BY(local_crit_sect_);
395 bool force_init_encode_failed_ GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700396 };
397
Per512ecb32016-09-23 15:52:06 +0200398 class TestSink : public ViEEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700399 public:
400 explicit TestSink(TestEncoder* test_encoder)
401 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
402
perkj26091b12016-09-01 01:17:40 -0700403 void WaitForEncodedFrame(int64_t expected_ntp_time) {
404 uint32_t timestamp = 0;
perkja49cbd32016-09-16 07:53:41 -0700405 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700406 {
407 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800408 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700409 }
410 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
411 }
412
sprangb1ca0732017-02-01 08:38:12 -0800413 void WaitForEncodedFrame(uint32_t expected_width,
414 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700415 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
416 CheckLastFrameSizeMathces(expected_width, expected_height);
417 }
418
419 void CheckLastFrameSizeMathces(uint32_t expected_width,
420 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800421 uint32_t width = 0;
422 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800423 {
424 rtc::CritScope lock(&crit_);
425 width = last_width_;
426 height = last_height_;
427 }
428 EXPECT_EQ(expected_height, height);
429 EXPECT_EQ(expected_width, width);
430 }
431
kthelgason2fc52542017-03-03 00:24:41 -0800432 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800433
sprangc5d62e22017-04-02 23:53:04 -0700434 bool WaitForFrame(int64_t timeout_ms) {
435 return encoded_frame_event_.Wait(timeout_ms);
436 }
437
perkj26091b12016-09-01 01:17:40 -0700438 void SetExpectNoFrames() {
439 rtc::CritScope lock(&crit_);
440 expect_frames_ = false;
441 }
442
asaperssonfab67072017-04-04 05:51:49 -0700443 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200444 rtc::CritScope lock(&crit_);
445 return number_of_reconfigurations_;
446 }
447
asaperssonfab67072017-04-04 05:51:49 -0700448 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200449 rtc::CritScope lock(&crit_);
450 return min_transmit_bitrate_bps_;
451 }
452
perkj26091b12016-09-01 01:17:40 -0700453 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700454 Result OnEncodedImage(
455 const EncodedImage& encoded_image,
456 const CodecSpecificInfo* codec_specific_info,
457 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200458 rtc::CritScope lock(&crit_);
459 EXPECT_TRUE(expect_frames_);
sprangb1ca0732017-02-01 08:38:12 -0800460 last_timestamp_ = encoded_image._timeStamp;
461 last_width_ = encoded_image._encodedWidth;
462 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200463 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800464 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200465 }
466
467 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
468 int min_transmit_bitrate_bps) override {
469 rtc::CriticalSection crit_;
470 ++number_of_reconfigurations_;
471 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
472 }
473
perkj26091b12016-09-01 01:17:40 -0700474 rtc::CriticalSection crit_;
475 TestEncoder* test_encoder_;
476 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800477 uint32_t last_timestamp_ = 0;
478 uint32_t last_height_ = 0;
479 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700480 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200481 int number_of_reconfigurations_ = 0;
482 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700483 };
484
485 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100486 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200487 int codec_width_;
488 int codec_height_;
perkj26091b12016-09-01 01:17:40 -0700489 TestEncoder fake_encoder_;
sprangc5d62e22017-04-02 23:53:04 -0700490 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700491 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800492 AdaptingFrameForwarder video_source_;
perkj803d97f2016-11-01 11:45:46 -0700493 std::unique_ptr<ViEEncoderUnderTest> vie_encoder_;
perkj26091b12016-09-01 01:17:40 -0700494};
495
496TEST_F(ViEEncoderTest, EncodeOneFrame) {
perkj26091b12016-09-01 01:17:40 -0700497 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
498 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700499 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
perkj26091b12016-09-01 01:17:40 -0700500 sink_.WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700501 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700502 vie_encoder_->Stop();
503}
504
505TEST_F(ViEEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
506 // Dropped since no target bitrate has been set.
507 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700508 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
509 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700510
perkj26091b12016-09-01 01:17:40 -0700511 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
512
perkja49cbd32016-09-16 07:53:41 -0700513 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkj26091b12016-09-01 01:17:40 -0700514 sink_.WaitForEncodedFrame(2);
515 vie_encoder_->Stop();
516}
517
518TEST_F(ViEEncoderTest, DropsFramesWhenRateSetToZero) {
perkj26091b12016-09-01 01:17:40 -0700519 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700520 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700521 sink_.WaitForEncodedFrame(1);
522
523 vie_encoder_->OnBitrateUpdated(0, 0, 0);
524 // Dropped since bitrate is zero.
perkja49cbd32016-09-16 07:53:41 -0700525 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkj26091b12016-09-01 01:17:40 -0700526
527 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700528 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700529 sink_.WaitForEncodedFrame(3);
530 vie_encoder_->Stop();
531}
532
533TEST_F(ViEEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
perkj26091b12016-09-01 01:17:40 -0700534 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700535 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700536 sink_.WaitForEncodedFrame(1);
537
538 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700539 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700540
perkja49cbd32016-09-16 07:53:41 -0700541 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkj26091b12016-09-01 01:17:40 -0700542 sink_.WaitForEncodedFrame(2);
543 vie_encoder_->Stop();
544}
545
546TEST_F(ViEEncoderTest, DropsFrameAfterStop) {
perkj26091b12016-09-01 01:17:40 -0700547 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
548
perkja49cbd32016-09-16 07:53:41 -0700549 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700550 sink_.WaitForEncodedFrame(1);
551
552 vie_encoder_->Stop();
553 sink_.SetExpectNoFrames();
554 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700555 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
556 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700557}
558
559TEST_F(ViEEncoderTest, DropsPendingFramesOnSlowEncode) {
perkj26091b12016-09-01 01:17:40 -0700560 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
561
562 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700563 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700564 sink_.WaitForEncodedFrame(1);
565 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
566 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700567 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
568 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700569 fake_encoder_.ContinueEncode();
570 sink_.WaitForEncodedFrame(3);
571
572 vie_encoder_->Stop();
573}
574
Per512ecb32016-09-23 15:52:06 +0200575TEST_F(ViEEncoderTest, ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
Per512ecb32016-09-23 15:52:06 +0200576 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100577 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200578
579 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200580 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
Per512ecb32016-09-23 15:52:06 +0200581 sink_.WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100582 // The encoder will have been configured once when the first frame is
583 // received.
584 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200585
586 VideoEncoderConfig video_encoder_config;
perkjfa10b552016-10-02 23:45:26 -0700587 test::FillEncoderConfiguration(1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200588 video_encoder_config.min_transmit_bitrate_bps = 9999;
asapersson5f7226f2016-11-25 04:37:00 -0800589 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
590 kMaxPayloadLength, true /* nack_enabled */);
Per512ecb32016-09-23 15:52:06 +0200591
592 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200593 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Per512ecb32016-09-23 15:52:06 +0200594 sink_.WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100595 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700596 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700597
598 vie_encoder_->Stop();
599}
600
perkjfa10b552016-10-02 23:45:26 -0700601TEST_F(ViEEncoderTest, FrameResolutionChangeReconfigureEncoder) {
perkjfa10b552016-10-02 23:45:26 -0700602 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
603
604 // Capture a frame and wait for it to synchronize with the encoder thread.
605 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
606 sink_.WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100607 // The encoder will have been configured once.
608 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700609 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
610 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
611
612 codec_width_ *= 2;
613 codec_height_ *= 2;
614 // Capture a frame with a higher resolution and wait for it to synchronize
615 // with the encoder thread.
616 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
617 sink_.WaitForEncodedFrame(2);
618 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
619 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100620 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700621
622 vie_encoder_->Stop();
623}
624
asapersson5f7226f2016-11-25 04:37:00 -0800625TEST_F(ViEEncoderTest, Vp8ResilienceIsOffFor1S1TLWithNackEnabled) {
626 const bool kNackEnabled = true;
627 const size_t kNumStreams = 1;
628 const size_t kNumTl = 1;
asaperssona90799d2016-12-09 02:35:20 -0800629 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800630 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
631
632 // Capture a frame and wait for it to synchronize with the encoder thread.
633 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
634 sink_.WaitForEncodedFrame(1);
635 // The encoder have been configured once when the first frame is received.
636 EXPECT_EQ(1, sink_.number_of_reconfigurations());
637 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
638 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
639 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
640 // Resilience is off for no temporal layers with nack on.
641 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
642 vie_encoder_->Stop();
643}
644
645TEST_F(ViEEncoderTest, Vp8ResilienceIsOffFor2S1TlWithNackEnabled) {
646 const bool kNackEnabled = true;
647 const size_t kNumStreams = 2;
648 const size_t kNumTl = 1;
asaperssona90799d2016-12-09 02:35:20 -0800649 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800650 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
651
652 // Capture a frame and wait for it to synchronize with the encoder thread.
653 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
654 sink_.WaitForEncodedFrame(1);
655 // The encoder have been configured once when the first frame is received.
656 EXPECT_EQ(1, sink_.number_of_reconfigurations());
657 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
658 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
659 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
660 // Resilience is off for no temporal layers and >1 streams with nack on.
661 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
662 vie_encoder_->Stop();
663}
664
665TEST_F(ViEEncoderTest, Vp8ResilienceIsOnFor1S1TLWithNackDisabled) {
666 const bool kNackEnabled = false;
667 const size_t kNumStreams = 1;
668 const size_t kNumTl = 1;
asaperssona90799d2016-12-09 02:35:20 -0800669 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800670 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
671
672 // Capture a frame and wait for it to synchronize with the encoder thread.
673 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
674 sink_.WaitForEncodedFrame(1);
675 // The encoder have been configured once when the first frame is received.
676 EXPECT_EQ(1, sink_.number_of_reconfigurations());
677 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
678 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
679 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
680 // Resilience is on for no temporal layers with nack off.
681 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
682 vie_encoder_->Stop();
683}
684
685TEST_F(ViEEncoderTest, Vp8ResilienceIsOnFor1S2TlWithNackEnabled) {
686 const bool kNackEnabled = true;
687 const size_t kNumStreams = 1;
688 const size_t kNumTl = 2;
asaperssona90799d2016-12-09 02:35:20 -0800689 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800690 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
691
692 // Capture a frame and wait for it to synchronize with the encoder thread.
693 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
694 sink_.WaitForEncodedFrame(1);
695 // The encoder have been configured once when the first frame is received.
696 EXPECT_EQ(1, sink_.number_of_reconfigurations());
697 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
698 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
699 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
700 // Resilience is on for temporal layers.
701 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
702 vie_encoder_->Stop();
703}
704
perkj803d97f2016-11-01 11:45:46 -0700705TEST_F(ViEEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
706 EXPECT_TRUE(video_source_.has_sinks());
707 test::FrameForwarder new_video_source;
sprangc5d62e22017-04-02 23:53:04 -0700708 vie_encoder_->SetSource(
709 &new_video_source,
710 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -0700711 EXPECT_FALSE(video_source_.has_sinks());
712 EXPECT_TRUE(new_video_source.has_sinks());
713
714 vie_encoder_->Stop();
715}
716
717TEST_F(ViEEncoderTest, SinkWantsRotationApplied) {
718 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
719 vie_encoder_->SetSink(&sink_, true /*rotation_applied*/);
720 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
721 vie_encoder_->Stop();
722}
723
724TEST_F(ViEEncoderTest, SinkWantsFromOveruseDetector) {
asaperssond0de2952017-04-21 01:47:31 -0700725 const int kMaxDowngrades = ViEEncoder::kMaxCpuResolutionDowngrades;
perkj803d97f2016-11-01 11:45:46 -0700726 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
727
asapersson02465b82017-04-10 01:12:52 -0700728 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700729
730 int frame_width = 1280;
731 int frame_height = 720;
732
733 // Trigger CPU overuse kMaxCpuDowngrades times. Every time, ViEEncoder should
734 // request lower resolution.
asaperssond0de2952017-04-21 01:47:31 -0700735 for (int i = 1; i <= kMaxDowngrades; ++i) {
perkj803d97f2016-11-01 11:45:46 -0700736 video_source_.IncomingCapturedFrame(
737 CreateFrame(i, frame_width, frame_height));
738 sink_.WaitForEncodedFrame(i);
739
740 vie_encoder_->TriggerCpuOveruse();
741
sprang84a37592017-02-10 07:04:27 -0800742 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700743 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
perkj803d97f2016-11-01 11:45:46 -0700744 frame_width * frame_height);
asaperssond0de2952017-04-21 01:47:31 -0700745 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
746 EXPECT_EQ(i, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -0700747
748 frame_width /= 2;
749 frame_height /= 2;
750 }
751
kthelgason876222f2016-11-29 01:44:11 -0800752 // Trigger CPU overuse one more time. This should not trigger a request for
perkj803d97f2016-11-01 11:45:46 -0700753 // lower resolution.
754 rtc::VideoSinkWants current_wants = video_source_.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -0700755 video_source_.IncomingCapturedFrame(
756 CreateFrame(kMaxDowngrades + 1, frame_width, frame_height));
757 sink_.WaitForEncodedFrame(kMaxDowngrades + 1);
perkj803d97f2016-11-01 11:45:46 -0700758 vie_encoder_->TriggerCpuOveruse();
sprang84a37592017-02-10 07:04:27 -0800759 EXPECT_EQ(video_source_.sink_wants().target_pixel_count,
760 current_wants.target_pixel_count);
perkj803d97f2016-11-01 11:45:46 -0700761 EXPECT_EQ(video_source_.sink_wants().max_pixel_count,
762 current_wants.max_pixel_count);
asaperssond0de2952017-04-21 01:47:31 -0700763 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
764 EXPECT_EQ(kMaxDowngrades,
765 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -0700766
767 // Trigger CPU normal use.
768 vie_encoder_->TriggerCpuNormalUsage();
sprang84a37592017-02-10 07:04:27 -0800769 EXPECT_EQ(frame_width * frame_height * 5 / 3,
770 video_source_.sink_wants().target_pixel_count.value_or(0));
771 EXPECT_EQ(frame_width * frame_height * 4,
sprangc5d62e22017-04-02 23:53:04 -0700772 video_source_.sink_wants().max_pixel_count);
asaperssond0de2952017-04-21 01:47:31 -0700773 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
774 EXPECT_EQ(kMaxDowngrades + 1,
775 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -0700776
777 vie_encoder_->Stop();
778}
779
sprangc5d62e22017-04-02 23:53:04 -0700780TEST_F(ViEEncoderTest, SinkWantsStoredByDegradationPreference) {
perkj803d97f2016-11-01 11:45:46 -0700781 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -0700782 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700783
sprangc5d62e22017-04-02 23:53:04 -0700784 const int kFrameWidth = 1280;
785 const int kFrameHeight = 720;
786 const int kFrameIntervalMs = 1000 / 30;
787
788 int frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -0700789
kthelgason5e13d412016-12-01 03:59:51 -0800790 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700791 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
792 sink_.WaitForEncodedFrame(frame_timestamp);
793 frame_timestamp += kFrameIntervalMs;
794
perkj803d97f2016-11-01 11:45:46 -0700795 // Trigger CPU overuse.
796 vie_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700797 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700798 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
799 sink_.WaitForEncodedFrame(frame_timestamp);
800 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -0700801
asapersson0944a802017-04-07 00:57:58 -0700802 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -0700803 // wanted resolution.
804 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
805 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
806 kFrameWidth * kFrameHeight);
807 EXPECT_EQ(std::numeric_limits<int>::max(),
808 video_source_.sink_wants().max_framerate_fps);
809
810 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -0700811 test::FrameForwarder new_video_source;
812 vie_encoder_->SetSource(
813 &new_video_source,
814 VideoSendStream::DegradationPreference::kMaintainResolution);
815
sprangc5d62e22017-04-02 23:53:04 -0700816 // Initially no degradation registered.
asapersson02465b82017-04-10 01:12:52 -0700817 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700818
sprangc5d62e22017-04-02 23:53:04 -0700819 // Force an input frame rate to be available, or the adaptation call won't
820 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -0700821 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -0700822 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -0700823 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -0700824 stats_proxy_->SetMockStats(stats);
825
826 vie_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700827 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700828 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
829 sink_.WaitForEncodedFrame(frame_timestamp);
830 frame_timestamp += kFrameIntervalMs;
831
832 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -0800833 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700834 EXPECT_EQ(std::numeric_limits<int>::max(),
835 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700836 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -0700837
asapersson02465b82017-04-10 01:12:52 -0700838 // Turn off degradation completely.
sprangc5d62e22017-04-02 23:53:04 -0700839 vie_encoder_->SetSource(
840 &new_video_source,
841 VideoSendStream::DegradationPreference::kDegradationDisabled);
asapersson02465b82017-04-10 01:12:52 -0700842 VerifyNoLimitation(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -0700843
844 vie_encoder_->TriggerCpuOveruse();
845 new_video_source.IncomingCapturedFrame(
846 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
847 sink_.WaitForEncodedFrame(frame_timestamp);
848 frame_timestamp += kFrameIntervalMs;
849
850 // Still no degradation.
asapersson02465b82017-04-10 01:12:52 -0700851 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700852
853 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
sprangc5d62e22017-04-02 23:53:04 -0700854 vie_encoder_->SetSource(
855 &new_video_source,
856 VideoSendStream::DegradationPreference::kMaintainFramerate);
857 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
858 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -0800859 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700860 EXPECT_EQ(std::numeric_limits<int>::max(),
861 new_video_source.sink_wants().max_framerate_fps);
862
863 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
864 vie_encoder_->SetSource(
865 &new_video_source,
866 VideoSendStream::DegradationPreference::kMaintainResolution);
867 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
868 EXPECT_EQ(std::numeric_limits<int>::max(),
869 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700870 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -0700871
872 vie_encoder_->Stop();
873}
874
asaperssonfab67072017-04-04 05:51:49 -0700875TEST_F(ViEEncoderTest, StatsTracksQualityAdaptationStats) {
perkj803d97f2016-11-01 11:45:46 -0700876 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
877
asaperssonfab67072017-04-04 05:51:49 -0700878 const int kWidth = 1280;
879 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -0700880 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
881 sink_.WaitForEncodedFrame(1);
882 VideoSendStream::Stats stats = stats_proxy_->GetStats();
883 EXPECT_FALSE(stats.bw_limited_resolution);
884 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
885
886 // Trigger adapt down.
887 vie_encoder_->TriggerQualityLow();
888 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
889 sink_.WaitForEncodedFrame(2);
890
891 stats = stats_proxy_->GetStats();
892 EXPECT_TRUE(stats.bw_limited_resolution);
893 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
894
895 // Trigger adapt up.
896 vie_encoder_->TriggerQualityHigh();
897 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
898 sink_.WaitForEncodedFrame(3);
899
900 stats = stats_proxy_->GetStats();
901 EXPECT_FALSE(stats.bw_limited_resolution);
902 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
903 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
904
905 vie_encoder_->Stop();
906}
907
908TEST_F(ViEEncoderTest, StatsTracksCpuAdaptationStats) {
909 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
910
911 const int kWidth = 1280;
912 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -0700913 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
perkj803d97f2016-11-01 11:45:46 -0700914 sink_.WaitForEncodedFrame(1);
915 VideoSendStream::Stats stats = stats_proxy_->GetStats();
916 EXPECT_FALSE(stats.cpu_limited_resolution);
917 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
918
919 // Trigger CPU overuse.
920 vie_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -0700921 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
perkj803d97f2016-11-01 11:45:46 -0700922 sink_.WaitForEncodedFrame(2);
923
924 stats = stats_proxy_->GetStats();
925 EXPECT_TRUE(stats.cpu_limited_resolution);
926 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
927
928 // Trigger CPU normal use.
929 vie_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -0700930 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
perkj803d97f2016-11-01 11:45:46 -0700931 sink_.WaitForEncodedFrame(3);
932
933 stats = stats_proxy_->GetStats();
934 EXPECT_FALSE(stats.cpu_limited_resolution);
935 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -0700936 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -0700937
938 vie_encoder_->Stop();
939}
940
kthelgason876222f2016-11-29 01:44:11 -0800941TEST_F(ViEEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
kthelgason876222f2016-11-29 01:44:11 -0800942 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
943
asaperssonfab67072017-04-04 05:51:49 -0700944 const int kWidth = 1280;
945 const int kHeight = 720;
946 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -0800947 sink_.WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -0800948 VideoSendStream::Stats stats = stats_proxy_->GetStats();
949 EXPECT_FALSE(stats.cpu_limited_resolution);
950 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
951
asaperssonfab67072017-04-04 05:51:49 -0700952 // Trigger CPU overuse.
kthelgason876222f2016-11-29 01:44:11 -0800953 vie_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -0700954 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -0800955 sink_.WaitForEncodedFrame(2);
956 stats = stats_proxy_->GetStats();
957 EXPECT_TRUE(stats.cpu_limited_resolution);
958 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
959
960 // Set new source with adaptation still enabled.
961 test::FrameForwarder new_video_source;
sprangc5d62e22017-04-02 23:53:04 -0700962 vie_encoder_->SetSource(
963 &new_video_source,
964 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -0800965
asaperssonfab67072017-04-04 05:51:49 -0700966 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -0800967 sink_.WaitForEncodedFrame(3);
968 stats = stats_proxy_->GetStats();
969 EXPECT_TRUE(stats.cpu_limited_resolution);
970 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
971
972 // Set adaptation disabled.
973 vie_encoder_->SetSource(
974 &new_video_source,
sprangc5d62e22017-04-02 23:53:04 -0700975 VideoSendStream::DegradationPreference::kDegradationDisabled);
kthelgason876222f2016-11-29 01:44:11 -0800976
asaperssonfab67072017-04-04 05:51:49 -0700977 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -0800978 sink_.WaitForEncodedFrame(4);
979 stats = stats_proxy_->GetStats();
980 EXPECT_FALSE(stats.cpu_limited_resolution);
981 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
982
983 // Set adaptation back to enabled.
sprangc5d62e22017-04-02 23:53:04 -0700984 vie_encoder_->SetSource(
985 &new_video_source,
986 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -0800987
asaperssonfab67072017-04-04 05:51:49 -0700988 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -0800989 sink_.WaitForEncodedFrame(5);
990 stats = stats_proxy_->GetStats();
991 EXPECT_TRUE(stats.cpu_limited_resolution);
992 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
993
asaperssonfab67072017-04-04 05:51:49 -0700994 // Trigger CPU normal use.
kthelgason876222f2016-11-29 01:44:11 -0800995 vie_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -0700996 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -0800997 sink_.WaitForEncodedFrame(6);
998 stats = stats_proxy_->GetStats();
999 EXPECT_FALSE(stats.cpu_limited_resolution);
1000 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001001 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001002
1003 vie_encoder_->Stop();
1004}
1005
1006TEST_F(ViEEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
kthelgason876222f2016-11-29 01:44:11 -08001007 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1008
asaperssonfab67072017-04-04 05:51:49 -07001009 const int kWidth = 1280;
1010 const int kHeight = 720;
1011 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -08001012 sink_.WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001013 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1014 EXPECT_FALSE(stats.cpu_limited_resolution);
1015 EXPECT_FALSE(stats.bw_limited_resolution);
asaperssonfab67072017-04-04 05:51:49 -07001016 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001017
1018 // Set new source with adaptation still enabled.
1019 test::FrameForwarder new_video_source;
1020 vie_encoder_->SetSource(&new_video_source,
1021 VideoSendStream::DegradationPreference::kBalanced);
1022
asaperssonfab67072017-04-04 05:51:49 -07001023 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -08001024 sink_.WaitForEncodedFrame(2);
1025 stats = stats_proxy_->GetStats();
1026 EXPECT_FALSE(stats.cpu_limited_resolution);
1027 EXPECT_FALSE(stats.bw_limited_resolution);
asaperssonfab67072017-04-04 05:51:49 -07001028 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001029
asaperssonfab67072017-04-04 05:51:49 -07001030 // Trigger adapt down.
kthelgason876222f2016-11-29 01:44:11 -08001031 vie_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001032 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -08001033 sink_.WaitForEncodedFrame(3);
1034 stats = stats_proxy_->GetStats();
1035 EXPECT_FALSE(stats.cpu_limited_resolution);
1036 EXPECT_TRUE(stats.bw_limited_resolution);
asaperssonfab67072017-04-04 05:51:49 -07001037 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001038
asaperssonfab67072017-04-04 05:51:49 -07001039 // Set new source with adaptation still enabled.
kthelgason876222f2016-11-29 01:44:11 -08001040 vie_encoder_->SetSource(&new_video_source,
1041 VideoSendStream::DegradationPreference::kBalanced);
1042
asaperssonfab67072017-04-04 05:51:49 -07001043 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -08001044 sink_.WaitForEncodedFrame(4);
1045 stats = stats_proxy_->GetStats();
1046 EXPECT_FALSE(stats.cpu_limited_resolution);
1047 EXPECT_TRUE(stats.bw_limited_resolution);
asaperssonfab67072017-04-04 05:51:49 -07001048 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001049
asapersson02465b82017-04-10 01:12:52 -07001050 // Disable resolution scaling.
kthelgason876222f2016-11-29 01:44:11 -08001051 vie_encoder_->SetSource(
1052 &new_video_source,
1053 VideoSendStream::DegradationPreference::kMaintainResolution);
1054
asaperssonfab67072017-04-04 05:51:49 -07001055 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -08001056 sink_.WaitForEncodedFrame(5);
1057 stats = stats_proxy_->GetStats();
1058 EXPECT_FALSE(stats.cpu_limited_resolution);
1059 EXPECT_FALSE(stats.bw_limited_resolution);
asaperssonfab67072017-04-04 05:51:49 -07001060 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1061 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001062
1063 vie_encoder_->Stop();
1064}
1065
asapersson36e9eb42017-03-31 05:29:12 -07001066TEST_F(ViEEncoderTest, QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1067 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1068
1069 const int kWidth = 1280;
1070 const int kHeight = 720;
1071 video_source_.set_adaptation_enabled(true);
1072 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1073 sink_.WaitForEncodedFrame(1);
1074 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1075 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1076 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1077
1078 // Trigger adapt down.
1079 vie_encoder_->TriggerQualityLow();
1080 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1081 sink_.WaitForEncodedFrame(2);
1082 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1083 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1084 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1085
1086 // Trigger overuse.
1087 vie_encoder_->TriggerCpuOveruse();
1088 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1089 sink_.WaitForEncodedFrame(3);
1090 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1091 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1092 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1093
1094 // Set source with adaptation still enabled but quality scaler is off.
1095 fake_encoder_.SetQualityScaling(false);
sprangc5d62e22017-04-02 23:53:04 -07001096 vie_encoder_->SetSource(
1097 &video_source_,
1098 VideoSendStream::DegradationPreference::kMaintainFramerate);
asapersson36e9eb42017-03-31 05:29:12 -07001099
1100 video_source_.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
1101 sink_.WaitForEncodedFrame(4);
1102 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1103 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1104 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1105
1106 vie_encoder_->Stop();
1107}
1108
asapersson02465b82017-04-10 01:12:52 -07001109TEST_F(ViEEncoderTest, StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
perkj803d97f2016-11-01 11:45:46 -07001110 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1111
asapersson0944a802017-04-07 00:57:58 -07001112 const int kWidth = 1280;
1113 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001114 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001115
asaperssonfab67072017-04-04 05:51:49 -07001116 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang84a37592017-02-10 07:04:27 -08001117 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001118 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001119 EXPECT_FALSE(stats.cpu_limited_resolution);
1120 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1121
asapersson02465b82017-04-10 01:12:52 -07001122 // Trigger CPU overuse, should now adapt down.
sprang84a37592017-02-10 07:04:27 -08001123 vie_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001124 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang84a37592017-02-10 07:04:27 -08001125 sink_.WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001126 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001127 EXPECT_TRUE(stats.cpu_limited_resolution);
1128 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1129
1130 // Set new source with adaptation still enabled.
1131 test::FrameForwarder new_video_source;
sprangc5d62e22017-04-02 23:53:04 -07001132 vie_encoder_->SetSource(
1133 &new_video_source,
1134 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001135
1136 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001137 CreateFrame(sequence, kWidth, kHeight));
sprang84a37592017-02-10 07:04:27 -08001138 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001139 stats = stats_proxy_->GetStats();
1140 EXPECT_TRUE(stats.cpu_limited_resolution);
1141 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1142
sprangc5d62e22017-04-02 23:53:04 -07001143 // Set cpu adaptation by frame dropping.
perkj803d97f2016-11-01 11:45:46 -07001144 vie_encoder_->SetSource(
1145 &new_video_source,
1146 VideoSendStream::DegradationPreference::kMaintainResolution);
1147 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001148 CreateFrame(sequence, kWidth, kHeight));
sprang84a37592017-02-10 07:04:27 -08001149 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001150 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001151 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001152 EXPECT_FALSE(stats.cpu_limited_resolution);
1153 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1154
sprangc5d62e22017-04-02 23:53:04 -07001155 // Force an input frame rate to be available, or the adaptation call won't
1156 // know what framerate to adapt form.
1157 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1158 mock_stats.input_frame_rate = 30;
1159 stats_proxy_->SetMockStats(mock_stats);
1160 vie_encoder_->TriggerCpuOveruse();
1161 stats_proxy_->ResetMockStats();
1162
1163 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001164 CreateFrame(sequence, kWidth, kHeight));
sprangc5d62e22017-04-02 23:53:04 -07001165 sink_.WaitForEncodedFrame(sequence++);
1166
1167 // Framerate now adapted.
1168 stats = stats_proxy_->GetStats();
1169 EXPECT_TRUE(stats.cpu_limited_resolution);
1170 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1171
1172 // Disable CPU adaptation.
1173 vie_encoder_->SetSource(
1174 &new_video_source,
1175 VideoSendStream::DegradationPreference::kDegradationDisabled);
1176 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001177 CreateFrame(sequence, kWidth, kHeight));
sprangc5d62e22017-04-02 23:53:04 -07001178 sink_.WaitForEncodedFrame(sequence++);
1179
1180 stats = stats_proxy_->GetStats();
1181 EXPECT_FALSE(stats.cpu_limited_resolution);
1182 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1183
1184 // Try to trigger overuse. Should not succeed.
1185 stats_proxy_->SetMockStats(mock_stats);
1186 vie_encoder_->TriggerCpuOveruse();
1187 stats_proxy_->ResetMockStats();
1188
1189 stats = stats_proxy_->GetStats();
1190 EXPECT_FALSE(stats.cpu_limited_resolution);
1191 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1192
1193 // Switch back the source with resolution adaptation enabled.
1194 vie_encoder_->SetSource(
1195 &video_source_,
1196 VideoSendStream::DegradationPreference::kMaintainFramerate);
asaperssonfab67072017-04-04 05:51:49 -07001197 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang84a37592017-02-10 07:04:27 -08001198 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001199 stats = stats_proxy_->GetStats();
1200 EXPECT_TRUE(stats.cpu_limited_resolution);
sprangc5d62e22017-04-02 23:53:04 -07001201 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001202
1203 // Trigger CPU normal usage.
1204 vie_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001205 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang84a37592017-02-10 07:04:27 -08001206 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001207 stats = stats_proxy_->GetStats();
1208 EXPECT_FALSE(stats.cpu_limited_resolution);
sprangc5d62e22017-04-02 23:53:04 -07001209 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1210
1211 // Back to the source with adaptation off, set it back to maintain-resolution.
1212 vie_encoder_->SetSource(
1213 &new_video_source,
1214 VideoSendStream::DegradationPreference::kMaintainResolution);
1215 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001216 CreateFrame(sequence, kWidth, kHeight));
sprangc5d62e22017-04-02 23:53:04 -07001217 sink_.WaitForEncodedFrame(sequence++);
1218 stats = stats_proxy_->GetStats();
1219 // Disabled, since we previously switched the source too disabled.
1220 EXPECT_FALSE(stats.cpu_limited_resolution);
1221 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1222
1223 // Trigger CPU normal usage.
1224 vie_encoder_->TriggerCpuNormalUsage();
1225 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001226 CreateFrame(sequence, kWidth, kHeight));
sprangc5d62e22017-04-02 23:53:04 -07001227 sink_.WaitForEncodedFrame(sequence++);
1228 stats = stats_proxy_->GetStats();
1229 EXPECT_FALSE(stats.cpu_limited_resolution);
1230 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001231 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001232
1233 vie_encoder_->Stop();
1234}
1235
Erik Språng08127a92016-11-16 16:41:30 +01001236TEST_F(ViEEncoderTest, StatsTracksPreferredBitrate) {
Erik Språng08127a92016-11-16 16:41:30 +01001237 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1238
asaperssonfab67072017-04-04 05:51:49 -07001239 const int kWidth = 1280;
1240 const int kHeight = 720;
1241 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
Erik Språng08127a92016-11-16 16:41:30 +01001242 sink_.WaitForEncodedFrame(1);
1243
1244 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1245 EXPECT_EQ(video_encoder_config_.max_bitrate_bps,
1246 stats.preferred_media_bitrate_bps);
1247
1248 vie_encoder_->Stop();
1249}
1250
kthelgason876222f2016-11-29 01:44:11 -08001251TEST_F(ViEEncoderTest, ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001252 const int kWidth = 1280;
1253 const int kHeight = 720;
kthelgason876222f2016-11-29 01:44:11 -08001254 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1255
asaperssonfab67072017-04-04 05:51:49 -07001256 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001257 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001258
asaperssonfab67072017-04-04 05:51:49 -07001259 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -08001260 sink_.WaitForEncodedFrame(1);
1261
asaperssonfab67072017-04-04 05:51:49 -07001262 // Trigger scale down.
kthelgason5e13d412016-12-01 03:59:51 -08001263 vie_encoder_->TriggerQualityLow();
1264
asaperssonfab67072017-04-04 05:51:49 -07001265 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
kthelgason5e13d412016-12-01 03:59:51 -08001266 sink_.WaitForEncodedFrame(2);
1267
kthelgason876222f2016-11-29 01:44:11 -08001268 // Expect a scale down.
1269 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001270 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001271
asapersson02465b82017-04-10 01:12:52 -07001272 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001273 test::FrameForwarder new_video_source;
1274 vie_encoder_->SetSource(
1275 &new_video_source,
1276 VideoSendStream::DegradationPreference::kMaintainResolution);
1277
asaperssonfab67072017-04-04 05:51:49 -07001278 // Trigger scale down.
kthelgason876222f2016-11-29 01:44:11 -08001279 vie_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001280 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
kthelgason5e13d412016-12-01 03:59:51 -08001281 sink_.WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001282
asaperssonfab67072017-04-04 05:51:49 -07001283 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001284 EXPECT_EQ(std::numeric_limits<int>::max(),
1285 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001286
asaperssonfab67072017-04-04 05:51:49 -07001287 // Trigger scale up.
kthelgason876222f2016-11-29 01:44:11 -08001288 vie_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001289 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
kthelgason5e13d412016-12-01 03:59:51 -08001290 sink_.WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001291
asapersson02465b82017-04-10 01:12:52 -07001292 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001293 EXPECT_EQ(std::numeric_limits<int>::max(),
1294 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001295
1296 vie_encoder_->Stop();
1297}
1298
asapersson02465b82017-04-10 01:12:52 -07001299TEST_F(ViEEncoderTest, SkipsSameAdaptDownRequest_MaintainFramerateMode) {
1300 const int kWidth = 1280;
1301 const int kHeight = 720;
1302 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1303
1304 // Enable kMaintainFramerate preference, no initial limitation.
1305 test::FrameForwarder source;
1306 vie_encoder_->SetSource(
1307 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1308
1309 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1310 sink_.WaitForEncodedFrame(1);
1311 VerifyNoLimitation(source.sink_wants());
1312 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1313 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1314
1315 // Trigger adapt down, expect scaled down resolution.
1316 vie_encoder_->TriggerCpuOveruse();
1317 VerifyResolutionLimitationLessThan(source.sink_wants(), kWidth * kHeight);
1318 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1319 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1320 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1321
1322 // Trigger adapt down for same input resolution, expect no change.
1323 vie_encoder_->TriggerCpuOveruse();
1324 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1325 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1326 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1327
1328 vie_encoder_->Stop();
1329}
1330
1331TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_MaintainFramerateMode) {
1332 const int kWidth = 1280;
1333 const int kHeight = 720;
1334 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1335
1336 // Enable kMaintainFramerate preference, no initial limitation.
1337 test::FrameForwarder source;
1338 vie_encoder_->SetSource(
1339 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1340
1341 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1342 sink_.WaitForEncodedFrame(kWidth, kHeight);
1343 VerifyNoLimitation(source.sink_wants());
1344 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1345 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1346
1347 // Trigger adapt up, expect no change.
1348 vie_encoder_->TriggerCpuNormalUsage();
1349 VerifyNoLimitation(source.sink_wants());
1350 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1351 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1352
1353 vie_encoder_->Stop();
1354}
1355
1356TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_MaintainResolutionMode) {
1357 const int kWidth = 1280;
1358 const int kHeight = 720;
1359 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1360
1361 // Enable kMaintainResolution preference, no initial limitation.
1362 test::FrameForwarder source;
1363 vie_encoder_->SetSource(
1364 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
1365
1366 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1367 sink_.WaitForEncodedFrame(kWidth, kHeight);
1368 VerifyNoLimitation(source.sink_wants());
1369 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1370 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1371
1372 // Trigger adapt up, expect no change.
1373 vie_encoder_->TriggerCpuNormalUsage();
1374 VerifyNoLimitation(source.sink_wants());
1375 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1376 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1377
1378 vie_encoder_->Stop();
1379}
1380
1381TEST_F(ViEEncoderTest, AdaptsResolutionForLowQuality_MaintainFramerateMode) {
1382 const int kWidth = 1280;
1383 const int kHeight = 720;
1384 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1385
1386 // Enable kMaintainFramerate preference, no initial limitation.
1387 AdaptingFrameForwarder source;
1388 source.set_adaptation_enabled(true);
1389 vie_encoder_->SetSource(
1390 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1391
1392 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1393 sink_.WaitForEncodedFrame(1);
1394 VerifyNoLimitation(source.sink_wants());
1395 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1396 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1397
1398 // Trigger adapt down, expect scaled down resolution.
1399 vie_encoder_->TriggerQualityLow();
1400 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1401 sink_.WaitForEncodedFrame(2);
1402 VerifyResolutionLimitationLessThan(source.sink_wants(), kWidth * kHeight);
1403 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1404 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1405
1406 // Trigger adapt up, expect no restriction.
1407 vie_encoder_->TriggerQualityHigh();
1408 VerifyNoLimitation(source.sink_wants());
1409 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1410 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1411 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1412
1413 vie_encoder_->Stop();
1414}
1415
asaperssond0de2952017-04-21 01:47:31 -07001416TEST_F(ViEEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
1417 const int kWidth = 1280;
1418 const int kHeight = 720;
1419 const size_t kNumFrames = 10;
1420
kthelgason5e13d412016-12-01 03:59:51 -08001421 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1422
asaperssond0de2952017-04-21 01:47:31 -07001423 // Enable adapter, expected input resolutions when downscaling:
1424 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (min resolution limit)
1425 video_source_.set_adaptation_enabled(true);
1426
1427 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1428 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1429
1430 int downscales = 0;
1431 for (size_t i = 1; i <= kNumFrames; i++) {
1432 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
kthelgason5e13d412016-12-01 03:59:51 -08001433 sink_.WaitForEncodedFrame(i);
asaperssond0de2952017-04-21 01:47:31 -07001434
asaperssonfab67072017-04-04 05:51:49 -07001435 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001436 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
kthelgason5e13d412016-12-01 03:59:51 -08001437 vie_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001438 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001439
1440 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1441 ++downscales;
1442
1443 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1444 EXPECT_EQ(downscales,
1445 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1446 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001447 }
asaperssond0de2952017-04-21 01:47:31 -07001448 vie_encoder_->Stop();
1449}
1450
1451TEST_F(ViEEncoderTest,
1452 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1453 const int kWidth = 1280;
1454 const int kHeight = 720;
1455 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1456
1457 // Enable kMaintainFramerate preference, no initial limitation.
1458 AdaptingFrameForwarder source;
1459 source.set_adaptation_enabled(true);
1460 vie_encoder_->SetSource(
1461 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1462
1463 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1464 sink_.WaitForEncodedFrame(1);
1465 VerifyNoLimitation(source.sink_wants());
1466 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1467 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1468
1469 // Trigger adapt down, expect scaled down resolution.
1470 vie_encoder_->TriggerCpuOveruse();
1471 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1472 sink_.WaitForEncodedFrame(2);
1473 VerifyResolutionLimitationLessThan(source.sink_wants(), kWidth * kHeight);
1474 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1475 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1476
1477 // Trigger adapt up, expect no restriction.
1478 vie_encoder_->TriggerCpuNormalUsage();
1479 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1480 sink_.WaitForEncodedFrame(3);
1481 VerifyNoLimitation(source.sink_wants());
1482 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1483 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1484
1485 // Trigger adapt down, expect scaled down resolution.
1486 vie_encoder_->TriggerCpuOveruse();
1487 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
1488 sink_.WaitForEncodedFrame(4);
1489 VerifyResolutionLimitationLessThan(source.sink_wants(), kWidth * kHeight);
1490 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1491 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1492
1493 // Trigger adapt up, expect no restriction.
1494 vie_encoder_->TriggerCpuNormalUsage();
1495 VerifyNoLimitation(source.sink_wants());
1496 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1497 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1498
1499 vie_encoder_->Stop();
1500}
1501
1502TEST_F(ViEEncoderTest,
1503 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
1504 const int kWidth = 1280;
1505 const int kHeight = 720;
1506 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1507
1508 // Enable kMaintainFramerate preference, no initial limitation.
1509 AdaptingFrameForwarder source;
1510 source.set_adaptation_enabled(true);
1511 vie_encoder_->SetSource(
1512 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1513
1514 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1515 sink_.WaitForEncodedFrame(kWidth, kHeight);
1516 VerifyNoLimitation(source.sink_wants());
1517 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1518 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1519 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1520 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1521
1522 // Trigger cpu adapt down, expect scaled down resolution (960x540).
1523 vie_encoder_->TriggerCpuOveruse();
1524 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1525 sink_.WaitForEncodedFrame(2);
1526 VerifyResolutionLimitationLessThan(source.sink_wants(), kWidth * kHeight);
1527 rtc::VideoSinkWants last_wants = source.sink_wants();
1528 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1529 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1530 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1531 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1532
1533 // Trigger cpu adapt down, expect scaled down resolution (640x360).
1534 vie_encoder_->TriggerCpuOveruse();
1535 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1536 sink_.WaitForEncodedFrame(3);
1537 EXPECT_LT(source.sink_wants().max_pixel_count, last_wants.max_pixel_count);
1538 last_wants = source.sink_wants();
1539 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1540 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1541 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1542 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1543
1544 // Trigger cpu adapt down, max cpu downgrades reached, expect no change.
1545 vie_encoder_->TriggerCpuOveruse();
1546 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
1547 sink_.WaitForEncodedFrame(4);
1548 EXPECT_EQ(last_wants.max_pixel_count, source.sink_wants().max_pixel_count);
1549 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1550 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1551 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1552 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1553
1554 // Trigger quality adapt down, expect scaled down resolution (480x270).
1555 vie_encoder_->TriggerQualityLow();
1556 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1557 sink_.WaitForEncodedFrame(5);
1558 EXPECT_LT(source.sink_wants().max_pixel_count, last_wants.max_pixel_count);
1559 last_wants = source.sink_wants();
1560 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1561 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1562 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1563 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1564
1565 // Trigger cpu adapt up, expect upscaled resolution (640x360).
1566 vie_encoder_->TriggerCpuNormalUsage();
1567 source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
1568 sink_.WaitForEncodedFrame(6);
1569 EXPECT_GT(source.sink_wants().max_pixel_count, last_wants.max_pixel_count);
1570 last_wants = source.sink_wants();
1571 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1572 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1573 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1574 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1575
1576 // Trigger cpu adapt up, expect upscaled resolution (960x540).
1577 vie_encoder_->TriggerCpuNormalUsage();
1578 source.IncomingCapturedFrame(CreateFrame(7, kWidth, kHeight));
1579 sink_.WaitForEncodedFrame(7);
1580 EXPECT_GT(source.sink_wants().max_pixel_count, last_wants.max_pixel_count);
1581 last_wants = source.sink_wants();
1582 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1583 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1584 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1585 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1586
1587 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
1588 vie_encoder_->TriggerCpuNormalUsage();
1589 source.IncomingCapturedFrame(CreateFrame(8, kWidth, kHeight));
1590 sink_.WaitForEncodedFrame(8);
1591 EXPECT_EQ(last_wants.max_pixel_count, source.sink_wants().max_pixel_count);
1592 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1593 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1594 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1595 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1596
1597 // Trigger quality adapt up, expect no restriction (1280x720).
1598 vie_encoder_->TriggerQualityHigh();
1599 source.IncomingCapturedFrame(CreateFrame(9, kWidth, kHeight));
1600 sink_.WaitForEncodedFrame(kWidth, kHeight);
1601 EXPECT_GT(source.sink_wants().max_pixel_count, last_wants.max_pixel_count);
1602 VerifyNoLimitation(source.sink_wants());
1603 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1604 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1605 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1606 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08001607
1608 vie_encoder_->Stop();
1609}
1610
asaperssonf4e44af2017-04-19 02:01:06 -07001611TEST_F(ViEEncoderTest, CpuLimitedHistogramIsReported) {
perkj803d97f2016-11-01 11:45:46 -07001612 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001613 const int kWidth = 640;
1614 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07001615
1616 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07001617 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
perkj803d97f2016-11-01 11:45:46 -07001618 sink_.WaitForEncodedFrame(i);
1619 }
1620
1621 vie_encoder_->TriggerCpuOveruse();
1622 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07001623 video_source_.IncomingCapturedFrame(CreateFrame(
1624 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
perkj803d97f2016-11-01 11:45:46 -07001625 sink_.WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples +
1626 i);
1627 }
1628
1629 vie_encoder_->Stop();
sprangf8ee65e2017-02-28 08:49:33 -08001630 vie_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07001631 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08001632
perkj803d97f2016-11-01 11:45:46 -07001633 EXPECT_EQ(1,
1634 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
1635 EXPECT_EQ(
1636 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
1637}
1638
asaperssonf4e44af2017-04-19 02:01:06 -07001639TEST_F(ViEEncoderTest, CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
1640 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1641 const int kWidth = 640;
1642 const int kHeight = 360;
1643
1644 vie_encoder_->SetSource(
1645 &video_source_,
1646 VideoSendStream::DegradationPreference::kDegradationDisabled);
1647
1648 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
1649 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
1650 sink_.WaitForEncodedFrame(i);
1651 }
1652
1653 vie_encoder_->Stop();
1654 vie_encoder_.reset();
1655 stats_proxy_.reset();
1656
1657 EXPECT_EQ(0,
1658 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
1659}
1660
sprang57c2fff2017-01-16 06:24:02 -08001661TEST_F(ViEEncoderTest, CallsBitrateObserver) {
1662 class MockBitrateObserver : public VideoBitrateAllocationObserver {
1663 public:
1664 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const BitrateAllocation&));
1665 } bitrate_observer;
1666 vie_encoder_->SetBitrateObserver(&bitrate_observer);
1667
1668 const int kDefaultFps = 30;
1669 const BitrateAllocation expected_bitrate =
1670 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08001671 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08001672
1673 // First called on bitrate updated, then again on first frame.
1674 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
1675 .Times(2);
kthelgason2bc68642017-02-07 07:02:22 -08001676 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08001677
1678 const int64_t kStartTimeMs = 1;
1679 video_source_.IncomingCapturedFrame(
1680 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
1681 sink_.WaitForEncodedFrame(kStartTimeMs);
1682
1683 // Not called on second frame.
1684 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
1685 .Times(0);
1686 video_source_.IncomingCapturedFrame(
1687 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
1688 sink_.WaitForEncodedFrame(kStartTimeMs + 1);
1689
1690 // Called after a process interval.
1691 const int64_t kProcessIntervalMs =
1692 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
1693 // TODO(sprang): ViEEncoder should die and/or get injectable clock.
1694 // Sleep for one processing interval plus one frame to avoid flakiness.
1695 SleepMs(kProcessIntervalMs + 1000 / kDefaultFps);
1696 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
1697 .Times(1);
1698 video_source_.IncomingCapturedFrame(CreateFrame(
1699 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
1700 sink_.WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
1701
1702 vie_encoder_->Stop();
1703}
1704
kthelgason2bc68642017-02-07 07:02:22 -08001705TEST_F(ViEEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07001706 const int kTooLowBitrateForFrameSizeBps = 10000;
1707 vie_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
1708 const int kWidth = 640;
1709 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08001710
asaperssonfab67072017-04-04 05:51:49 -07001711 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08001712
1713 // Expect to drop this frame, the wait should time out.
1714 sink_.ExpectDroppedFrame();
1715
1716 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07001717 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08001718
sprangc5d62e22017-04-02 23:53:04 -07001719 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08001720
asaperssonfab67072017-04-04 05:51:49 -07001721 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08001722 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001723 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08001724
1725 // Expect to drop this frame, the wait should time out.
1726 sink_.ExpectDroppedFrame();
1727
sprangc5d62e22017-04-02 23:53:04 -07001728 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08001729
1730 vie_encoder_->Stop();
1731}
1732
asaperssonfab67072017-04-04 05:51:49 -07001733TEST_F(ViEEncoderTest, NrOfDroppedFramesLimitedWhenBitrateIsTooLow) {
1734 const int kTooLowBitrateForFrameSizeBps = 10000;
1735 vie_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
1736 const int kWidth = 640;
1737 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08001738
1739 // We expect the n initial frames to get dropped.
1740 int i;
1741 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07001742 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08001743 sink_.ExpectDroppedFrame();
1744 }
1745 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07001746 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08001747 sink_.WaitForEncodedFrame(i);
1748
1749 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07001750 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08001751
1752 vie_encoder_->Stop();
1753}
1754
1755TEST_F(ViEEncoderTest, InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07001756 const int kWidth = 640;
1757 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08001758 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
1759
1760 // Set degradation preference.
1761 vie_encoder_->SetSource(
1762 &video_source_,
1763 VideoSendStream::DegradationPreference::kMaintainResolution);
1764
asaperssonfab67072017-04-04 05:51:49 -07001765 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08001766 // Frame should not be dropped, even if it's too large.
1767 sink_.WaitForEncodedFrame(1);
1768
1769 vie_encoder_->Stop();
1770}
1771
kthelgason2fc52542017-03-03 00:24:41 -08001772TEST_F(ViEEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07001773 const int kWidth = 640;
1774 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08001775 fake_encoder_.SetQualityScaling(false);
1776 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgasonb83797b2017-02-14 11:57:25 -08001777 // Force quality scaler reconfiguration by resetting the source.
1778 vie_encoder_->SetSource(&video_source_,
1779 VideoSendStream::DegradationPreference::kBalanced);
kthelgasonad9010c2017-02-14 00:46:51 -08001780
asaperssonfab67072017-04-04 05:51:49 -07001781 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08001782 // Frame should not be dropped, even if it's too large.
1783 sink_.WaitForEncodedFrame(1);
1784
1785 vie_encoder_->Stop();
1786 fake_encoder_.SetQualityScaling(true);
1787}
1788
asaperssond0de2952017-04-21 01:47:31 -07001789TEST_F(ViEEncoderTest,
1790 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
1791 const int kTooSmallWidth = 10;
1792 const int kTooSmallHeight = 10;
1793 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1794
1795 // Enable kMaintainFramerate preference, no initial limitation.
1796 test::FrameForwarder source;
1797 vie_encoder_->SetSource(
1798 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1799 VerifyNoLimitation(source.sink_wants());
1800 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1801
1802 // Trigger adapt down, too small frame, expect no change.
1803 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
1804 sink_.WaitForEncodedFrame(1);
1805 vie_encoder_->TriggerCpuOveruse();
1806 VerifyNoLimitation(source.sink_wants());
1807 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1808 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1809
1810 vie_encoder_->Stop();
1811}
1812
asapersson02465b82017-04-10 01:12:52 -07001813TEST_F(ViEEncoderTest, FailingInitEncodeDoesntCauseCrash) {
1814 fake_encoder_.ForceInitEncodeFailure(true);
1815 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1816 ResetEncoder("VP8", 2, 1, true);
1817 const int kFrameWidth = 1280;
1818 const int kFrameHeight = 720;
1819 video_source_.IncomingCapturedFrame(
1820 CreateFrame(1, kFrameWidth, kFrameHeight));
1821 sink_.ExpectDroppedFrame();
1822 vie_encoder_->Stop();
1823}
1824
sprangb1ca0732017-02-01 08:38:12 -08001825// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
asaperssond0de2952017-04-21 01:47:31 -07001826TEST_F(ViEEncoderTest, AdaptsResolutionOnOveruse_MaintainFramerateMode) {
sprangb1ca0732017-02-01 08:38:12 -08001827 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1828
1829 const int kFrameWidth = 1280;
1830 const int kFrameHeight = 720;
1831 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
1832 // requested by ViEEncoder::VideoSourceProxy::RequestResolutionLowerThan().
1833 video_source_.set_adaptation_enabled(true);
1834
1835 video_source_.IncomingCapturedFrame(
1836 CreateFrame(1, kFrameWidth, kFrameHeight));
1837 sink_.WaitForEncodedFrame(kFrameWidth, kFrameHeight);
1838
1839 // Trigger CPU overuse, downscale by 3/4.
1840 vie_encoder_->TriggerCpuOveruse();
1841 video_source_.IncomingCapturedFrame(
1842 CreateFrame(2, kFrameWidth, kFrameHeight));
1843 sink_.WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
1844
asaperssonfab67072017-04-04 05:51:49 -07001845 // Trigger CPU normal use, return to original resolution.
sprangb1ca0732017-02-01 08:38:12 -08001846 vie_encoder_->TriggerCpuNormalUsage();
1847 video_source_.IncomingCapturedFrame(
1848 CreateFrame(3, kFrameWidth, kFrameHeight));
1849 sink_.WaitForEncodedFrame(kFrameWidth, kFrameHeight);
1850
1851 vie_encoder_->Stop();
1852}
sprangfe627f32017-03-29 08:24:59 -07001853
asapersson02465b82017-04-10 01:12:52 -07001854TEST_F(ViEEncoderTest, AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07001855 const int kDefaultFramerateFps = 30;
1856 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kDefaultFramerateFps;
1857 const int kFrameWidth = 1280;
1858 const int kFrameHeight = 720;
1859 rtc::ScopedFakeClock fake_clock;
1860
1861 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1862 vie_encoder_->SetSource(
1863 &video_source_,
1864 VideoSendStream::DegradationPreference::kMaintainResolution);
1865 video_source_.set_adaptation_enabled(true);
1866
1867 fake_clock.SetTimeMicros(kFrameIntervalMs * 1000);
1868 int64_t timestamp_ms = kFrameIntervalMs;
1869
1870 video_source_.IncomingCapturedFrame(
1871 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1872 sink_.WaitForEncodedFrame(timestamp_ms);
1873
1874 // Try to trigger overuse. No fps estimate available => no effect.
1875 vie_encoder_->TriggerCpuOveruse();
1876
1877 // Insert frames for one second to get a stable estimate.
1878 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1879 timestamp_ms += kFrameIntervalMs;
1880 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1881 video_source_.IncomingCapturedFrame(
1882 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1883 sink_.WaitForEncodedFrame(timestamp_ms);
1884 }
1885
1886 // Trigger CPU overuse, reduce framerate by 2/3.
1887 vie_encoder_->TriggerCpuOveruse();
1888 int num_frames_dropped = 0;
1889 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1890 timestamp_ms += kFrameIntervalMs;
1891 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1892 video_source_.IncomingCapturedFrame(
1893 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1894 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
1895 ++num_frames_dropped;
1896 } else {
1897 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
1898 }
1899 }
1900
1901 // TODO(sprang): Find where there's rounding errors or stuff causing the
1902 // margin here to be a little larger than we'd like (input fps estimate is
1903 // off) and the frame dropping is a little too aggressive.
1904 const int kErrorMargin = 5;
1905 EXPECT_NEAR(num_frames_dropped,
1906 kDefaultFramerateFps - (kDefaultFramerateFps * 2 / 3),
1907 kErrorMargin);
1908
1909 // Trigger CPU overuse, reduce framerate by 2/3 again.
1910 vie_encoder_->TriggerCpuOveruse();
1911 num_frames_dropped = 0;
1912 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1913 timestamp_ms += kFrameIntervalMs;
1914 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1915 video_source_.IncomingCapturedFrame(
1916 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1917 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
1918 ++num_frames_dropped;
1919 } else {
1920 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
1921 }
1922 }
1923 EXPECT_NEAR(num_frames_dropped,
1924 kDefaultFramerateFps - (kDefaultFramerateFps * 4 / 9),
1925 kErrorMargin);
1926
1927 // Go back up one step.
1928 vie_encoder_->TriggerCpuNormalUsage();
1929 num_frames_dropped = 0;
1930 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1931 timestamp_ms += kFrameIntervalMs;
1932 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1933 video_source_.IncomingCapturedFrame(
1934 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1935 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
1936 ++num_frames_dropped;
1937 } else {
1938 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
1939 }
1940 }
1941 EXPECT_NEAR(num_frames_dropped,
1942 kDefaultFramerateFps - (kDefaultFramerateFps * 2 / 3),
1943 kErrorMargin);
1944
1945 // Go back up to original mode.
1946 vie_encoder_->TriggerCpuNormalUsage();
1947 num_frames_dropped = 0;
1948 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1949 timestamp_ms += kFrameIntervalMs;
1950 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1951 video_source_.IncomingCapturedFrame(
1952 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1953 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
1954 ++num_frames_dropped;
1955 } else {
1956 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
1957 }
1958 }
1959 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
1960
1961 vie_encoder_->Stop();
1962}
1963
1964TEST_F(ViEEncoderTest, DoesntAdaptDownPastMinFramerate) {
1965 const int kFramerateFps = 5;
1966 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
1967 const int kMinFpsFrameInterval = rtc::kNumMillisecsPerSec / kMinFramerateFps;
1968 const int kFrameWidth = 1280;
1969 const int kFrameHeight = 720;
1970
1971 rtc::ScopedFakeClock fake_clock;
1972 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1973 vie_encoder_->SetSource(
1974 &video_source_,
1975 VideoSendStream::DegradationPreference::kMaintainResolution);
1976 video_source_.set_adaptation_enabled(true);
1977
1978 fake_clock.SetTimeMicros(kFrameIntervalMs * 1000);
1979 int64_t timestamp_ms = kFrameIntervalMs;
1980
1981 // Trigger overuse as much as we can.
1982 for (int i = 0; i < ViEEncoder::kMaxCpuResolutionDowngrades; ++i) {
1983 // Insert frames to get a new fps estimate...
1984 for (int j = 0; j < kFramerateFps; ++j) {
1985 video_source_.IncomingCapturedFrame(
1986 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1987 timestamp_ms += kFrameIntervalMs;
1988 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1989 }
1990 // ...and then try to adapt again.
1991 vie_encoder_->TriggerCpuOveruse();
1992 }
1993
1994 // Drain any frame in the pipeline.
1995 sink_.WaitForFrame(kDefaultTimeoutMs);
1996
1997 // Insert frames at min fps, all should go through.
1998 for (int i = 0; i < 10; ++i) {
1999 timestamp_ms += kMinFpsFrameInterval;
2000 fake_clock.AdvanceTimeMicros(kMinFpsFrameInterval * 1000);
2001 video_source_.IncomingCapturedFrame(
2002 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
2003 sink_.WaitForEncodedFrame(timestamp_ms);
2004 }
2005 vie_encoder_->Stop();
2006}
perkj26091b12016-09-01 01:17:40 -07002007} // namespace webrtc