blob: a5bc91474d4934b58f5111fa28ff515a2b710ec7 [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 {
32#if defined(WEBRTC_ANDROID)
33// TODO(kthelgason): Lower this limit when better testing
34// on MediaCodec and fallback implementations are in place.
35const int kMinPixelsPerFrame = 320 * 180;
36#else
37const int kMinPixelsPerFrame = 120 * 90;
38#endif
sprangc5d62e22017-04-02 23:53:04 -070039const int kMinFramerateFps = 2;
40const int64_t kFrameTimeoutMs = 100;
41} // namespace
kthelgason33ce8892016-12-09 03:53:59 -080042
perkj26091b12016-09-01 01:17:40 -070043namespace webrtc {
44
kthelgason876222f2016-11-29 01:44:11 -080045using DegredationPreference = VideoSendStream::DegradationPreference;
sprangb1ca0732017-02-01 08:38:12 -080046using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080047using ::testing::_;
48using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080049
perkj803d97f2016-11-01 11:45:46 -070050namespace {
asapersson5f7226f2016-11-25 04:37:00 -080051const size_t kMaxPayloadLength = 1440;
kthelgason2bc68642017-02-07 07:02:22 -080052const int kTargetBitrateBps = 1000000;
53const int kLowTargetBitrateBps = kTargetBitrateBps / 10;
54const int kMaxInitialFramedrop = 4;
asapersson5f7226f2016-11-25 04:37:00 -080055
perkj803d97f2016-11-01 11:45:46 -070056class TestBuffer : public webrtc::I420Buffer {
57 public:
58 TestBuffer(rtc::Event* event, int width, int height)
59 : I420Buffer(width, height), event_(event) {}
60
61 private:
62 friend class rtc::RefCountedObject<TestBuffer>;
63 ~TestBuffer() override {
64 if (event_)
65 event_->Set();
66 }
67 rtc::Event* const event_;
68};
69
70class ViEEncoderUnderTest : public ViEEncoder {
71 public:
kthelgason876222f2016-11-29 01:44:11 -080072 ViEEncoderUnderTest(SendStatisticsProxy* stats_proxy,
73 const VideoSendStream::Config::EncoderSettings& settings)
perkj803d97f2016-11-01 11:45:46 -070074 : ViEEncoder(1 /* number_of_cores */,
75 stats_proxy,
76 settings,
77 nullptr /* pre_encode_callback */,
78 nullptr /* encoder_timing */) {}
79
sprangb1ca0732017-02-01 08:38:12 -080080 void PostTaskAndWait(bool down, AdaptReason reason) {
perkj803d97f2016-11-01 11:45:46 -070081 rtc::Event event(false, false);
kthelgason876222f2016-11-29 01:44:11 -080082 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -080083 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -070084 event.Set();
85 });
perkj070ba852017-02-16 15:46:27 -080086 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -070087 }
88
kthelgason2fc52542017-03-03 00:24:41 -080089 // This is used as a synchronisation mechanism, to make sure that the
90 // encoder queue is not blocked before we start sending it frames.
91 void WaitUntilTaskQueueIsIdle() {
92 rtc::Event event(false, false);
93 encoder_queue()->PostTask([&event] {
94 event.Set();
95 });
96 ASSERT_TRUE(event.Wait(5000));
97 }
98
sprangb1ca0732017-02-01 08:38:12 -080099 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800100
sprangb1ca0732017-02-01 08:38:12 -0800101 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800102
sprangb1ca0732017-02-01 08:38:12 -0800103 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800104
sprangb1ca0732017-02-01 08:38:12 -0800105 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
perkj803d97f2016-11-01 11:45:46 -0700106};
107
asapersson5f7226f2016-11-25 04:37:00 -0800108class VideoStreamFactory
109 : public VideoEncoderConfig::VideoStreamFactoryInterface {
110 public:
111 explicit VideoStreamFactory(size_t num_temporal_layers)
112 : num_temporal_layers_(num_temporal_layers) {
113 EXPECT_GT(num_temporal_layers, 0u);
114 }
115
116 private:
117 std::vector<VideoStream> CreateEncoderStreams(
118 int width,
119 int height,
120 const VideoEncoderConfig& encoder_config) override {
121 std::vector<VideoStream> streams =
122 test::CreateVideoStreams(width, height, encoder_config);
123 for (VideoStream& stream : streams) {
124 stream.temporal_layer_thresholds_bps.resize(num_temporal_layers_ - 1);
125 }
126 return streams;
127 }
128 const size_t num_temporal_layers_;
129};
130
sprangb1ca0732017-02-01 08:38:12 -0800131class AdaptingFrameForwarder : public test::FrameForwarder {
132 public:
133 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700134 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800135
136 void set_adaptation_enabled(bool enabled) {
137 rtc::CritScope cs(&crit_);
138 adaptation_enabled_ = enabled;
139 }
140
asaperssonfab67072017-04-04 05:51:49 -0700141 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800142 rtc::CritScope cs(&crit_);
143 return adaptation_enabled_;
144 }
145
146 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
147 int cropped_width = 0;
148 int cropped_height = 0;
149 int out_width = 0;
150 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700151 if (adaption_enabled()) {
152 if (adapter_.AdaptFrameResolution(
153 video_frame.width(), video_frame.height(),
154 video_frame.timestamp_us() * 1000, &cropped_width,
155 &cropped_height, &out_width, &out_height)) {
156 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
157 nullptr, out_width, out_height),
158 99, 99, kVideoRotation_0);
159 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
160 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
161 }
sprangb1ca0732017-02-01 08:38:12 -0800162 } else {
163 test::FrameForwarder::IncomingCapturedFrame(video_frame);
164 }
165 }
166
167 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
168 const rtc::VideoSinkWants& wants) override {
169 rtc::CritScope cs(&crit_);
sprangc5d62e22017-04-02 23:53:04 -0700170 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
171 wants.max_pixel_count,
172 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800173 test::FrameForwarder::AddOrUpdateSink(sink, wants);
174 }
175
176 cricket::VideoAdapter adapter_;
177 bool adaptation_enabled_ GUARDED_BY(crit_);
178};
sprangc5d62e22017-04-02 23:53:04 -0700179
180class MockableSendStatisticsProxy : public SendStatisticsProxy {
181 public:
182 MockableSendStatisticsProxy(Clock* clock,
183 const VideoSendStream::Config& config,
184 VideoEncoderConfig::ContentType content_type)
185 : SendStatisticsProxy(clock, config, content_type) {}
186
187 VideoSendStream::Stats GetStats() override {
188 rtc::CritScope cs(&lock_);
189 if (mock_stats_)
190 return *mock_stats_;
191 return SendStatisticsProxy::GetStats();
192 }
193
194 void SetMockStats(const VideoSendStream::Stats& stats) {
195 rtc::CritScope cs(&lock_);
196 mock_stats_.emplace(stats);
197 }
198
199 void ResetMockStats() {
200 rtc::CritScope cs(&lock_);
201 mock_stats_.reset();
202 }
203
204 private:
205 rtc::CriticalSection lock_;
206 rtc::Optional<VideoSendStream::Stats> mock_stats_ GUARDED_BY(lock_);
207};
208
perkj803d97f2016-11-01 11:45:46 -0700209} // namespace
210
perkj26091b12016-09-01 01:17:40 -0700211class ViEEncoderTest : public ::testing::Test {
212 public:
213 static const int kDefaultTimeoutMs = 30 * 1000;
214
215 ViEEncoderTest()
216 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700217 codec_width_(320),
218 codec_height_(240),
perkj26091b12016-09-01 01:17:40 -0700219 fake_encoder_(),
sprangc5d62e22017-04-02 23:53:04 -0700220 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700221 Clock::GetRealTimeClock(),
222 video_send_config_,
223 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700224 sink_(&fake_encoder_) {}
225
226 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700227 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700228 video_send_config_ = VideoSendStream::Config(nullptr);
229 video_send_config_.encoder_settings.encoder = &fake_encoder_;
230 video_send_config_.encoder_settings.payload_name = "FAKE";
231 video_send_config_.encoder_settings.payload_type = 125;
232
Per512ecb32016-09-23 15:52:06 +0200233 VideoEncoderConfig video_encoder_config;
perkjfa10b552016-10-02 23:45:26 -0700234 test::FillEncoderConfiguration(1, &video_encoder_config);
Erik Språng08127a92016-11-16 16:41:30 +0100235 video_encoder_config_ = video_encoder_config.Copy();
asapersson5f7226f2016-11-25 04:37:00 -0800236 ConfigureEncoder(std::move(video_encoder_config), true /* nack_enabled */);
237 }
238
239 void ConfigureEncoder(VideoEncoderConfig video_encoder_config,
240 bool nack_enabled) {
241 if (vie_encoder_)
242 vie_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700243 vie_encoder_.reset(new ViEEncoderUnderTest(
244 stats_proxy_.get(), video_send_config_.encoder_settings));
245 vie_encoder_->SetSink(&sink_, false /* rotation_applied */);
sprangc5d62e22017-04-02 23:53:04 -0700246 vie_encoder_->SetSource(
247 &video_source_,
248 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason2bc68642017-02-07 07:02:22 -0800249 vie_encoder_->SetStartBitrate(kTargetBitrateBps);
asapersson5f7226f2016-11-25 04:37:00 -0800250 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
251 kMaxPayloadLength, nack_enabled);
kthelgason2fc52542017-03-03 00:24:41 -0800252 vie_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800253 }
254
255 void ResetEncoder(const std::string& payload_name,
256 size_t num_streams,
257 size_t num_temporal_layers,
258 bool nack_enabled) {
259 video_send_config_.encoder_settings.payload_name = payload_name;
260
261 VideoEncoderConfig video_encoder_config;
262 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800263 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800264 video_encoder_config.video_stream_factory =
265 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers);
266 ConfigureEncoder(std::move(video_encoder_config), nack_enabled);
perkj26091b12016-09-01 01:17:40 -0700267 }
268
sprang57c2fff2017-01-16 06:24:02 -0800269 VideoFrame CreateFrame(int64_t ntp_time_ms,
270 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200271 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
272 destruction_event, codec_width_, codec_height_),
273 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800274 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700275 return frame;
276 }
277
sprang57c2fff2017-01-16 06:24:02 -0800278 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700279 VideoFrame frame(
280 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
281 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800282 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700283 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700284 return frame;
285 }
286
perkj26091b12016-09-01 01:17:40 -0700287 class TestEncoder : public test::FakeEncoder {
288 public:
289 TestEncoder()
290 : FakeEncoder(Clock::GetRealTimeClock()),
291 continue_encode_event_(false, false) {}
292
asaperssonfab67072017-04-04 05:51:49 -0700293 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800294 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700295 return config_;
296 }
297
298 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800299 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700300 block_next_encode_ = true;
301 }
302
kthelgason876222f2016-11-29 01:44:11 -0800303 VideoEncoder::ScalingSettings GetScalingSettings() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800304 rtc::CritScope lock(&local_crit_sect_);
kthelgasonad9010c2017-02-14 00:46:51 -0800305 if (quality_scaling_)
306 return VideoEncoder::ScalingSettings(true, 1, 2);
307 return VideoEncoder::ScalingSettings(false);
kthelgason876222f2016-11-29 01:44:11 -0800308 }
309
perkjfa10b552016-10-02 23:45:26 -0700310 void ContinueEncode() { continue_encode_event_.Set(); }
311
312 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
313 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800314 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700315 EXPECT_EQ(timestamp_, timestamp);
316 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
317 }
318
kthelgason2fc52542017-03-03 00:24:41 -0800319 void SetQualityScaling(bool b) {
320 rtc::CritScope lock(&local_crit_sect_);
321 quality_scaling_ = b;
322 }
kthelgasonad9010c2017-02-14 00:46:51 -0800323
sprangfe627f32017-03-29 08:24:59 -0700324 void ForceInitEncodeFailure(bool force_failure) {
325 rtc::CritScope lock(&local_crit_sect_);
326 force_init_encode_failed_ = force_failure;
327 }
328
perkjfa10b552016-10-02 23:45:26 -0700329 private:
perkj26091b12016-09-01 01:17:40 -0700330 int32_t Encode(const VideoFrame& input_image,
331 const CodecSpecificInfo* codec_specific_info,
332 const std::vector<FrameType>* frame_types) override {
333 bool block_encode;
334 {
brandtre78d2662017-01-16 05:57:16 -0800335 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700336 EXPECT_GT(input_image.timestamp(), timestamp_);
337 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
338 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
339
340 timestamp_ = input_image.timestamp();
341 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700342 last_input_width_ = input_image.width();
343 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700344 block_encode = block_next_encode_;
345 block_next_encode_ = false;
346 }
347 int32_t result =
348 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
349 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700350 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700351 return result;
352 }
353
sprangfe627f32017-03-29 08:24:59 -0700354 int32_t InitEncode(const VideoCodec* config,
355 int32_t number_of_cores,
356 size_t max_payload_size) override {
357 int res =
358 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
359 rtc::CritScope lock(&local_crit_sect_);
360 if (config->codecType == kVideoCodecVP8 && config->VP8().tl_factory) {
361 // Simulate setting up temporal layers, in order to validate the life
362 // cycle of these objects.
363 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
364 int num_temporal_layers =
365 std::max<int>(1, config->VP8().numberOfTemporalLayers);
366 for (int i = 0; i < num_streams; ++i) {
367 allocated_temporal_layers_.emplace_back(
368 config->VP8().tl_factory->Create(i, num_temporal_layers, 42));
369 }
370 }
371 if (force_init_encode_failed_)
372 return -1;
373 return res;
374 }
375
brandtre78d2662017-01-16 05:57:16 -0800376 rtc::CriticalSection local_crit_sect_;
sprangfe627f32017-03-29 08:24:59 -0700377 bool block_next_encode_ GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700378 rtc::Event continue_encode_event_;
sprangfe627f32017-03-29 08:24:59 -0700379 uint32_t timestamp_ GUARDED_BY(local_crit_sect_) = 0;
380 int64_t ntp_time_ms_ GUARDED_BY(local_crit_sect_) = 0;
381 int last_input_width_ GUARDED_BY(local_crit_sect_) = 0;
382 int last_input_height_ GUARDED_BY(local_crit_sect_) = 0;
383 bool quality_scaling_ GUARDED_BY(local_crit_sect_) = true;
384 std::vector<std::unique_ptr<TemporalLayers>> allocated_temporal_layers_
385 GUARDED_BY(local_crit_sect_);
386 bool force_init_encode_failed_ GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700387 };
388
Per512ecb32016-09-23 15:52:06 +0200389 class TestSink : public ViEEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700390 public:
391 explicit TestSink(TestEncoder* test_encoder)
392 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
393
perkj26091b12016-09-01 01:17:40 -0700394 void WaitForEncodedFrame(int64_t expected_ntp_time) {
395 uint32_t timestamp = 0;
perkja49cbd32016-09-16 07:53:41 -0700396 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700397 {
398 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800399 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700400 }
401 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
402 }
403
sprangb1ca0732017-02-01 08:38:12 -0800404 void WaitForEncodedFrame(uint32_t expected_width,
405 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700406 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
407 CheckLastFrameSizeMathces(expected_width, expected_height);
408 }
409
410 void CheckLastFrameSizeMathces(uint32_t expected_width,
411 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800412 uint32_t width = 0;
413 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800414 {
415 rtc::CritScope lock(&crit_);
416 width = last_width_;
417 height = last_height_;
418 }
419 EXPECT_EQ(expected_height, height);
420 EXPECT_EQ(expected_width, width);
421 }
422
kthelgason2fc52542017-03-03 00:24:41 -0800423 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800424
sprangc5d62e22017-04-02 23:53:04 -0700425 bool WaitForFrame(int64_t timeout_ms) {
426 return encoded_frame_event_.Wait(timeout_ms);
427 }
428
perkj26091b12016-09-01 01:17:40 -0700429 void SetExpectNoFrames() {
430 rtc::CritScope lock(&crit_);
431 expect_frames_ = false;
432 }
433
asaperssonfab67072017-04-04 05:51:49 -0700434 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200435 rtc::CritScope lock(&crit_);
436 return number_of_reconfigurations_;
437 }
438
asaperssonfab67072017-04-04 05:51:49 -0700439 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200440 rtc::CritScope lock(&crit_);
441 return min_transmit_bitrate_bps_;
442 }
443
perkj26091b12016-09-01 01:17:40 -0700444 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700445 Result OnEncodedImage(
446 const EncodedImage& encoded_image,
447 const CodecSpecificInfo* codec_specific_info,
448 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200449 rtc::CritScope lock(&crit_);
450 EXPECT_TRUE(expect_frames_);
sprangb1ca0732017-02-01 08:38:12 -0800451 last_timestamp_ = encoded_image._timeStamp;
452 last_width_ = encoded_image._encodedWidth;
453 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200454 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800455 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200456 }
457
458 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
459 int min_transmit_bitrate_bps) override {
460 rtc::CriticalSection crit_;
461 ++number_of_reconfigurations_;
462 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
463 }
464
perkj26091b12016-09-01 01:17:40 -0700465 rtc::CriticalSection crit_;
466 TestEncoder* test_encoder_;
467 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800468 uint32_t last_timestamp_ = 0;
469 uint32_t last_height_ = 0;
470 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700471 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200472 int number_of_reconfigurations_ = 0;
473 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700474 };
475
476 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100477 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200478 int codec_width_;
479 int codec_height_;
perkj26091b12016-09-01 01:17:40 -0700480 TestEncoder fake_encoder_;
sprangc5d62e22017-04-02 23:53:04 -0700481 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700482 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800483 AdaptingFrameForwarder video_source_;
perkj803d97f2016-11-01 11:45:46 -0700484 std::unique_ptr<ViEEncoderUnderTest> vie_encoder_;
perkj26091b12016-09-01 01:17:40 -0700485};
486
487TEST_F(ViEEncoderTest, EncodeOneFrame) {
perkj26091b12016-09-01 01:17:40 -0700488 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
489 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700490 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
perkj26091b12016-09-01 01:17:40 -0700491 sink_.WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700492 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700493 vie_encoder_->Stop();
494}
495
496TEST_F(ViEEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
497 // Dropped since no target bitrate has been set.
498 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700499 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
500 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700501
perkj26091b12016-09-01 01:17:40 -0700502 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
503
perkja49cbd32016-09-16 07:53:41 -0700504 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkj26091b12016-09-01 01:17:40 -0700505 sink_.WaitForEncodedFrame(2);
506 vie_encoder_->Stop();
507}
508
509TEST_F(ViEEncoderTest, DropsFramesWhenRateSetToZero) {
perkj26091b12016-09-01 01:17:40 -0700510 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700511 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700512 sink_.WaitForEncodedFrame(1);
513
514 vie_encoder_->OnBitrateUpdated(0, 0, 0);
515 // Dropped since bitrate is zero.
perkja49cbd32016-09-16 07:53:41 -0700516 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkj26091b12016-09-01 01:17:40 -0700517
518 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700519 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700520 sink_.WaitForEncodedFrame(3);
521 vie_encoder_->Stop();
522}
523
524TEST_F(ViEEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
perkj26091b12016-09-01 01:17:40 -0700525 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700526 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700527 sink_.WaitForEncodedFrame(1);
528
529 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700530 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700531
perkja49cbd32016-09-16 07:53:41 -0700532 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkj26091b12016-09-01 01:17:40 -0700533 sink_.WaitForEncodedFrame(2);
534 vie_encoder_->Stop();
535}
536
537TEST_F(ViEEncoderTest, DropsFrameAfterStop) {
perkj26091b12016-09-01 01:17:40 -0700538 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
539
perkja49cbd32016-09-16 07:53:41 -0700540 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700541 sink_.WaitForEncodedFrame(1);
542
543 vie_encoder_->Stop();
544 sink_.SetExpectNoFrames();
545 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700546 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
547 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700548}
549
550TEST_F(ViEEncoderTest, DropsPendingFramesOnSlowEncode) {
perkj26091b12016-09-01 01:17:40 -0700551 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
552
553 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700554 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700555 sink_.WaitForEncodedFrame(1);
556 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
557 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700558 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
559 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700560 fake_encoder_.ContinueEncode();
561 sink_.WaitForEncodedFrame(3);
562
563 vie_encoder_->Stop();
564}
565
Per512ecb32016-09-23 15:52:06 +0200566TEST_F(ViEEncoderTest, ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
Per512ecb32016-09-23 15:52:06 +0200567 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100568 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200569
570 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200571 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
Per512ecb32016-09-23 15:52:06 +0200572 sink_.WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100573 // The encoder will have been configured once when the first frame is
574 // received.
575 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200576
577 VideoEncoderConfig video_encoder_config;
perkjfa10b552016-10-02 23:45:26 -0700578 test::FillEncoderConfiguration(1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200579 video_encoder_config.min_transmit_bitrate_bps = 9999;
asapersson5f7226f2016-11-25 04:37:00 -0800580 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
581 kMaxPayloadLength, true /* nack_enabled */);
Per512ecb32016-09-23 15:52:06 +0200582
583 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200584 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Per512ecb32016-09-23 15:52:06 +0200585 sink_.WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100586 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700587 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700588
589 vie_encoder_->Stop();
590}
591
perkjfa10b552016-10-02 23:45:26 -0700592TEST_F(ViEEncoderTest, FrameResolutionChangeReconfigureEncoder) {
perkjfa10b552016-10-02 23:45:26 -0700593 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
594
595 // Capture a frame and wait for it to synchronize with the encoder thread.
596 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
597 sink_.WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100598 // The encoder will have been configured once.
599 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700600 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
601 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
602
603 codec_width_ *= 2;
604 codec_height_ *= 2;
605 // Capture a frame with a higher resolution and wait for it to synchronize
606 // with the encoder thread.
607 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
608 sink_.WaitForEncodedFrame(2);
609 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
610 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100611 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700612
613 vie_encoder_->Stop();
614}
615
asapersson5f7226f2016-11-25 04:37:00 -0800616TEST_F(ViEEncoderTest, Vp8ResilienceIsOffFor1S1TLWithNackEnabled) {
617 const bool kNackEnabled = true;
618 const size_t kNumStreams = 1;
619 const size_t kNumTl = 1;
asaperssona90799d2016-12-09 02:35:20 -0800620 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800621 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
622
623 // Capture a frame and wait for it to synchronize with the encoder thread.
624 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
625 sink_.WaitForEncodedFrame(1);
626 // The encoder have been configured once when the first frame is received.
627 EXPECT_EQ(1, sink_.number_of_reconfigurations());
628 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
629 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
630 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
631 // Resilience is off for no temporal layers with nack on.
632 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
633 vie_encoder_->Stop();
634}
635
636TEST_F(ViEEncoderTest, Vp8ResilienceIsOffFor2S1TlWithNackEnabled) {
637 const bool kNackEnabled = true;
638 const size_t kNumStreams = 2;
639 const size_t kNumTl = 1;
asaperssona90799d2016-12-09 02:35:20 -0800640 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800641 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
642
643 // Capture a frame and wait for it to synchronize with the encoder thread.
644 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
645 sink_.WaitForEncodedFrame(1);
646 // The encoder have been configured once when the first frame is received.
647 EXPECT_EQ(1, sink_.number_of_reconfigurations());
648 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
649 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
650 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
651 // Resilience is off for no temporal layers and >1 streams with nack on.
652 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
653 vie_encoder_->Stop();
654}
655
656TEST_F(ViEEncoderTest, Vp8ResilienceIsOnFor1S1TLWithNackDisabled) {
657 const bool kNackEnabled = false;
658 const size_t kNumStreams = 1;
659 const size_t kNumTl = 1;
asaperssona90799d2016-12-09 02:35:20 -0800660 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800661 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
662
663 // Capture a frame and wait for it to synchronize with the encoder thread.
664 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
665 sink_.WaitForEncodedFrame(1);
666 // The encoder have been configured once when the first frame is received.
667 EXPECT_EQ(1, sink_.number_of_reconfigurations());
668 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
669 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
670 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
671 // Resilience is on for no temporal layers with nack off.
672 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
673 vie_encoder_->Stop();
674}
675
676TEST_F(ViEEncoderTest, Vp8ResilienceIsOnFor1S2TlWithNackEnabled) {
677 const bool kNackEnabled = true;
678 const size_t kNumStreams = 1;
679 const size_t kNumTl = 2;
asaperssona90799d2016-12-09 02:35:20 -0800680 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800681 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
682
683 // Capture a frame and wait for it to synchronize with the encoder thread.
684 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
685 sink_.WaitForEncodedFrame(1);
686 // The encoder have been configured once when the first frame is received.
687 EXPECT_EQ(1, sink_.number_of_reconfigurations());
688 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
689 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
690 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
691 // Resilience is on for temporal layers.
692 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
693 vie_encoder_->Stop();
694}
695
perkj803d97f2016-11-01 11:45:46 -0700696TEST_F(ViEEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
697 EXPECT_TRUE(video_source_.has_sinks());
698 test::FrameForwarder new_video_source;
sprangc5d62e22017-04-02 23:53:04 -0700699 vie_encoder_->SetSource(
700 &new_video_source,
701 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -0700702 EXPECT_FALSE(video_source_.has_sinks());
703 EXPECT_TRUE(new_video_source.has_sinks());
704
705 vie_encoder_->Stop();
706}
707
708TEST_F(ViEEncoderTest, SinkWantsRotationApplied) {
709 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
710 vie_encoder_->SetSink(&sink_, true /*rotation_applied*/);
711 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
712 vie_encoder_->Stop();
713}
714
715TEST_F(ViEEncoderTest, SinkWantsFromOveruseDetector) {
perkj803d97f2016-11-01 11:45:46 -0700716 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
717
sprang84a37592017-02-10 07:04:27 -0800718 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700719 EXPECT_EQ(std::numeric_limits<int>::max(),
720 video_source_.sink_wants().max_pixel_count);
perkj803d97f2016-11-01 11:45:46 -0700721
722 int frame_width = 1280;
723 int frame_height = 720;
724
725 // Trigger CPU overuse kMaxCpuDowngrades times. Every time, ViEEncoder should
726 // request lower resolution.
sprangc5d62e22017-04-02 23:53:04 -0700727 for (int i = 1; i <= ViEEncoder::kMaxCpuResolutionDowngrades; ++i) {
perkj803d97f2016-11-01 11:45:46 -0700728 video_source_.IncomingCapturedFrame(
729 CreateFrame(i, frame_width, frame_height));
730 sink_.WaitForEncodedFrame(i);
731
732 vie_encoder_->TriggerCpuOveruse();
733
sprang84a37592017-02-10 07:04:27 -0800734 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700735 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
perkj803d97f2016-11-01 11:45:46 -0700736 frame_width * frame_height);
perkj803d97f2016-11-01 11:45:46 -0700737
738 frame_width /= 2;
739 frame_height /= 2;
740 }
741
kthelgason876222f2016-11-29 01:44:11 -0800742 // Trigger CPU overuse one more time. This should not trigger a request for
perkj803d97f2016-11-01 11:45:46 -0700743 // lower resolution.
744 rtc::VideoSinkWants current_wants = video_source_.sink_wants();
745 video_source_.IncomingCapturedFrame(CreateFrame(
sprangc5d62e22017-04-02 23:53:04 -0700746 ViEEncoder::kMaxCpuResolutionDowngrades + 1, frame_width, frame_height));
747 sink_.WaitForEncodedFrame(ViEEncoder::kMaxCpuResolutionDowngrades + 1);
perkj803d97f2016-11-01 11:45:46 -0700748 vie_encoder_->TriggerCpuOveruse();
sprang84a37592017-02-10 07:04:27 -0800749 EXPECT_EQ(video_source_.sink_wants().target_pixel_count,
750 current_wants.target_pixel_count);
perkj803d97f2016-11-01 11:45:46 -0700751 EXPECT_EQ(video_source_.sink_wants().max_pixel_count,
752 current_wants.max_pixel_count);
perkj803d97f2016-11-01 11:45:46 -0700753
754 // Trigger CPU normal use.
755 vie_encoder_->TriggerCpuNormalUsage();
sprang84a37592017-02-10 07:04:27 -0800756 EXPECT_EQ(frame_width * frame_height * 5 / 3,
757 video_source_.sink_wants().target_pixel_count.value_or(0));
758 EXPECT_EQ(frame_width * frame_height * 4,
sprangc5d62e22017-04-02 23:53:04 -0700759 video_source_.sink_wants().max_pixel_count);
perkj803d97f2016-11-01 11:45:46 -0700760
761 vie_encoder_->Stop();
762}
763
sprangc5d62e22017-04-02 23:53:04 -0700764TEST_F(ViEEncoderTest, SinkWantsStoredByDegradationPreference) {
perkj803d97f2016-11-01 11:45:46 -0700765 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
766
sprang84a37592017-02-10 07:04:27 -0800767 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700768 EXPECT_EQ(std::numeric_limits<int>::max(),
769 video_source_.sink_wants().max_pixel_count);
770 EXPECT_EQ(std::numeric_limits<int>::max(),
771 video_source_.sink_wants().max_framerate_fps);
perkj803d97f2016-11-01 11:45:46 -0700772
sprangc5d62e22017-04-02 23:53:04 -0700773 const int kFrameWidth = 1280;
774 const int kFrameHeight = 720;
775 const int kFrameIntervalMs = 1000 / 30;
776
777 int frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -0700778
kthelgason5e13d412016-12-01 03:59:51 -0800779 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700780 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
781 sink_.WaitForEncodedFrame(frame_timestamp);
782 frame_timestamp += kFrameIntervalMs;
783
perkj803d97f2016-11-01 11:45:46 -0700784 // Trigger CPU overuse.
785 vie_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700786 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700787 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
788 sink_.WaitForEncodedFrame(frame_timestamp);
789 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -0700790
sprangc5d62e22017-04-02 23:53:04 -0700791 // Default degradation preference in maintain-framerate, so will lower max
792 // wanted resolution.
793 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
794 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
795 kFrameWidth * kFrameHeight);
796 EXPECT_EQ(std::numeric_limits<int>::max(),
797 video_source_.sink_wants().max_framerate_fps);
798
799 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -0700800 test::FrameForwarder new_video_source;
801 vie_encoder_->SetSource(
802 &new_video_source,
803 VideoSendStream::DegradationPreference::kMaintainResolution);
804
sprangc5d62e22017-04-02 23:53:04 -0700805 // Initially no degradation registered.
sprang84a37592017-02-10 07:04:27 -0800806 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700807 EXPECT_EQ(std::numeric_limits<int>::max(),
808 new_video_source.sink_wants().max_pixel_count);
809 EXPECT_EQ(std::numeric_limits<int>::max(),
810 new_video_source.sink_wants().max_framerate_fps);
perkj803d97f2016-11-01 11:45:46 -0700811
sprangc5d62e22017-04-02 23:53:04 -0700812 // Force an input frame rate to be available, or the adaptation call won't
813 // know what framerate to adapt form.
814 VideoSendStream::Stats stats = stats_proxy_->GetStats();
815 stats.input_frame_rate = 30;
816 stats_proxy_->SetMockStats(stats);
817
818 vie_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700819 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700820 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
821 sink_.WaitForEncodedFrame(frame_timestamp);
822 frame_timestamp += kFrameIntervalMs;
823
824 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -0800825 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700826 EXPECT_EQ(std::numeric_limits<int>::max(),
827 new_video_source.sink_wants().max_pixel_count);
828 EXPECT_TRUE(new_video_source.sink_wants().max_framerate_fps);
829
830 // Turn of degradation completely.
831 vie_encoder_->SetSource(
832 &new_video_source,
833 VideoSendStream::DegradationPreference::kDegradationDisabled);
834
835 // Initially no degradation registered.
836 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
837 EXPECT_EQ(std::numeric_limits<int>::max(),
838 new_video_source.sink_wants().max_pixel_count);
839 EXPECT_EQ(std::numeric_limits<int>::max(),
840 new_video_source.sink_wants().max_framerate_fps);
841
842 vie_encoder_->TriggerCpuOveruse();
843 new_video_source.IncomingCapturedFrame(
844 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
845 sink_.WaitForEncodedFrame(frame_timestamp);
846 frame_timestamp += kFrameIntervalMs;
847
848 // Still no degradation.
849 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
850 EXPECT_EQ(std::numeric_limits<int>::max(),
851 new_video_source.sink_wants().max_pixel_count);
852 EXPECT_EQ(std::numeric_limits<int>::max(),
853 new_video_source.sink_wants().max_framerate_fps);
perkj803d97f2016-11-01 11:45:46 -0700854
855 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
sprangc5d62e22017-04-02 23:53:04 -0700856 vie_encoder_->SetSource(
857 &new_video_source,
858 VideoSendStream::DegradationPreference::kMaintainFramerate);
859 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
860 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -0800861 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700862 EXPECT_EQ(std::numeric_limits<int>::max(),
863 new_video_source.sink_wants().max_framerate_fps);
864
865 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
866 vie_encoder_->SetSource(
867 &new_video_source,
868 VideoSendStream::DegradationPreference::kMaintainResolution);
869 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
870 EXPECT_EQ(std::numeric_limits<int>::max(),
871 new_video_source.sink_wants().max_pixel_count);
872 EXPECT_TRUE(new_video_source.sink_wants().max_framerate_fps);
perkj803d97f2016-11-01 11:45:46 -0700873
874 vie_encoder_->Stop();
875}
876
asaperssonfab67072017-04-04 05:51:49 -0700877TEST_F(ViEEncoderTest, StatsTracksQualityAdaptationStats) {
perkj803d97f2016-11-01 11:45:46 -0700878 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
879
asaperssonfab67072017-04-04 05:51:49 -0700880 const int kWidth = 1280;
881 const int kHeight = 720;
perkj803d97f2016-11-01 11:45:46 -0700882
asaperssonfab67072017-04-04 05:51:49 -0700883 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
884 sink_.WaitForEncodedFrame(1);
885 VideoSendStream::Stats stats = stats_proxy_->GetStats();
886 EXPECT_FALSE(stats.bw_limited_resolution);
887 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
888
889 // Trigger adapt down.
890 vie_encoder_->TriggerQualityLow();
891 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
892 sink_.WaitForEncodedFrame(2);
893
894 stats = stats_proxy_->GetStats();
895 EXPECT_TRUE(stats.bw_limited_resolution);
896 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
897
898 // Trigger adapt up.
899 vie_encoder_->TriggerQualityHigh();
900 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
901 sink_.WaitForEncodedFrame(3);
902
903 stats = stats_proxy_->GetStats();
904 EXPECT_FALSE(stats.bw_limited_resolution);
905 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
906 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
907
908 vie_encoder_->Stop();
909}
910
911TEST_F(ViEEncoderTest, StatsTracksCpuAdaptationStats) {
912 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
913
914 const int kWidth = 1280;
915 const int kHeight = 720;
916
917 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
perkj803d97f2016-11-01 11:45:46 -0700918 sink_.WaitForEncodedFrame(1);
919 VideoSendStream::Stats stats = stats_proxy_->GetStats();
920 EXPECT_FALSE(stats.cpu_limited_resolution);
921 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
922
923 // Trigger CPU overuse.
924 vie_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -0700925 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
perkj803d97f2016-11-01 11:45:46 -0700926 sink_.WaitForEncodedFrame(2);
927
928 stats = stats_proxy_->GetStats();
929 EXPECT_TRUE(stats.cpu_limited_resolution);
930 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
931
932 // Trigger CPU normal use.
933 vie_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -0700934 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
perkj803d97f2016-11-01 11:45:46 -0700935 sink_.WaitForEncodedFrame(3);
936
937 stats = stats_proxy_->GetStats();
938 EXPECT_FALSE(stats.cpu_limited_resolution);
939 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -0700940 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -0700941
942 vie_encoder_->Stop();
943}
944
kthelgason876222f2016-11-29 01:44:11 -0800945TEST_F(ViEEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
kthelgason876222f2016-11-29 01:44:11 -0800946 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
947
asaperssonfab67072017-04-04 05:51:49 -0700948 const int kWidth = 1280;
949 const int kHeight = 720;
950 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -0800951 sink_.WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -0800952 VideoSendStream::Stats stats = stats_proxy_->GetStats();
953 EXPECT_FALSE(stats.cpu_limited_resolution);
954 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
955
asaperssonfab67072017-04-04 05:51:49 -0700956 // Trigger CPU overuse.
kthelgason876222f2016-11-29 01:44:11 -0800957 vie_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -0700958 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -0800959 sink_.WaitForEncodedFrame(2);
960 stats = stats_proxy_->GetStats();
961 EXPECT_TRUE(stats.cpu_limited_resolution);
962 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
963
964 // Set new source with adaptation still enabled.
965 test::FrameForwarder new_video_source;
sprangc5d62e22017-04-02 23:53:04 -0700966 vie_encoder_->SetSource(
967 &new_video_source,
968 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -0800969
asaperssonfab67072017-04-04 05:51:49 -0700970 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -0800971 sink_.WaitForEncodedFrame(3);
972 stats = stats_proxy_->GetStats();
973 EXPECT_TRUE(stats.cpu_limited_resolution);
974 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
975
976 // Set adaptation disabled.
977 vie_encoder_->SetSource(
978 &new_video_source,
sprangc5d62e22017-04-02 23:53:04 -0700979 VideoSendStream::DegradationPreference::kDegradationDisabled);
kthelgason876222f2016-11-29 01:44:11 -0800980
asaperssonfab67072017-04-04 05:51:49 -0700981 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -0800982 sink_.WaitForEncodedFrame(4);
983 stats = stats_proxy_->GetStats();
984 EXPECT_FALSE(stats.cpu_limited_resolution);
985 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
986
987 // Set adaptation back to enabled.
sprangc5d62e22017-04-02 23:53:04 -0700988 vie_encoder_->SetSource(
989 &new_video_source,
990 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -0800991
asaperssonfab67072017-04-04 05:51:49 -0700992 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -0800993 sink_.WaitForEncodedFrame(5);
994 stats = stats_proxy_->GetStats();
995 EXPECT_TRUE(stats.cpu_limited_resolution);
996 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
997
asaperssonfab67072017-04-04 05:51:49 -0700998 // Trigger CPU normal use.
kthelgason876222f2016-11-29 01:44:11 -0800999 vie_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001000 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -08001001 sink_.WaitForEncodedFrame(6);
1002 stats = stats_proxy_->GetStats();
1003 EXPECT_FALSE(stats.cpu_limited_resolution);
1004 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1005
1006 vie_encoder_->Stop();
1007}
1008
1009TEST_F(ViEEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
kthelgason876222f2016-11-29 01:44:11 -08001010 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1011
asaperssonfab67072017-04-04 05:51:49 -07001012 const int kWidth = 1280;
1013 const int kHeight = 720;
1014 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -08001015 sink_.WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001016 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1017 EXPECT_FALSE(stats.cpu_limited_resolution);
1018 EXPECT_FALSE(stats.bw_limited_resolution);
asaperssonfab67072017-04-04 05:51:49 -07001019 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001020
1021 // Set new source with adaptation still enabled.
1022 test::FrameForwarder new_video_source;
1023 vie_encoder_->SetSource(&new_video_source,
1024 VideoSendStream::DegradationPreference::kBalanced);
1025
asaperssonfab67072017-04-04 05:51:49 -07001026 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -08001027 sink_.WaitForEncodedFrame(2);
1028 stats = stats_proxy_->GetStats();
1029 EXPECT_FALSE(stats.cpu_limited_resolution);
1030 EXPECT_FALSE(stats.bw_limited_resolution);
asaperssonfab67072017-04-04 05:51:49 -07001031 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001032
asaperssonfab67072017-04-04 05:51:49 -07001033 // Trigger adapt down.
kthelgason876222f2016-11-29 01:44:11 -08001034 vie_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001035 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -08001036 sink_.WaitForEncodedFrame(3);
1037 stats = stats_proxy_->GetStats();
1038 EXPECT_FALSE(stats.cpu_limited_resolution);
1039 EXPECT_TRUE(stats.bw_limited_resolution);
asaperssonfab67072017-04-04 05:51:49 -07001040 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001041
asaperssonfab67072017-04-04 05:51:49 -07001042 // Set new source with adaptation still enabled.
kthelgason876222f2016-11-29 01:44:11 -08001043 vie_encoder_->SetSource(&new_video_source,
1044 VideoSendStream::DegradationPreference::kBalanced);
1045
asaperssonfab67072017-04-04 05:51:49 -07001046 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -08001047 sink_.WaitForEncodedFrame(4);
1048 stats = stats_proxy_->GetStats();
1049 EXPECT_FALSE(stats.cpu_limited_resolution);
1050 EXPECT_TRUE(stats.bw_limited_resolution);
asaperssonfab67072017-04-04 05:51:49 -07001051 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001052
1053 // Set adaptation disabled.
1054 vie_encoder_->SetSource(
1055 &new_video_source,
1056 VideoSendStream::DegradationPreference::kMaintainResolution);
1057
asaperssonfab67072017-04-04 05:51:49 -07001058 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -08001059 sink_.WaitForEncodedFrame(5);
1060 stats = stats_proxy_->GetStats();
1061 EXPECT_FALSE(stats.cpu_limited_resolution);
1062 EXPECT_FALSE(stats.bw_limited_resolution);
asaperssonfab67072017-04-04 05:51:49 -07001063 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1064 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001065
1066 vie_encoder_->Stop();
1067}
1068
asapersson36e9eb42017-03-31 05:29:12 -07001069TEST_F(ViEEncoderTest, QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1070 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1071
1072 const int kWidth = 1280;
1073 const int kHeight = 720;
1074 video_source_.set_adaptation_enabled(true);
1075 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1076 sink_.WaitForEncodedFrame(1);
1077 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1078 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1079 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1080
1081 // Trigger adapt down.
1082 vie_encoder_->TriggerQualityLow();
1083 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1084 sink_.WaitForEncodedFrame(2);
1085 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1086 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1087 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1088
1089 // Trigger overuse.
1090 vie_encoder_->TriggerCpuOveruse();
1091 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1092 sink_.WaitForEncodedFrame(3);
1093 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1094 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1095 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1096
1097 // Set source with adaptation still enabled but quality scaler is off.
1098 fake_encoder_.SetQualityScaling(false);
sprangc5d62e22017-04-02 23:53:04 -07001099 vie_encoder_->SetSource(
1100 &video_source_,
1101 VideoSendStream::DegradationPreference::kMaintainFramerate);
asapersson36e9eb42017-03-31 05:29:12 -07001102
1103 video_source_.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
1104 sink_.WaitForEncodedFrame(4);
1105 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1106 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1107 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1108
1109 vie_encoder_->Stop();
1110}
1111
perkj803d97f2016-11-01 11:45:46 -07001112TEST_F(ViEEncoderTest, StatsTracksAdaptationStatsWhenSwitchingSource) {
perkj803d97f2016-11-01 11:45:46 -07001113 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1114
asaperssonfab67072017-04-04 05:51:49 -07001115 int kWidth = 1280;
1116 int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001117 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001118
asaperssonfab67072017-04-04 05:51:49 -07001119 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang84a37592017-02-10 07:04:27 -08001120 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001121
1122 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001123 EXPECT_FALSE(stats.cpu_limited_resolution);
1124 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1125
1126 // Trigger CPU overuse again, should now adapt down.
1127 vie_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001128 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang84a37592017-02-10 07:04:27 -08001129 sink_.WaitForEncodedFrame(sequence++);
1130
1131 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001132 EXPECT_TRUE(stats.cpu_limited_resolution);
1133 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1134
1135 // Set new source with adaptation still enabled.
1136 test::FrameForwarder new_video_source;
sprangc5d62e22017-04-02 23:53:04 -07001137 vie_encoder_->SetSource(
1138 &new_video_source,
1139 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001140
1141 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001142 CreateFrame(sequence, kWidth, kHeight));
sprang84a37592017-02-10 07:04:27 -08001143 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001144 stats = stats_proxy_->GetStats();
1145 EXPECT_TRUE(stats.cpu_limited_resolution);
1146 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1147
sprangc5d62e22017-04-02 23:53:04 -07001148 // Set cpu adaptation by frame dropping.
perkj803d97f2016-11-01 11:45:46 -07001149 vie_encoder_->SetSource(
1150 &new_video_source,
1151 VideoSendStream::DegradationPreference::kMaintainResolution);
1152 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001153 CreateFrame(sequence, kWidth, kHeight));
sprang84a37592017-02-10 07:04:27 -08001154 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001155 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001156 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001157 EXPECT_FALSE(stats.cpu_limited_resolution);
1158 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1159
sprangc5d62e22017-04-02 23:53:04 -07001160 // Force an input frame rate to be available, or the adaptation call won't
1161 // know what framerate to adapt form.
1162 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1163 mock_stats.input_frame_rate = 30;
1164 stats_proxy_->SetMockStats(mock_stats);
1165 vie_encoder_->TriggerCpuOveruse();
1166 stats_proxy_->ResetMockStats();
1167
1168 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001169 CreateFrame(sequence, kWidth, kHeight));
sprangc5d62e22017-04-02 23:53:04 -07001170 sink_.WaitForEncodedFrame(sequence++);
1171
1172 // Framerate now adapted.
1173 stats = stats_proxy_->GetStats();
1174 EXPECT_TRUE(stats.cpu_limited_resolution);
1175 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1176
1177 // Disable CPU adaptation.
1178 vie_encoder_->SetSource(
1179 &new_video_source,
1180 VideoSendStream::DegradationPreference::kDegradationDisabled);
1181 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001182 CreateFrame(sequence, kWidth, kHeight));
sprangc5d62e22017-04-02 23:53:04 -07001183 sink_.WaitForEncodedFrame(sequence++);
1184
1185 stats = stats_proxy_->GetStats();
1186 EXPECT_FALSE(stats.cpu_limited_resolution);
1187 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1188
1189 // Try to trigger overuse. Should not succeed.
1190 stats_proxy_->SetMockStats(mock_stats);
1191 vie_encoder_->TriggerCpuOveruse();
1192 stats_proxy_->ResetMockStats();
1193
1194 stats = stats_proxy_->GetStats();
1195 EXPECT_FALSE(stats.cpu_limited_resolution);
1196 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1197
1198 // Switch back the source with resolution adaptation enabled.
1199 vie_encoder_->SetSource(
1200 &video_source_,
1201 VideoSendStream::DegradationPreference::kMaintainFramerate);
asaperssonfab67072017-04-04 05:51:49 -07001202 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang84a37592017-02-10 07:04:27 -08001203 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001204 stats = stats_proxy_->GetStats();
1205 EXPECT_TRUE(stats.cpu_limited_resolution);
sprangc5d62e22017-04-02 23:53:04 -07001206 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001207
1208 // Trigger CPU normal usage.
1209 vie_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001210 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang84a37592017-02-10 07:04:27 -08001211 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001212 stats = stats_proxy_->GetStats();
1213 EXPECT_FALSE(stats.cpu_limited_resolution);
sprangc5d62e22017-04-02 23:53:04 -07001214 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1215
1216 // Back to the source with adaptation off, set it back to maintain-resolution.
1217 vie_encoder_->SetSource(
1218 &new_video_source,
1219 VideoSendStream::DegradationPreference::kMaintainResolution);
1220 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001221 CreateFrame(sequence, kWidth, kHeight));
sprangc5d62e22017-04-02 23:53:04 -07001222 sink_.WaitForEncodedFrame(sequence++);
1223 stats = stats_proxy_->GetStats();
1224 // Disabled, since we previously switched the source too disabled.
1225 EXPECT_FALSE(stats.cpu_limited_resolution);
1226 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1227
1228 // Trigger CPU normal usage.
1229 vie_encoder_->TriggerCpuNormalUsage();
1230 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001231 CreateFrame(sequence, kWidth, kHeight));
sprangc5d62e22017-04-02 23:53:04 -07001232 sink_.WaitForEncodedFrame(sequence++);
1233 stats = stats_proxy_->GetStats();
1234 EXPECT_FALSE(stats.cpu_limited_resolution);
1235 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001236
1237 vie_encoder_->Stop();
1238}
1239
Erik Språng08127a92016-11-16 16:41:30 +01001240TEST_F(ViEEncoderTest, StatsTracksPreferredBitrate) {
Erik Språng08127a92016-11-16 16:41:30 +01001241 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1242
asaperssonfab67072017-04-04 05:51:49 -07001243 const int kWidth = 1280;
1244 const int kHeight = 720;
1245 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
Erik Språng08127a92016-11-16 16:41:30 +01001246 sink_.WaitForEncodedFrame(1);
1247
1248 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1249 EXPECT_EQ(video_encoder_config_.max_bitrate_bps,
1250 stats.preferred_media_bitrate_bps);
1251
1252 vie_encoder_->Stop();
1253}
1254
kthelgason876222f2016-11-29 01:44:11 -08001255TEST_F(ViEEncoderTest, ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001256 const int kWidth = 1280;
1257 const int kHeight = 720;
kthelgason876222f2016-11-29 01:44:11 -08001258 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1259
asaperssonfab67072017-04-04 05:51:49 -07001260 // Expect no scaling to begin with.
sprang84a37592017-02-10 07:04:27 -08001261 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001262 EXPECT_EQ(std::numeric_limits<int>::max(),
1263 video_source_.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001264
asaperssonfab67072017-04-04 05:51:49 -07001265 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -08001266 sink_.WaitForEncodedFrame(1);
1267
asaperssonfab67072017-04-04 05:51:49 -07001268 // Trigger scale down.
kthelgason5e13d412016-12-01 03:59:51 -08001269 vie_encoder_->TriggerQualityLow();
1270
asaperssonfab67072017-04-04 05:51:49 -07001271 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
kthelgason5e13d412016-12-01 03:59:51 -08001272 sink_.WaitForEncodedFrame(2);
1273
kthelgason876222f2016-11-29 01:44:11 -08001274 // Expect a scale down.
1275 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001276 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001277
1278 // Set adaptation disabled.
1279 test::FrameForwarder new_video_source;
1280 vie_encoder_->SetSource(
1281 &new_video_source,
1282 VideoSendStream::DegradationPreference::kMaintainResolution);
1283
asaperssonfab67072017-04-04 05:51:49 -07001284 // Trigger scale down.
kthelgason876222f2016-11-29 01:44:11 -08001285 vie_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001286 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
kthelgason5e13d412016-12-01 03:59:51 -08001287 sink_.WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001288
asaperssonfab67072017-04-04 05:51:49 -07001289 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001290 EXPECT_EQ(std::numeric_limits<int>::max(),
1291 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001292
asaperssonfab67072017-04-04 05:51:49 -07001293 // Trigger scale up.
kthelgason876222f2016-11-29 01:44:11 -08001294 vie_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001295 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
kthelgason5e13d412016-12-01 03:59:51 -08001296 sink_.WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001297
1298 // Expect nothing to change, still no scaling
sprangc5d62e22017-04-02 23:53:04 -07001299 EXPECT_EQ(std::numeric_limits<int>::max(),
1300 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001301
1302 vie_encoder_->Stop();
1303}
1304
kthelgason5e13d412016-12-01 03:59:51 -08001305TEST_F(ViEEncoderTest, DoesNotScaleBelowSetLimit) {
kthelgason5e13d412016-12-01 03:59:51 -08001306 int frame_width = 1280;
1307 int frame_height = 720;
kthelgason5e13d412016-12-01 03:59:51 -08001308 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1309
1310 for (size_t i = 1; i <= 10; i++) {
1311 video_source_.IncomingCapturedFrame(
1312 CreateFrame(i, frame_width, frame_height));
1313 sink_.WaitForEncodedFrame(i);
asaperssonfab67072017-04-04 05:51:49 -07001314 // Trigger scale down.
kthelgason5e13d412016-12-01 03:59:51 -08001315 vie_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001316 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
kthelgason5e13d412016-12-01 03:59:51 -08001317 }
1318
1319 vie_encoder_->Stop();
1320}
1321
perkj803d97f2016-11-01 11:45:46 -07001322TEST_F(ViEEncoderTest, UMACpuLimitedResolutionInPercent) {
perkj803d97f2016-11-01 11:45:46 -07001323 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1324
asaperssonfab67072017-04-04 05:51:49 -07001325 const int kWidth = 640;
1326 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07001327
1328 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07001329 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
perkj803d97f2016-11-01 11:45:46 -07001330 sink_.WaitForEncodedFrame(i);
1331 }
1332
1333 vie_encoder_->TriggerCpuOveruse();
1334 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07001335 video_source_.IncomingCapturedFrame(CreateFrame(
1336 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
perkj803d97f2016-11-01 11:45:46 -07001337 sink_.WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples +
1338 i);
1339 }
1340
1341 vie_encoder_->Stop();
sprangf8ee65e2017-02-28 08:49:33 -08001342 vie_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07001343 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08001344
perkj803d97f2016-11-01 11:45:46 -07001345 EXPECT_EQ(1,
1346 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
1347 EXPECT_EQ(
1348 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
1349}
1350
sprang57c2fff2017-01-16 06:24:02 -08001351TEST_F(ViEEncoderTest, CallsBitrateObserver) {
1352 class MockBitrateObserver : public VideoBitrateAllocationObserver {
1353 public:
1354 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const BitrateAllocation&));
1355 } bitrate_observer;
1356 vie_encoder_->SetBitrateObserver(&bitrate_observer);
1357
1358 const int kDefaultFps = 30;
1359 const BitrateAllocation expected_bitrate =
1360 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08001361 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08001362
1363 // First called on bitrate updated, then again on first frame.
1364 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
1365 .Times(2);
kthelgason2bc68642017-02-07 07:02:22 -08001366 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08001367
1368 const int64_t kStartTimeMs = 1;
1369 video_source_.IncomingCapturedFrame(
1370 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
1371 sink_.WaitForEncodedFrame(kStartTimeMs);
1372
1373 // Not called on second frame.
1374 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
1375 .Times(0);
1376 video_source_.IncomingCapturedFrame(
1377 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
1378 sink_.WaitForEncodedFrame(kStartTimeMs + 1);
1379
1380 // Called after a process interval.
1381 const int64_t kProcessIntervalMs =
1382 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
1383 // TODO(sprang): ViEEncoder should die and/or get injectable clock.
1384 // Sleep for one processing interval plus one frame to avoid flakiness.
1385 SleepMs(kProcessIntervalMs + 1000 / kDefaultFps);
1386 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
1387 .Times(1);
1388 video_source_.IncomingCapturedFrame(CreateFrame(
1389 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
1390 sink_.WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
1391
1392 vie_encoder_->Stop();
1393}
1394
kthelgason2bc68642017-02-07 07:02:22 -08001395TEST_F(ViEEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07001396 const int kTooLowBitrateForFrameSizeBps = 10000;
1397 vie_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
1398 const int kWidth = 640;
1399 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08001400
asaperssonfab67072017-04-04 05:51:49 -07001401 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08001402
1403 // Expect to drop this frame, the wait should time out.
1404 sink_.ExpectDroppedFrame();
1405
1406 // Expect the sink_wants to specify a scaled frame.
sprangc5d62e22017-04-02 23:53:04 -07001407 EXPECT_LT(video_source_.sink_wants().max_pixel_count, 1000 * 1000);
kthelgason2bc68642017-02-07 07:02:22 -08001408
sprangc5d62e22017-04-02 23:53:04 -07001409 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08001410
asaperssonfab67072017-04-04 05:51:49 -07001411 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08001412 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001413 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08001414
1415 // Expect to drop this frame, the wait should time out.
1416 sink_.ExpectDroppedFrame();
1417
sprangc5d62e22017-04-02 23:53:04 -07001418 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08001419
1420 vie_encoder_->Stop();
1421}
1422
asaperssonfab67072017-04-04 05:51:49 -07001423TEST_F(ViEEncoderTest, NrOfDroppedFramesLimitedWhenBitrateIsTooLow) {
1424 const int kTooLowBitrateForFrameSizeBps = 10000;
1425 vie_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
1426 const int kWidth = 640;
1427 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08001428
1429 // We expect the n initial frames to get dropped.
1430 int i;
1431 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07001432 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08001433 sink_.ExpectDroppedFrame();
1434 }
1435 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07001436 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08001437 sink_.WaitForEncodedFrame(i);
1438
1439 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07001440 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08001441
1442 vie_encoder_->Stop();
1443}
1444
1445TEST_F(ViEEncoderTest, InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07001446 const int kWidth = 640;
1447 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08001448 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
1449
1450 // Set degradation preference.
1451 vie_encoder_->SetSource(
1452 &video_source_,
1453 VideoSendStream::DegradationPreference::kMaintainResolution);
1454
asaperssonfab67072017-04-04 05:51:49 -07001455 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08001456 // Frame should not be dropped, even if it's too large.
1457 sink_.WaitForEncodedFrame(1);
1458
1459 vie_encoder_->Stop();
1460}
1461
kthelgason2fc52542017-03-03 00:24:41 -08001462TEST_F(ViEEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07001463 const int kWidth = 640;
1464 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08001465 fake_encoder_.SetQualityScaling(false);
1466 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgasonb83797b2017-02-14 11:57:25 -08001467 // Force quality scaler reconfiguration by resetting the source.
1468 vie_encoder_->SetSource(&video_source_,
1469 VideoSendStream::DegradationPreference::kBalanced);
kthelgasonad9010c2017-02-14 00:46:51 -08001470
asaperssonfab67072017-04-04 05:51:49 -07001471 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08001472 // Frame should not be dropped, even if it's too large.
1473 sink_.WaitForEncodedFrame(1);
1474
1475 vie_encoder_->Stop();
1476 fake_encoder_.SetQualityScaling(true);
1477}
1478
sprangb1ca0732017-02-01 08:38:12 -08001479// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
1480TEST_F(ViEEncoderTest, AdaptsResolutionOnOveruse) {
1481 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1482
1483 const int kFrameWidth = 1280;
1484 const int kFrameHeight = 720;
1485 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
1486 // requested by ViEEncoder::VideoSourceProxy::RequestResolutionLowerThan().
1487 video_source_.set_adaptation_enabled(true);
1488
1489 video_source_.IncomingCapturedFrame(
1490 CreateFrame(1, kFrameWidth, kFrameHeight));
1491 sink_.WaitForEncodedFrame(kFrameWidth, kFrameHeight);
1492
1493 // Trigger CPU overuse, downscale by 3/4.
1494 vie_encoder_->TriggerCpuOveruse();
1495 video_source_.IncomingCapturedFrame(
1496 CreateFrame(2, kFrameWidth, kFrameHeight));
1497 sink_.WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
1498
asaperssonfab67072017-04-04 05:51:49 -07001499 // Trigger CPU normal use, return to original resolution.
sprangb1ca0732017-02-01 08:38:12 -08001500 vie_encoder_->TriggerCpuNormalUsage();
1501 video_source_.IncomingCapturedFrame(
1502 CreateFrame(3, kFrameWidth, kFrameHeight));
1503 sink_.WaitForEncodedFrame(kFrameWidth, kFrameHeight);
1504
1505 vie_encoder_->Stop();
1506}
sprangfe627f32017-03-29 08:24:59 -07001507
1508TEST_F(ViEEncoderTest, FailingInitEncodeDoesntCauseCrash) {
1509 fake_encoder_.ForceInitEncodeFailure(true);
1510 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1511 ResetEncoder("VP8", 2, 1, true);
1512 const int kFrameWidth = 1280;
1513 const int kFrameHeight = 720;
1514 video_source_.IncomingCapturedFrame(
1515 CreateFrame(1, kFrameWidth, kFrameHeight));
1516 sink_.ExpectDroppedFrame();
1517 vie_encoder_->Stop();
1518}
sprangc5d62e22017-04-02 23:53:04 -07001519
1520TEST_F(ViEEncoderTest, AdaptsFrameOnOveruseWithMaintainResolution) {
1521 const int kDefaultFramerateFps = 30;
1522 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kDefaultFramerateFps;
1523 const int kFrameWidth = 1280;
1524 const int kFrameHeight = 720;
1525 rtc::ScopedFakeClock fake_clock;
1526
1527 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1528 vie_encoder_->SetSource(
1529 &video_source_,
1530 VideoSendStream::DegradationPreference::kMaintainResolution);
1531 video_source_.set_adaptation_enabled(true);
1532
1533 fake_clock.SetTimeMicros(kFrameIntervalMs * 1000);
1534 int64_t timestamp_ms = kFrameIntervalMs;
1535
1536 video_source_.IncomingCapturedFrame(
1537 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1538 sink_.WaitForEncodedFrame(timestamp_ms);
1539
1540 // Try to trigger overuse. No fps estimate available => no effect.
1541 vie_encoder_->TriggerCpuOveruse();
1542
1543 // Insert frames for one second to get a stable estimate.
1544 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1545 timestamp_ms += kFrameIntervalMs;
1546 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1547 video_source_.IncomingCapturedFrame(
1548 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1549 sink_.WaitForEncodedFrame(timestamp_ms);
1550 }
1551
1552 // Trigger CPU overuse, reduce framerate by 2/3.
1553 vie_encoder_->TriggerCpuOveruse();
1554 int num_frames_dropped = 0;
1555 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1556 timestamp_ms += kFrameIntervalMs;
1557 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1558 video_source_.IncomingCapturedFrame(
1559 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1560 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
1561 ++num_frames_dropped;
1562 } else {
1563 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
1564 }
1565 }
1566
1567 // TODO(sprang): Find where there's rounding errors or stuff causing the
1568 // margin here to be a little larger than we'd like (input fps estimate is
1569 // off) and the frame dropping is a little too aggressive.
1570 const int kErrorMargin = 5;
1571 EXPECT_NEAR(num_frames_dropped,
1572 kDefaultFramerateFps - (kDefaultFramerateFps * 2 / 3),
1573 kErrorMargin);
1574
1575 // Trigger CPU overuse, reduce framerate by 2/3 again.
1576 vie_encoder_->TriggerCpuOveruse();
1577 num_frames_dropped = 0;
1578 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1579 timestamp_ms += kFrameIntervalMs;
1580 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1581 video_source_.IncomingCapturedFrame(
1582 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1583 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
1584 ++num_frames_dropped;
1585 } else {
1586 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
1587 }
1588 }
1589 EXPECT_NEAR(num_frames_dropped,
1590 kDefaultFramerateFps - (kDefaultFramerateFps * 4 / 9),
1591 kErrorMargin);
1592
1593 // Go back up one step.
1594 vie_encoder_->TriggerCpuNormalUsage();
1595 num_frames_dropped = 0;
1596 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1597 timestamp_ms += kFrameIntervalMs;
1598 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1599 video_source_.IncomingCapturedFrame(
1600 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1601 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
1602 ++num_frames_dropped;
1603 } else {
1604 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
1605 }
1606 }
1607 EXPECT_NEAR(num_frames_dropped,
1608 kDefaultFramerateFps - (kDefaultFramerateFps * 2 / 3),
1609 kErrorMargin);
1610
1611 // Go back up to original mode.
1612 vie_encoder_->TriggerCpuNormalUsage();
1613 num_frames_dropped = 0;
1614 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1615 timestamp_ms += kFrameIntervalMs;
1616 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1617 video_source_.IncomingCapturedFrame(
1618 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1619 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
1620 ++num_frames_dropped;
1621 } else {
1622 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
1623 }
1624 }
1625 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
1626
1627 vie_encoder_->Stop();
1628}
1629
1630TEST_F(ViEEncoderTest, DoesntAdaptDownPastMinFramerate) {
1631 const int kFramerateFps = 5;
1632 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
1633 const int kMinFpsFrameInterval = rtc::kNumMillisecsPerSec / kMinFramerateFps;
1634 const int kFrameWidth = 1280;
1635 const int kFrameHeight = 720;
1636
1637 rtc::ScopedFakeClock fake_clock;
1638 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1639 vie_encoder_->SetSource(
1640 &video_source_,
1641 VideoSendStream::DegradationPreference::kMaintainResolution);
1642 video_source_.set_adaptation_enabled(true);
1643
1644 fake_clock.SetTimeMicros(kFrameIntervalMs * 1000);
1645 int64_t timestamp_ms = kFrameIntervalMs;
1646
1647 // Trigger overuse as much as we can.
1648 for (int i = 0; i < ViEEncoder::kMaxCpuResolutionDowngrades; ++i) {
1649 // Insert frames to get a new fps estimate...
1650 for (int j = 0; j < kFramerateFps; ++j) {
1651 video_source_.IncomingCapturedFrame(
1652 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1653 timestamp_ms += kFrameIntervalMs;
1654 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1655 }
1656 // ...and then try to adapt again.
1657 vie_encoder_->TriggerCpuOveruse();
1658 }
1659
1660 // Drain any frame in the pipeline.
1661 sink_.WaitForFrame(kDefaultTimeoutMs);
1662
1663 // Insert frames at min fps, all should go through.
1664 for (int i = 0; i < 10; ++i) {
1665 timestamp_ms += kMinFpsFrameInterval;
1666 fake_clock.AdvanceTimeMicros(kMinFpsFrameInterval * 1000);
1667 video_source_.IncomingCapturedFrame(
1668 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1669 sink_.WaitForEncodedFrame(timestamp_ms);
1670 }
1671 vie_encoder_->Stop();
1672}
perkj26091b12016-09-01 01:17:40 -07001673} // namespace webrtc