blob: 79a08b354a37195d2b94c17966c09c67677b0334 [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
asapersson02465b82017-04-10 01:12:52 -0700287 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
288 EXPECT_FALSE(wants.target_pixel_count);
289 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
290 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
291 }
292
293 void VerifyResolutionLimitationLessThan(const rtc::VideoSinkWants& wants,
294 int pixel_count) {
295 EXPECT_LT(wants.max_pixel_count, pixel_count);
296 EXPECT_GT(wants.max_pixel_count, 0);
297 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
298 }
299
perkj26091b12016-09-01 01:17:40 -0700300 class TestEncoder : public test::FakeEncoder {
301 public:
302 TestEncoder()
303 : FakeEncoder(Clock::GetRealTimeClock()),
304 continue_encode_event_(false, false) {}
305
asaperssonfab67072017-04-04 05:51:49 -0700306 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800307 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700308 return config_;
309 }
310
311 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800312 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700313 block_next_encode_ = true;
314 }
315
kthelgason876222f2016-11-29 01:44:11 -0800316 VideoEncoder::ScalingSettings GetScalingSettings() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800317 rtc::CritScope lock(&local_crit_sect_);
kthelgasonad9010c2017-02-14 00:46:51 -0800318 if (quality_scaling_)
319 return VideoEncoder::ScalingSettings(true, 1, 2);
320 return VideoEncoder::ScalingSettings(false);
kthelgason876222f2016-11-29 01:44:11 -0800321 }
322
perkjfa10b552016-10-02 23:45:26 -0700323 void ContinueEncode() { continue_encode_event_.Set(); }
324
325 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
326 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800327 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700328 EXPECT_EQ(timestamp_, timestamp);
329 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
330 }
331
kthelgason2fc52542017-03-03 00:24:41 -0800332 void SetQualityScaling(bool b) {
333 rtc::CritScope lock(&local_crit_sect_);
334 quality_scaling_ = b;
335 }
kthelgasonad9010c2017-02-14 00:46:51 -0800336
sprangfe627f32017-03-29 08:24:59 -0700337 void ForceInitEncodeFailure(bool force_failure) {
338 rtc::CritScope lock(&local_crit_sect_);
339 force_init_encode_failed_ = force_failure;
340 }
341
perkjfa10b552016-10-02 23:45:26 -0700342 private:
perkj26091b12016-09-01 01:17:40 -0700343 int32_t Encode(const VideoFrame& input_image,
344 const CodecSpecificInfo* codec_specific_info,
345 const std::vector<FrameType>* frame_types) override {
346 bool block_encode;
347 {
brandtre78d2662017-01-16 05:57:16 -0800348 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700349 EXPECT_GT(input_image.timestamp(), timestamp_);
350 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
351 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
352
353 timestamp_ = input_image.timestamp();
354 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700355 last_input_width_ = input_image.width();
356 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700357 block_encode = block_next_encode_;
358 block_next_encode_ = false;
359 }
360 int32_t result =
361 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
362 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700363 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700364 return result;
365 }
366
sprangfe627f32017-03-29 08:24:59 -0700367 int32_t InitEncode(const VideoCodec* config,
368 int32_t number_of_cores,
369 size_t max_payload_size) override {
370 int res =
371 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
372 rtc::CritScope lock(&local_crit_sect_);
373 if (config->codecType == kVideoCodecVP8 && config->VP8().tl_factory) {
374 // Simulate setting up temporal layers, in order to validate the life
375 // cycle of these objects.
376 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
377 int num_temporal_layers =
378 std::max<int>(1, config->VP8().numberOfTemporalLayers);
379 for (int i = 0; i < num_streams; ++i) {
380 allocated_temporal_layers_.emplace_back(
381 config->VP8().tl_factory->Create(i, num_temporal_layers, 42));
382 }
383 }
384 if (force_init_encode_failed_)
385 return -1;
386 return res;
387 }
388
brandtre78d2662017-01-16 05:57:16 -0800389 rtc::CriticalSection local_crit_sect_;
sprangfe627f32017-03-29 08:24:59 -0700390 bool block_next_encode_ GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700391 rtc::Event continue_encode_event_;
sprangfe627f32017-03-29 08:24:59 -0700392 uint32_t timestamp_ GUARDED_BY(local_crit_sect_) = 0;
393 int64_t ntp_time_ms_ GUARDED_BY(local_crit_sect_) = 0;
394 int last_input_width_ GUARDED_BY(local_crit_sect_) = 0;
395 int last_input_height_ GUARDED_BY(local_crit_sect_) = 0;
396 bool quality_scaling_ GUARDED_BY(local_crit_sect_) = true;
397 std::vector<std::unique_ptr<TemporalLayers>> allocated_temporal_layers_
398 GUARDED_BY(local_crit_sect_);
399 bool force_init_encode_failed_ GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700400 };
401
Per512ecb32016-09-23 15:52:06 +0200402 class TestSink : public ViEEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700403 public:
404 explicit TestSink(TestEncoder* test_encoder)
405 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
406
perkj26091b12016-09-01 01:17:40 -0700407 void WaitForEncodedFrame(int64_t expected_ntp_time) {
408 uint32_t timestamp = 0;
perkja49cbd32016-09-16 07:53:41 -0700409 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700410 {
411 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800412 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700413 }
414 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
415 }
416
sprangb1ca0732017-02-01 08:38:12 -0800417 void WaitForEncodedFrame(uint32_t expected_width,
418 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700419 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
420 CheckLastFrameSizeMathces(expected_width, expected_height);
421 }
422
423 void CheckLastFrameSizeMathces(uint32_t expected_width,
424 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800425 uint32_t width = 0;
426 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800427 {
428 rtc::CritScope lock(&crit_);
429 width = last_width_;
430 height = last_height_;
431 }
432 EXPECT_EQ(expected_height, height);
433 EXPECT_EQ(expected_width, width);
434 }
435
kthelgason2fc52542017-03-03 00:24:41 -0800436 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800437
sprangc5d62e22017-04-02 23:53:04 -0700438 bool WaitForFrame(int64_t timeout_ms) {
439 return encoded_frame_event_.Wait(timeout_ms);
440 }
441
perkj26091b12016-09-01 01:17:40 -0700442 void SetExpectNoFrames() {
443 rtc::CritScope lock(&crit_);
444 expect_frames_ = false;
445 }
446
asaperssonfab67072017-04-04 05:51:49 -0700447 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200448 rtc::CritScope lock(&crit_);
449 return number_of_reconfigurations_;
450 }
451
asaperssonfab67072017-04-04 05:51:49 -0700452 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200453 rtc::CritScope lock(&crit_);
454 return min_transmit_bitrate_bps_;
455 }
456
perkj26091b12016-09-01 01:17:40 -0700457 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700458 Result OnEncodedImage(
459 const EncodedImage& encoded_image,
460 const CodecSpecificInfo* codec_specific_info,
461 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200462 rtc::CritScope lock(&crit_);
463 EXPECT_TRUE(expect_frames_);
sprangb1ca0732017-02-01 08:38:12 -0800464 last_timestamp_ = encoded_image._timeStamp;
465 last_width_ = encoded_image._encodedWidth;
466 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200467 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800468 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200469 }
470
471 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
472 int min_transmit_bitrate_bps) override {
473 rtc::CriticalSection crit_;
474 ++number_of_reconfigurations_;
475 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
476 }
477
perkj26091b12016-09-01 01:17:40 -0700478 rtc::CriticalSection crit_;
479 TestEncoder* test_encoder_;
480 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800481 uint32_t last_timestamp_ = 0;
482 uint32_t last_height_ = 0;
483 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700484 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200485 int number_of_reconfigurations_ = 0;
486 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700487 };
488
489 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100490 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200491 int codec_width_;
492 int codec_height_;
perkj26091b12016-09-01 01:17:40 -0700493 TestEncoder fake_encoder_;
sprangc5d62e22017-04-02 23:53:04 -0700494 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700495 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800496 AdaptingFrameForwarder video_source_;
perkj803d97f2016-11-01 11:45:46 -0700497 std::unique_ptr<ViEEncoderUnderTest> vie_encoder_;
perkj26091b12016-09-01 01:17:40 -0700498};
499
500TEST_F(ViEEncoderTest, EncodeOneFrame) {
perkj26091b12016-09-01 01:17:40 -0700501 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
502 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700503 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
perkj26091b12016-09-01 01:17:40 -0700504 sink_.WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700505 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700506 vie_encoder_->Stop();
507}
508
509TEST_F(ViEEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
510 // Dropped since no target bitrate has been set.
511 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700512 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
513 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700514
perkj26091b12016-09-01 01:17:40 -0700515 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
516
perkja49cbd32016-09-16 07:53:41 -0700517 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkj26091b12016-09-01 01:17:40 -0700518 sink_.WaitForEncodedFrame(2);
519 vie_encoder_->Stop();
520}
521
522TEST_F(ViEEncoderTest, DropsFramesWhenRateSetToZero) {
perkj26091b12016-09-01 01:17:40 -0700523 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700524 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700525 sink_.WaitForEncodedFrame(1);
526
527 vie_encoder_->OnBitrateUpdated(0, 0, 0);
528 // Dropped since bitrate is zero.
perkja49cbd32016-09-16 07:53:41 -0700529 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkj26091b12016-09-01 01:17:40 -0700530
531 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700532 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700533 sink_.WaitForEncodedFrame(3);
534 vie_encoder_->Stop();
535}
536
537TEST_F(ViEEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
perkj26091b12016-09-01 01:17:40 -0700538 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700539 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700540 sink_.WaitForEncodedFrame(1);
541
542 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700543 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700544
perkja49cbd32016-09-16 07:53:41 -0700545 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkj26091b12016-09-01 01:17:40 -0700546 sink_.WaitForEncodedFrame(2);
547 vie_encoder_->Stop();
548}
549
550TEST_F(ViEEncoderTest, DropsFrameAfterStop) {
perkj26091b12016-09-01 01:17:40 -0700551 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
552
perkja49cbd32016-09-16 07:53:41 -0700553 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700554 sink_.WaitForEncodedFrame(1);
555
556 vie_encoder_->Stop();
557 sink_.SetExpectNoFrames();
558 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700559 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
560 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700561}
562
563TEST_F(ViEEncoderTest, DropsPendingFramesOnSlowEncode) {
perkj26091b12016-09-01 01:17:40 -0700564 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
565
566 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700567 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700568 sink_.WaitForEncodedFrame(1);
569 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
570 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700571 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
572 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700573 fake_encoder_.ContinueEncode();
574 sink_.WaitForEncodedFrame(3);
575
576 vie_encoder_->Stop();
577}
578
Per512ecb32016-09-23 15:52:06 +0200579TEST_F(ViEEncoderTest, ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
Per512ecb32016-09-23 15:52:06 +0200580 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100581 EXPECT_EQ(0, sink_.number_of_reconfigurations());
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(1, nullptr));
Per512ecb32016-09-23 15:52:06 +0200585 sink_.WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100586 // The encoder will have been configured once when the first frame is
587 // received.
588 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200589
590 VideoEncoderConfig video_encoder_config;
perkjfa10b552016-10-02 23:45:26 -0700591 test::FillEncoderConfiguration(1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200592 video_encoder_config.min_transmit_bitrate_bps = 9999;
asapersson5f7226f2016-11-25 04:37:00 -0800593 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
594 kMaxPayloadLength, true /* nack_enabled */);
Per512ecb32016-09-23 15:52:06 +0200595
596 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200597 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Per512ecb32016-09-23 15:52:06 +0200598 sink_.WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100599 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700600 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700601
602 vie_encoder_->Stop();
603}
604
perkjfa10b552016-10-02 23:45:26 -0700605TEST_F(ViEEncoderTest, FrameResolutionChangeReconfigureEncoder) {
perkjfa10b552016-10-02 23:45:26 -0700606 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
607
608 // Capture a frame and wait for it to synchronize with the encoder thread.
609 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
610 sink_.WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100611 // The encoder will have been configured once.
612 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700613 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
614 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
615
616 codec_width_ *= 2;
617 codec_height_ *= 2;
618 // Capture a frame with a higher resolution and wait for it to synchronize
619 // with the encoder thread.
620 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
621 sink_.WaitForEncodedFrame(2);
622 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
623 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100624 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700625
626 vie_encoder_->Stop();
627}
628
asapersson5f7226f2016-11-25 04:37:00 -0800629TEST_F(ViEEncoderTest, Vp8ResilienceIsOffFor1S1TLWithNackEnabled) {
630 const bool kNackEnabled = true;
631 const size_t kNumStreams = 1;
632 const size_t kNumTl = 1;
asaperssona90799d2016-12-09 02:35:20 -0800633 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800634 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
635
636 // Capture a frame and wait for it to synchronize with the encoder thread.
637 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
638 sink_.WaitForEncodedFrame(1);
639 // The encoder have been configured once when the first frame is received.
640 EXPECT_EQ(1, sink_.number_of_reconfigurations());
641 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
642 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
643 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
644 // Resilience is off for no temporal layers with nack on.
645 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
646 vie_encoder_->Stop();
647}
648
649TEST_F(ViEEncoderTest, Vp8ResilienceIsOffFor2S1TlWithNackEnabled) {
650 const bool kNackEnabled = true;
651 const size_t kNumStreams = 2;
652 const size_t kNumTl = 1;
asaperssona90799d2016-12-09 02:35:20 -0800653 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800654 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
655
656 // Capture a frame and wait for it to synchronize with the encoder thread.
657 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
658 sink_.WaitForEncodedFrame(1);
659 // The encoder have been configured once when the first frame is received.
660 EXPECT_EQ(1, sink_.number_of_reconfigurations());
661 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
662 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
663 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
664 // Resilience is off for no temporal layers and >1 streams with nack on.
665 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
666 vie_encoder_->Stop();
667}
668
669TEST_F(ViEEncoderTest, Vp8ResilienceIsOnFor1S1TLWithNackDisabled) {
670 const bool kNackEnabled = false;
671 const size_t kNumStreams = 1;
672 const size_t kNumTl = 1;
asaperssona90799d2016-12-09 02:35:20 -0800673 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800674 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
675
676 // Capture a frame and wait for it to synchronize with the encoder thread.
677 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
678 sink_.WaitForEncodedFrame(1);
679 // The encoder have been configured once when the first frame is received.
680 EXPECT_EQ(1, sink_.number_of_reconfigurations());
681 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
682 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
683 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
684 // Resilience is on for no temporal layers with nack off.
685 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
686 vie_encoder_->Stop();
687}
688
689TEST_F(ViEEncoderTest, Vp8ResilienceIsOnFor1S2TlWithNackEnabled) {
690 const bool kNackEnabled = true;
691 const size_t kNumStreams = 1;
692 const size_t kNumTl = 2;
asaperssona90799d2016-12-09 02:35:20 -0800693 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800694 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
695
696 // Capture a frame and wait for it to synchronize with the encoder thread.
697 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
698 sink_.WaitForEncodedFrame(1);
699 // The encoder have been configured once when the first frame is received.
700 EXPECT_EQ(1, sink_.number_of_reconfigurations());
701 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
702 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
703 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
704 // Resilience is on for temporal layers.
705 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
706 vie_encoder_->Stop();
707}
708
perkj803d97f2016-11-01 11:45:46 -0700709TEST_F(ViEEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
710 EXPECT_TRUE(video_source_.has_sinks());
711 test::FrameForwarder new_video_source;
sprangc5d62e22017-04-02 23:53:04 -0700712 vie_encoder_->SetSource(
713 &new_video_source,
714 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -0700715 EXPECT_FALSE(video_source_.has_sinks());
716 EXPECT_TRUE(new_video_source.has_sinks());
717
718 vie_encoder_->Stop();
719}
720
721TEST_F(ViEEncoderTest, SinkWantsRotationApplied) {
722 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
723 vie_encoder_->SetSink(&sink_, true /*rotation_applied*/);
724 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
725 vie_encoder_->Stop();
726}
727
728TEST_F(ViEEncoderTest, SinkWantsFromOveruseDetector) {
perkj803d97f2016-11-01 11:45:46 -0700729 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
730
asapersson02465b82017-04-10 01:12:52 -0700731 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700732
733 int frame_width = 1280;
734 int frame_height = 720;
735
736 // Trigger CPU overuse kMaxCpuDowngrades times. Every time, ViEEncoder should
737 // request lower resolution.
sprangc5d62e22017-04-02 23:53:04 -0700738 for (int i = 1; i <= ViEEncoder::kMaxCpuResolutionDowngrades; ++i) {
perkj803d97f2016-11-01 11:45:46 -0700739 video_source_.IncomingCapturedFrame(
740 CreateFrame(i, frame_width, frame_height));
741 sink_.WaitForEncodedFrame(i);
742
743 vie_encoder_->TriggerCpuOveruse();
744
sprang84a37592017-02-10 07:04:27 -0800745 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700746 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
perkj803d97f2016-11-01 11:45:46 -0700747 frame_width * frame_height);
perkj803d97f2016-11-01 11:45:46 -0700748
749 frame_width /= 2;
750 frame_height /= 2;
751 }
752
kthelgason876222f2016-11-29 01:44:11 -0800753 // Trigger CPU overuse one more time. This should not trigger a request for
perkj803d97f2016-11-01 11:45:46 -0700754 // lower resolution.
755 rtc::VideoSinkWants current_wants = video_source_.sink_wants();
756 video_source_.IncomingCapturedFrame(CreateFrame(
sprangc5d62e22017-04-02 23:53:04 -0700757 ViEEncoder::kMaxCpuResolutionDowngrades + 1, frame_width, frame_height));
758 sink_.WaitForEncodedFrame(ViEEncoder::kMaxCpuResolutionDowngrades + 1);
perkj803d97f2016-11-01 11:45:46 -0700759 vie_encoder_->TriggerCpuOveruse();
sprang84a37592017-02-10 07:04:27 -0800760 EXPECT_EQ(video_source_.sink_wants().target_pixel_count,
761 current_wants.target_pixel_count);
perkj803d97f2016-11-01 11:45:46 -0700762 EXPECT_EQ(video_source_.sink_wants().max_pixel_count,
763 current_wants.max_pixel_count);
perkj803d97f2016-11-01 11:45:46 -0700764
765 // Trigger CPU normal use.
766 vie_encoder_->TriggerCpuNormalUsage();
sprang84a37592017-02-10 07:04:27 -0800767 EXPECT_EQ(frame_width * frame_height * 5 / 3,
768 video_source_.sink_wants().target_pixel_count.value_or(0));
769 EXPECT_EQ(frame_width * frame_height * 4,
sprangc5d62e22017-04-02 23:53:04 -0700770 video_source_.sink_wants().max_pixel_count);
perkj803d97f2016-11-01 11:45:46 -0700771
772 vie_encoder_->Stop();
773}
774
sprangc5d62e22017-04-02 23:53:04 -0700775TEST_F(ViEEncoderTest, SinkWantsStoredByDegradationPreference) {
perkj803d97f2016-11-01 11:45:46 -0700776 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -0700777 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700778
sprangc5d62e22017-04-02 23:53:04 -0700779 const int kFrameWidth = 1280;
780 const int kFrameHeight = 720;
781 const int kFrameIntervalMs = 1000 / 30;
782
783 int frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -0700784
kthelgason5e13d412016-12-01 03:59:51 -0800785 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700786 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
787 sink_.WaitForEncodedFrame(frame_timestamp);
788 frame_timestamp += kFrameIntervalMs;
789
perkj803d97f2016-11-01 11:45:46 -0700790 // Trigger CPU overuse.
791 vie_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700792 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700793 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
794 sink_.WaitForEncodedFrame(frame_timestamp);
795 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -0700796
asapersson0944a802017-04-07 00:57:58 -0700797 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -0700798 // wanted resolution.
799 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
800 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
801 kFrameWidth * kFrameHeight);
802 EXPECT_EQ(std::numeric_limits<int>::max(),
803 video_source_.sink_wants().max_framerate_fps);
804
805 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -0700806 test::FrameForwarder new_video_source;
807 vie_encoder_->SetSource(
808 &new_video_source,
809 VideoSendStream::DegradationPreference::kMaintainResolution);
810
sprangc5d62e22017-04-02 23:53:04 -0700811 // Initially no degradation registered.
asapersson02465b82017-04-10 01:12:52 -0700812 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700813
sprangc5d62e22017-04-02 23:53:04 -0700814 // Force an input frame rate to be available, or the adaptation call won't
815 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -0700816 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -0700817 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -0700818 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -0700819 stats_proxy_->SetMockStats(stats);
820
821 vie_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700822 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700823 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
824 sink_.WaitForEncodedFrame(frame_timestamp);
825 frame_timestamp += kFrameIntervalMs;
826
827 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -0800828 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700829 EXPECT_EQ(std::numeric_limits<int>::max(),
830 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700831 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -0700832
asapersson02465b82017-04-10 01:12:52 -0700833 // Turn off degradation completely.
sprangc5d62e22017-04-02 23:53:04 -0700834 vie_encoder_->SetSource(
835 &new_video_source,
836 VideoSendStream::DegradationPreference::kDegradationDisabled);
asapersson02465b82017-04-10 01:12:52 -0700837 VerifyNoLimitation(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -0700838
839 vie_encoder_->TriggerCpuOveruse();
840 new_video_source.IncomingCapturedFrame(
841 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
842 sink_.WaitForEncodedFrame(frame_timestamp);
843 frame_timestamp += kFrameIntervalMs;
844
845 // Still no degradation.
asapersson02465b82017-04-10 01:12:52 -0700846 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700847
848 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
sprangc5d62e22017-04-02 23:53:04 -0700849 vie_encoder_->SetSource(
850 &new_video_source,
851 VideoSendStream::DegradationPreference::kMaintainFramerate);
852 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
853 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -0800854 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700855 EXPECT_EQ(std::numeric_limits<int>::max(),
856 new_video_source.sink_wants().max_framerate_fps);
857
858 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
859 vie_encoder_->SetSource(
860 &new_video_source,
861 VideoSendStream::DegradationPreference::kMaintainResolution);
862 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
863 EXPECT_EQ(std::numeric_limits<int>::max(),
864 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700865 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -0700866
867 vie_encoder_->Stop();
868}
869
asaperssonfab67072017-04-04 05:51:49 -0700870TEST_F(ViEEncoderTest, StatsTracksQualityAdaptationStats) {
perkj803d97f2016-11-01 11:45:46 -0700871 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
872
asaperssonfab67072017-04-04 05:51:49 -0700873 const int kWidth = 1280;
874 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -0700875 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
876 sink_.WaitForEncodedFrame(1);
877 VideoSendStream::Stats stats = stats_proxy_->GetStats();
878 EXPECT_FALSE(stats.bw_limited_resolution);
879 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
880
881 // Trigger adapt down.
882 vie_encoder_->TriggerQualityLow();
883 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
884 sink_.WaitForEncodedFrame(2);
885
886 stats = stats_proxy_->GetStats();
887 EXPECT_TRUE(stats.bw_limited_resolution);
888 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
889
890 // Trigger adapt up.
891 vie_encoder_->TriggerQualityHigh();
892 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
893 sink_.WaitForEncodedFrame(3);
894
895 stats = stats_proxy_->GetStats();
896 EXPECT_FALSE(stats.bw_limited_resolution);
897 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
898 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
899
900 vie_encoder_->Stop();
901}
902
903TEST_F(ViEEncoderTest, StatsTracksCpuAdaptationStats) {
904 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
905
906 const int kWidth = 1280;
907 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -0700908 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
perkj803d97f2016-11-01 11:45:46 -0700909 sink_.WaitForEncodedFrame(1);
910 VideoSendStream::Stats stats = stats_proxy_->GetStats();
911 EXPECT_FALSE(stats.cpu_limited_resolution);
912 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
913
914 // Trigger CPU overuse.
915 vie_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -0700916 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
perkj803d97f2016-11-01 11:45:46 -0700917 sink_.WaitForEncodedFrame(2);
918
919 stats = stats_proxy_->GetStats();
920 EXPECT_TRUE(stats.cpu_limited_resolution);
921 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
922
923 // Trigger CPU normal use.
924 vie_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -0700925 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
perkj803d97f2016-11-01 11:45:46 -0700926 sink_.WaitForEncodedFrame(3);
927
928 stats = stats_proxy_->GetStats();
929 EXPECT_FALSE(stats.cpu_limited_resolution);
930 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -0700931 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -0700932
933 vie_encoder_->Stop();
934}
935
kthelgason876222f2016-11-29 01:44:11 -0800936TEST_F(ViEEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
kthelgason876222f2016-11-29 01:44:11 -0800937 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
938
asaperssonfab67072017-04-04 05:51:49 -0700939 const int kWidth = 1280;
940 const int kHeight = 720;
941 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -0800942 sink_.WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -0800943 VideoSendStream::Stats stats = stats_proxy_->GetStats();
944 EXPECT_FALSE(stats.cpu_limited_resolution);
945 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
946
asaperssonfab67072017-04-04 05:51:49 -0700947 // Trigger CPU overuse.
kthelgason876222f2016-11-29 01:44:11 -0800948 vie_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -0700949 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -0800950 sink_.WaitForEncodedFrame(2);
951 stats = stats_proxy_->GetStats();
952 EXPECT_TRUE(stats.cpu_limited_resolution);
953 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
954
955 // Set new source with adaptation still enabled.
956 test::FrameForwarder new_video_source;
sprangc5d62e22017-04-02 23:53:04 -0700957 vie_encoder_->SetSource(
958 &new_video_source,
959 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -0800960
asaperssonfab67072017-04-04 05:51:49 -0700961 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -0800962 sink_.WaitForEncodedFrame(3);
963 stats = stats_proxy_->GetStats();
964 EXPECT_TRUE(stats.cpu_limited_resolution);
965 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
966
967 // Set adaptation disabled.
968 vie_encoder_->SetSource(
969 &new_video_source,
sprangc5d62e22017-04-02 23:53:04 -0700970 VideoSendStream::DegradationPreference::kDegradationDisabled);
kthelgason876222f2016-11-29 01:44:11 -0800971
asaperssonfab67072017-04-04 05:51:49 -0700972 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -0800973 sink_.WaitForEncodedFrame(4);
974 stats = stats_proxy_->GetStats();
975 EXPECT_FALSE(stats.cpu_limited_resolution);
976 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
977
978 // Set adaptation back to enabled.
sprangc5d62e22017-04-02 23:53:04 -0700979 vie_encoder_->SetSource(
980 &new_video_source,
981 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -0800982
asaperssonfab67072017-04-04 05:51:49 -0700983 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -0800984 sink_.WaitForEncodedFrame(5);
985 stats = stats_proxy_->GetStats();
986 EXPECT_TRUE(stats.cpu_limited_resolution);
987 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
988
asaperssonfab67072017-04-04 05:51:49 -0700989 // Trigger CPU normal use.
kthelgason876222f2016-11-29 01:44:11 -0800990 vie_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -0700991 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -0800992 sink_.WaitForEncodedFrame(6);
993 stats = stats_proxy_->GetStats();
994 EXPECT_FALSE(stats.cpu_limited_resolution);
995 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -0700996 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -0800997
998 vie_encoder_->Stop();
999}
1000
1001TEST_F(ViEEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
kthelgason876222f2016-11-29 01:44:11 -08001002 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1003
asaperssonfab67072017-04-04 05:51:49 -07001004 const int kWidth = 1280;
1005 const int kHeight = 720;
1006 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -08001007 sink_.WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001008 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1009 EXPECT_FALSE(stats.cpu_limited_resolution);
1010 EXPECT_FALSE(stats.bw_limited_resolution);
asaperssonfab67072017-04-04 05:51:49 -07001011 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001012
1013 // Set new source with adaptation still enabled.
1014 test::FrameForwarder new_video_source;
1015 vie_encoder_->SetSource(&new_video_source,
1016 VideoSendStream::DegradationPreference::kBalanced);
1017
asaperssonfab67072017-04-04 05:51:49 -07001018 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -08001019 sink_.WaitForEncodedFrame(2);
1020 stats = stats_proxy_->GetStats();
1021 EXPECT_FALSE(stats.cpu_limited_resolution);
1022 EXPECT_FALSE(stats.bw_limited_resolution);
asaperssonfab67072017-04-04 05:51:49 -07001023 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001024
asaperssonfab67072017-04-04 05:51:49 -07001025 // Trigger adapt down.
kthelgason876222f2016-11-29 01:44:11 -08001026 vie_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001027 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -08001028 sink_.WaitForEncodedFrame(3);
1029 stats = stats_proxy_->GetStats();
1030 EXPECT_FALSE(stats.cpu_limited_resolution);
1031 EXPECT_TRUE(stats.bw_limited_resolution);
asaperssonfab67072017-04-04 05:51:49 -07001032 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001033
asaperssonfab67072017-04-04 05:51:49 -07001034 // Set new source with adaptation still enabled.
kthelgason876222f2016-11-29 01:44:11 -08001035 vie_encoder_->SetSource(&new_video_source,
1036 VideoSendStream::DegradationPreference::kBalanced);
1037
asaperssonfab67072017-04-04 05:51:49 -07001038 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -08001039 sink_.WaitForEncodedFrame(4);
1040 stats = stats_proxy_->GetStats();
1041 EXPECT_FALSE(stats.cpu_limited_resolution);
1042 EXPECT_TRUE(stats.bw_limited_resolution);
asaperssonfab67072017-04-04 05:51:49 -07001043 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001044
asapersson02465b82017-04-10 01:12:52 -07001045 // Disable resolution scaling.
kthelgason876222f2016-11-29 01:44:11 -08001046 vie_encoder_->SetSource(
1047 &new_video_source,
1048 VideoSendStream::DegradationPreference::kMaintainResolution);
1049
asaperssonfab67072017-04-04 05:51:49 -07001050 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -08001051 sink_.WaitForEncodedFrame(5);
1052 stats = stats_proxy_->GetStats();
1053 EXPECT_FALSE(stats.cpu_limited_resolution);
1054 EXPECT_FALSE(stats.bw_limited_resolution);
asaperssonfab67072017-04-04 05:51:49 -07001055 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1056 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001057
1058 vie_encoder_->Stop();
1059}
1060
asapersson36e9eb42017-03-31 05:29:12 -07001061TEST_F(ViEEncoderTest, QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1062 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1063
1064 const int kWidth = 1280;
1065 const int kHeight = 720;
1066 video_source_.set_adaptation_enabled(true);
1067 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1068 sink_.WaitForEncodedFrame(1);
1069 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1070 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1071 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1072
1073 // Trigger adapt down.
1074 vie_encoder_->TriggerQualityLow();
1075 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1076 sink_.WaitForEncodedFrame(2);
1077 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1078 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1079 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1080
1081 // Trigger overuse.
1082 vie_encoder_->TriggerCpuOveruse();
1083 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1084 sink_.WaitForEncodedFrame(3);
1085 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1086 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1087 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1088
1089 // Set source with adaptation still enabled but quality scaler is off.
1090 fake_encoder_.SetQualityScaling(false);
sprangc5d62e22017-04-02 23:53:04 -07001091 vie_encoder_->SetSource(
1092 &video_source_,
1093 VideoSendStream::DegradationPreference::kMaintainFramerate);
asapersson36e9eb42017-03-31 05:29:12 -07001094
1095 video_source_.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
1096 sink_.WaitForEncodedFrame(4);
1097 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1098 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1099 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1100
1101 vie_encoder_->Stop();
1102}
1103
asapersson02465b82017-04-10 01:12:52 -07001104TEST_F(ViEEncoderTest, StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
perkj803d97f2016-11-01 11:45:46 -07001105 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1106
asapersson0944a802017-04-07 00:57:58 -07001107 const int kWidth = 1280;
1108 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001109 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001110
asaperssonfab67072017-04-04 05:51:49 -07001111 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang84a37592017-02-10 07:04:27 -08001112 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001113 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001114 EXPECT_FALSE(stats.cpu_limited_resolution);
1115 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1116
asapersson02465b82017-04-10 01:12:52 -07001117 // Trigger CPU overuse, should now adapt down.
sprang84a37592017-02-10 07:04:27 -08001118 vie_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001119 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang84a37592017-02-10 07:04:27 -08001120 sink_.WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001121 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001122 EXPECT_TRUE(stats.cpu_limited_resolution);
1123 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1124
1125 // Set new source with adaptation still enabled.
1126 test::FrameForwarder new_video_source;
sprangc5d62e22017-04-02 23:53:04 -07001127 vie_encoder_->SetSource(
1128 &new_video_source,
1129 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001130
1131 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001132 CreateFrame(sequence, kWidth, kHeight));
sprang84a37592017-02-10 07:04:27 -08001133 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001134 stats = stats_proxy_->GetStats();
1135 EXPECT_TRUE(stats.cpu_limited_resolution);
1136 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1137
sprangc5d62e22017-04-02 23:53:04 -07001138 // Set cpu adaptation by frame dropping.
perkj803d97f2016-11-01 11:45:46 -07001139 vie_encoder_->SetSource(
1140 &new_video_source,
1141 VideoSendStream::DegradationPreference::kMaintainResolution);
1142 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001143 CreateFrame(sequence, kWidth, kHeight));
sprang84a37592017-02-10 07:04:27 -08001144 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001145 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001146 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001147 EXPECT_FALSE(stats.cpu_limited_resolution);
1148 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1149
sprangc5d62e22017-04-02 23:53:04 -07001150 // Force an input frame rate to be available, or the adaptation call won't
1151 // know what framerate to adapt form.
1152 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1153 mock_stats.input_frame_rate = 30;
1154 stats_proxy_->SetMockStats(mock_stats);
1155 vie_encoder_->TriggerCpuOveruse();
1156 stats_proxy_->ResetMockStats();
1157
1158 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001159 CreateFrame(sequence, kWidth, kHeight));
sprangc5d62e22017-04-02 23:53:04 -07001160 sink_.WaitForEncodedFrame(sequence++);
1161
1162 // Framerate now adapted.
1163 stats = stats_proxy_->GetStats();
1164 EXPECT_TRUE(stats.cpu_limited_resolution);
1165 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1166
1167 // Disable CPU adaptation.
1168 vie_encoder_->SetSource(
1169 &new_video_source,
1170 VideoSendStream::DegradationPreference::kDegradationDisabled);
1171 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001172 CreateFrame(sequence, kWidth, kHeight));
sprangc5d62e22017-04-02 23:53:04 -07001173 sink_.WaitForEncodedFrame(sequence++);
1174
1175 stats = stats_proxy_->GetStats();
1176 EXPECT_FALSE(stats.cpu_limited_resolution);
1177 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1178
1179 // Try to trigger overuse. Should not succeed.
1180 stats_proxy_->SetMockStats(mock_stats);
1181 vie_encoder_->TriggerCpuOveruse();
1182 stats_proxy_->ResetMockStats();
1183
1184 stats = stats_proxy_->GetStats();
1185 EXPECT_FALSE(stats.cpu_limited_resolution);
1186 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1187
1188 // Switch back the source with resolution adaptation enabled.
1189 vie_encoder_->SetSource(
1190 &video_source_,
1191 VideoSendStream::DegradationPreference::kMaintainFramerate);
asaperssonfab67072017-04-04 05:51:49 -07001192 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang84a37592017-02-10 07:04:27 -08001193 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001194 stats = stats_proxy_->GetStats();
1195 EXPECT_TRUE(stats.cpu_limited_resolution);
sprangc5d62e22017-04-02 23:53:04 -07001196 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001197
1198 // Trigger CPU normal usage.
1199 vie_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001200 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang84a37592017-02-10 07:04:27 -08001201 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001202 stats = stats_proxy_->GetStats();
1203 EXPECT_FALSE(stats.cpu_limited_resolution);
sprangc5d62e22017-04-02 23:53:04 -07001204 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1205
1206 // Back to the source with adaptation off, set it back to maintain-resolution.
1207 vie_encoder_->SetSource(
1208 &new_video_source,
1209 VideoSendStream::DegradationPreference::kMaintainResolution);
1210 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001211 CreateFrame(sequence, kWidth, kHeight));
sprangc5d62e22017-04-02 23:53:04 -07001212 sink_.WaitForEncodedFrame(sequence++);
1213 stats = stats_proxy_->GetStats();
1214 // Disabled, since we previously switched the source too disabled.
1215 EXPECT_FALSE(stats.cpu_limited_resolution);
1216 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1217
1218 // Trigger CPU normal usage.
1219 vie_encoder_->TriggerCpuNormalUsage();
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 EXPECT_FALSE(stats.cpu_limited_resolution);
1225 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001226 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001227
1228 vie_encoder_->Stop();
1229}
1230
Erik Språng08127a92016-11-16 16:41:30 +01001231TEST_F(ViEEncoderTest, StatsTracksPreferredBitrate) {
Erik Språng08127a92016-11-16 16:41:30 +01001232 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1233
asaperssonfab67072017-04-04 05:51:49 -07001234 const int kWidth = 1280;
1235 const int kHeight = 720;
1236 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
Erik Språng08127a92016-11-16 16:41:30 +01001237 sink_.WaitForEncodedFrame(1);
1238
1239 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1240 EXPECT_EQ(video_encoder_config_.max_bitrate_bps,
1241 stats.preferred_media_bitrate_bps);
1242
1243 vie_encoder_->Stop();
1244}
1245
kthelgason876222f2016-11-29 01:44:11 -08001246TEST_F(ViEEncoderTest, ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001247 const int kWidth = 1280;
1248 const int kHeight = 720;
kthelgason876222f2016-11-29 01:44:11 -08001249 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1250
asaperssonfab67072017-04-04 05:51:49 -07001251 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001252 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001253
asaperssonfab67072017-04-04 05:51:49 -07001254 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason876222f2016-11-29 01:44:11 -08001255 sink_.WaitForEncodedFrame(1);
1256
asaperssonfab67072017-04-04 05:51:49 -07001257 // Trigger scale down.
kthelgason5e13d412016-12-01 03:59:51 -08001258 vie_encoder_->TriggerQualityLow();
1259
asaperssonfab67072017-04-04 05:51:49 -07001260 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
kthelgason5e13d412016-12-01 03:59:51 -08001261 sink_.WaitForEncodedFrame(2);
1262
kthelgason876222f2016-11-29 01:44:11 -08001263 // Expect a scale down.
1264 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001265 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001266
asapersson02465b82017-04-10 01:12:52 -07001267 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001268 test::FrameForwarder new_video_source;
1269 vie_encoder_->SetSource(
1270 &new_video_source,
1271 VideoSendStream::DegradationPreference::kMaintainResolution);
1272
asaperssonfab67072017-04-04 05:51:49 -07001273 // Trigger scale down.
kthelgason876222f2016-11-29 01:44:11 -08001274 vie_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001275 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
kthelgason5e13d412016-12-01 03:59:51 -08001276 sink_.WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001277
asaperssonfab67072017-04-04 05:51:49 -07001278 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001279 EXPECT_EQ(std::numeric_limits<int>::max(),
1280 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001281
asaperssonfab67072017-04-04 05:51:49 -07001282 // Trigger scale up.
kthelgason876222f2016-11-29 01:44:11 -08001283 vie_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001284 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
kthelgason5e13d412016-12-01 03:59:51 -08001285 sink_.WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001286
asapersson02465b82017-04-10 01:12:52 -07001287 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001288 EXPECT_EQ(std::numeric_limits<int>::max(),
1289 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001290
1291 vie_encoder_->Stop();
1292}
1293
asapersson02465b82017-04-10 01:12:52 -07001294TEST_F(ViEEncoderTest, SkipsSameAdaptDownRequest_MaintainFramerateMode) {
1295 const int kWidth = 1280;
1296 const int kHeight = 720;
1297 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1298
1299 // Enable kMaintainFramerate preference, no initial limitation.
1300 test::FrameForwarder source;
1301 vie_encoder_->SetSource(
1302 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1303
1304 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1305 sink_.WaitForEncodedFrame(1);
1306 VerifyNoLimitation(source.sink_wants());
1307 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1308 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1309
1310 // Trigger adapt down, expect scaled down resolution.
1311 vie_encoder_->TriggerCpuOveruse();
1312 VerifyResolutionLimitationLessThan(source.sink_wants(), kWidth * kHeight);
1313 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1314 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1315 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1316
1317 // Trigger adapt down for same input resolution, expect no change.
1318 vie_encoder_->TriggerCpuOveruse();
1319 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1320 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1321 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1322
1323 vie_encoder_->Stop();
1324}
1325
1326TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_MaintainFramerateMode) {
1327 const int kWidth = 1280;
1328 const int kHeight = 720;
1329 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1330
1331 // Enable kMaintainFramerate preference, no initial limitation.
1332 test::FrameForwarder source;
1333 vie_encoder_->SetSource(
1334 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1335
1336 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1337 sink_.WaitForEncodedFrame(kWidth, kHeight);
1338 VerifyNoLimitation(source.sink_wants());
1339 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1340 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1341
1342 // Trigger adapt up, expect no change.
1343 vie_encoder_->TriggerCpuNormalUsage();
1344 VerifyNoLimitation(source.sink_wants());
1345 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1346 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1347
1348 vie_encoder_->Stop();
1349}
1350
1351TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_MaintainResolutionMode) {
1352 const int kWidth = 1280;
1353 const int kHeight = 720;
1354 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1355
1356 // Enable kMaintainResolution preference, no initial limitation.
1357 test::FrameForwarder source;
1358 vie_encoder_->SetSource(
1359 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
1360
1361 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1362 sink_.WaitForEncodedFrame(kWidth, kHeight);
1363 VerifyNoLimitation(source.sink_wants());
1364 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1365 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1366
1367 // Trigger adapt up, expect no change.
1368 vie_encoder_->TriggerCpuNormalUsage();
1369 VerifyNoLimitation(source.sink_wants());
1370 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1371 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1372
1373 vie_encoder_->Stop();
1374}
1375
1376TEST_F(ViEEncoderTest, AdaptsResolutionForLowQuality_MaintainFramerateMode) {
1377 const int kWidth = 1280;
1378 const int kHeight = 720;
1379 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1380
1381 // Enable kMaintainFramerate preference, no initial limitation.
1382 AdaptingFrameForwarder source;
1383 source.set_adaptation_enabled(true);
1384 vie_encoder_->SetSource(
1385 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1386
1387 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1388 sink_.WaitForEncodedFrame(1);
1389 VerifyNoLimitation(source.sink_wants());
1390 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1391 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1392
1393 // Trigger adapt down, expect scaled down resolution.
1394 vie_encoder_->TriggerQualityLow();
1395 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1396 sink_.WaitForEncodedFrame(2);
1397 VerifyResolutionLimitationLessThan(source.sink_wants(), kWidth * kHeight);
1398 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1399 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1400
1401 // Trigger adapt up, expect no restriction.
1402 vie_encoder_->TriggerQualityHigh();
1403 VerifyNoLimitation(source.sink_wants());
1404 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1405 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1406 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1407
1408 vie_encoder_->Stop();
1409}
1410
kthelgason5e13d412016-12-01 03:59:51 -08001411TEST_F(ViEEncoderTest, DoesNotScaleBelowSetLimit) {
kthelgason5e13d412016-12-01 03:59:51 -08001412 int frame_width = 1280;
1413 int frame_height = 720;
kthelgason5e13d412016-12-01 03:59:51 -08001414 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1415
1416 for (size_t i = 1; i <= 10; i++) {
1417 video_source_.IncomingCapturedFrame(
1418 CreateFrame(i, frame_width, frame_height));
1419 sink_.WaitForEncodedFrame(i);
asaperssonfab67072017-04-04 05:51:49 -07001420 // Trigger scale down.
kthelgason5e13d412016-12-01 03:59:51 -08001421 vie_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001422 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
kthelgason5e13d412016-12-01 03:59:51 -08001423 }
1424
1425 vie_encoder_->Stop();
1426}
1427
perkj803d97f2016-11-01 11:45:46 -07001428TEST_F(ViEEncoderTest, UMACpuLimitedResolutionInPercent) {
perkj803d97f2016-11-01 11:45:46 -07001429 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1430
asaperssonfab67072017-04-04 05:51:49 -07001431 const int kWidth = 640;
1432 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07001433
1434 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07001435 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
perkj803d97f2016-11-01 11:45:46 -07001436 sink_.WaitForEncodedFrame(i);
1437 }
1438
1439 vie_encoder_->TriggerCpuOveruse();
1440 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07001441 video_source_.IncomingCapturedFrame(CreateFrame(
1442 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
perkj803d97f2016-11-01 11:45:46 -07001443 sink_.WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples +
1444 i);
1445 }
1446
1447 vie_encoder_->Stop();
sprangf8ee65e2017-02-28 08:49:33 -08001448 vie_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07001449 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08001450
perkj803d97f2016-11-01 11:45:46 -07001451 EXPECT_EQ(1,
1452 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
1453 EXPECT_EQ(
1454 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
1455}
1456
sprang57c2fff2017-01-16 06:24:02 -08001457TEST_F(ViEEncoderTest, CallsBitrateObserver) {
1458 class MockBitrateObserver : public VideoBitrateAllocationObserver {
1459 public:
1460 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const BitrateAllocation&));
1461 } bitrate_observer;
1462 vie_encoder_->SetBitrateObserver(&bitrate_observer);
1463
1464 const int kDefaultFps = 30;
1465 const BitrateAllocation expected_bitrate =
1466 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08001467 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08001468
1469 // First called on bitrate updated, then again on first frame.
1470 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
1471 .Times(2);
kthelgason2bc68642017-02-07 07:02:22 -08001472 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08001473
1474 const int64_t kStartTimeMs = 1;
1475 video_source_.IncomingCapturedFrame(
1476 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
1477 sink_.WaitForEncodedFrame(kStartTimeMs);
1478
1479 // Not called on second frame.
1480 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
1481 .Times(0);
1482 video_source_.IncomingCapturedFrame(
1483 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
1484 sink_.WaitForEncodedFrame(kStartTimeMs + 1);
1485
1486 // Called after a process interval.
1487 const int64_t kProcessIntervalMs =
1488 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
1489 // TODO(sprang): ViEEncoder should die and/or get injectable clock.
1490 // Sleep for one processing interval plus one frame to avoid flakiness.
1491 SleepMs(kProcessIntervalMs + 1000 / kDefaultFps);
1492 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
1493 .Times(1);
1494 video_source_.IncomingCapturedFrame(CreateFrame(
1495 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
1496 sink_.WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
1497
1498 vie_encoder_->Stop();
1499}
1500
kthelgason2bc68642017-02-07 07:02:22 -08001501TEST_F(ViEEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07001502 const int kTooLowBitrateForFrameSizeBps = 10000;
1503 vie_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
1504 const int kWidth = 640;
1505 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08001506
asaperssonfab67072017-04-04 05:51:49 -07001507 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08001508
1509 // Expect to drop this frame, the wait should time out.
1510 sink_.ExpectDroppedFrame();
1511
1512 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07001513 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08001514
sprangc5d62e22017-04-02 23:53:04 -07001515 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08001516
asaperssonfab67072017-04-04 05:51:49 -07001517 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08001518 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001519 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08001520
1521 // Expect to drop this frame, the wait should time out.
1522 sink_.ExpectDroppedFrame();
1523
sprangc5d62e22017-04-02 23:53:04 -07001524 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08001525
1526 vie_encoder_->Stop();
1527}
1528
asaperssonfab67072017-04-04 05:51:49 -07001529TEST_F(ViEEncoderTest, NrOfDroppedFramesLimitedWhenBitrateIsTooLow) {
1530 const int kTooLowBitrateForFrameSizeBps = 10000;
1531 vie_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
1532 const int kWidth = 640;
1533 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08001534
1535 // We expect the n initial frames to get dropped.
1536 int i;
1537 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07001538 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08001539 sink_.ExpectDroppedFrame();
1540 }
1541 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07001542 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08001543 sink_.WaitForEncodedFrame(i);
1544
1545 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07001546 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08001547
1548 vie_encoder_->Stop();
1549}
1550
1551TEST_F(ViEEncoderTest, InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07001552 const int kWidth = 640;
1553 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08001554 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
1555
1556 // Set degradation preference.
1557 vie_encoder_->SetSource(
1558 &video_source_,
1559 VideoSendStream::DegradationPreference::kMaintainResolution);
1560
asaperssonfab67072017-04-04 05:51:49 -07001561 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08001562 // Frame should not be dropped, even if it's too large.
1563 sink_.WaitForEncodedFrame(1);
1564
1565 vie_encoder_->Stop();
1566}
1567
kthelgason2fc52542017-03-03 00:24:41 -08001568TEST_F(ViEEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07001569 const int kWidth = 640;
1570 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08001571 fake_encoder_.SetQualityScaling(false);
1572 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgasonb83797b2017-02-14 11:57:25 -08001573 // Force quality scaler reconfiguration by resetting the source.
1574 vie_encoder_->SetSource(&video_source_,
1575 VideoSendStream::DegradationPreference::kBalanced);
kthelgasonad9010c2017-02-14 00:46:51 -08001576
asaperssonfab67072017-04-04 05:51:49 -07001577 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08001578 // Frame should not be dropped, even if it's too large.
1579 sink_.WaitForEncodedFrame(1);
1580
1581 vie_encoder_->Stop();
1582 fake_encoder_.SetQualityScaling(true);
1583}
1584
asapersson02465b82017-04-10 01:12:52 -07001585TEST_F(ViEEncoderTest, FailingInitEncodeDoesntCauseCrash) {
1586 fake_encoder_.ForceInitEncodeFailure(true);
1587 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1588 ResetEncoder("VP8", 2, 1, true);
1589 const int kFrameWidth = 1280;
1590 const int kFrameHeight = 720;
1591 video_source_.IncomingCapturedFrame(
1592 CreateFrame(1, kFrameWidth, kFrameHeight));
1593 sink_.ExpectDroppedFrame();
1594 vie_encoder_->Stop();
1595}
1596
sprangb1ca0732017-02-01 08:38:12 -08001597// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
1598TEST_F(ViEEncoderTest, AdaptsResolutionOnOveruse) {
1599 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1600
1601 const int kFrameWidth = 1280;
1602 const int kFrameHeight = 720;
1603 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
1604 // requested by ViEEncoder::VideoSourceProxy::RequestResolutionLowerThan().
1605 video_source_.set_adaptation_enabled(true);
1606
1607 video_source_.IncomingCapturedFrame(
1608 CreateFrame(1, kFrameWidth, kFrameHeight));
1609 sink_.WaitForEncodedFrame(kFrameWidth, kFrameHeight);
1610
1611 // Trigger CPU overuse, downscale by 3/4.
1612 vie_encoder_->TriggerCpuOveruse();
1613 video_source_.IncomingCapturedFrame(
1614 CreateFrame(2, kFrameWidth, kFrameHeight));
1615 sink_.WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
1616
asaperssonfab67072017-04-04 05:51:49 -07001617 // Trigger CPU normal use, return to original resolution.
sprangb1ca0732017-02-01 08:38:12 -08001618 vie_encoder_->TriggerCpuNormalUsage();
1619 video_source_.IncomingCapturedFrame(
1620 CreateFrame(3, kFrameWidth, kFrameHeight));
1621 sink_.WaitForEncodedFrame(kFrameWidth, kFrameHeight);
1622
1623 vie_encoder_->Stop();
1624}
sprangfe627f32017-03-29 08:24:59 -07001625
asapersson02465b82017-04-10 01:12:52 -07001626TEST_F(ViEEncoderTest, AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07001627 const int kDefaultFramerateFps = 30;
1628 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kDefaultFramerateFps;
1629 const int kFrameWidth = 1280;
1630 const int kFrameHeight = 720;
1631 rtc::ScopedFakeClock fake_clock;
1632
1633 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1634 vie_encoder_->SetSource(
1635 &video_source_,
1636 VideoSendStream::DegradationPreference::kMaintainResolution);
1637 video_source_.set_adaptation_enabled(true);
1638
1639 fake_clock.SetTimeMicros(kFrameIntervalMs * 1000);
1640 int64_t timestamp_ms = kFrameIntervalMs;
1641
1642 video_source_.IncomingCapturedFrame(
1643 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1644 sink_.WaitForEncodedFrame(timestamp_ms);
1645
1646 // Try to trigger overuse. No fps estimate available => no effect.
1647 vie_encoder_->TriggerCpuOveruse();
1648
1649 // Insert frames for one second to get a stable estimate.
1650 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1651 timestamp_ms += kFrameIntervalMs;
1652 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1653 video_source_.IncomingCapturedFrame(
1654 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1655 sink_.WaitForEncodedFrame(timestamp_ms);
1656 }
1657
1658 // Trigger CPU overuse, reduce framerate by 2/3.
1659 vie_encoder_->TriggerCpuOveruse();
1660 int num_frames_dropped = 0;
1661 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1662 timestamp_ms += kFrameIntervalMs;
1663 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1664 video_source_.IncomingCapturedFrame(
1665 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1666 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
1667 ++num_frames_dropped;
1668 } else {
1669 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
1670 }
1671 }
1672
1673 // TODO(sprang): Find where there's rounding errors or stuff causing the
1674 // margin here to be a little larger than we'd like (input fps estimate is
1675 // off) and the frame dropping is a little too aggressive.
1676 const int kErrorMargin = 5;
1677 EXPECT_NEAR(num_frames_dropped,
1678 kDefaultFramerateFps - (kDefaultFramerateFps * 2 / 3),
1679 kErrorMargin);
1680
1681 // Trigger CPU overuse, reduce framerate by 2/3 again.
1682 vie_encoder_->TriggerCpuOveruse();
1683 num_frames_dropped = 0;
1684 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1685 timestamp_ms += kFrameIntervalMs;
1686 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1687 video_source_.IncomingCapturedFrame(
1688 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1689 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
1690 ++num_frames_dropped;
1691 } else {
1692 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
1693 }
1694 }
1695 EXPECT_NEAR(num_frames_dropped,
1696 kDefaultFramerateFps - (kDefaultFramerateFps * 4 / 9),
1697 kErrorMargin);
1698
1699 // Go back up one step.
1700 vie_encoder_->TriggerCpuNormalUsage();
1701 num_frames_dropped = 0;
1702 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1703 timestamp_ms += kFrameIntervalMs;
1704 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1705 video_source_.IncomingCapturedFrame(
1706 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1707 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
1708 ++num_frames_dropped;
1709 } else {
1710 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
1711 }
1712 }
1713 EXPECT_NEAR(num_frames_dropped,
1714 kDefaultFramerateFps - (kDefaultFramerateFps * 2 / 3),
1715 kErrorMargin);
1716
1717 // Go back up to original mode.
1718 vie_encoder_->TriggerCpuNormalUsage();
1719 num_frames_dropped = 0;
1720 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1721 timestamp_ms += kFrameIntervalMs;
1722 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1723 video_source_.IncomingCapturedFrame(
1724 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1725 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
1726 ++num_frames_dropped;
1727 } else {
1728 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
1729 }
1730 }
1731 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
1732
1733 vie_encoder_->Stop();
1734}
1735
1736TEST_F(ViEEncoderTest, DoesntAdaptDownPastMinFramerate) {
1737 const int kFramerateFps = 5;
1738 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
1739 const int kMinFpsFrameInterval = rtc::kNumMillisecsPerSec / kMinFramerateFps;
1740 const int kFrameWidth = 1280;
1741 const int kFrameHeight = 720;
1742
1743 rtc::ScopedFakeClock fake_clock;
1744 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1745 vie_encoder_->SetSource(
1746 &video_source_,
1747 VideoSendStream::DegradationPreference::kMaintainResolution);
1748 video_source_.set_adaptation_enabled(true);
1749
1750 fake_clock.SetTimeMicros(kFrameIntervalMs * 1000);
1751 int64_t timestamp_ms = kFrameIntervalMs;
1752
1753 // Trigger overuse as much as we can.
1754 for (int i = 0; i < ViEEncoder::kMaxCpuResolutionDowngrades; ++i) {
1755 // Insert frames to get a new fps estimate...
1756 for (int j = 0; j < kFramerateFps; ++j) {
1757 video_source_.IncomingCapturedFrame(
1758 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1759 timestamp_ms += kFrameIntervalMs;
1760 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1761 }
1762 // ...and then try to adapt again.
1763 vie_encoder_->TriggerCpuOveruse();
1764 }
1765
1766 // Drain any frame in the pipeline.
1767 sink_.WaitForFrame(kDefaultTimeoutMs);
1768
1769 // Insert frames at min fps, all should go through.
1770 for (int i = 0; i < 10; ++i) {
1771 timestamp_ms += kMinFpsFrameInterval;
1772 fake_clock.AdvanceTimeMicros(kMinFpsFrameInterval * 1000);
1773 video_source_.IncomingCapturedFrame(
1774 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1775 sink_.WaitForEncodedFrame(timestamp_ms);
1776 }
1777 vie_encoder_->Stop();
1778}
perkj26091b12016-09-01 01:17:40 -07001779} // namespace webrtc