blob: 7516a2e8ffe68b80ad9c913d292936a5fde4b3d4 [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"
sprang3ea3c772017-03-30 07:23:48 -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
sprang3ea3c772017-03-30 07:23:48 -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) {}
134 virtual ~AdaptingFrameForwarder() {}
135
136 void set_adaptation_enabled(bool enabled) {
137 rtc::CritScope cs(&crit_);
138 adaptation_enabled_ = enabled;
139 }
140
141 bool adaption_enabled() {
142 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;
sprang3ea3c772017-03-30 07:23:48 -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_);
sprang3ea3c772017-03-30 07:23:48 -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};
sprang3ea3c772017-03-30 07:23:48 -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_(),
sprang3ea3c772017-03-30 07:23:48 -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 */);
sprang3ea3c772017-03-30 07:23:48 -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);
sprang3ea3c772017-03-30 07:23:48 -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
perkjfa10b552016-10-02 23:45:26 -0700293 VideoCodec codec_config() {
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) {
sprang3ea3c772017-03-30 07:23:48 -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
sprang3ea3c772017-03-30 07:23:48 -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
Per512ecb32016-09-23 15:52:06 +0200434 int number_of_reconfigurations() {
435 rtc::CritScope lock(&crit_);
436 return number_of_reconfigurations_;
437 }
438
439 int last_min_transmit_bitrate() {
440 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_;
sprang3ea3c772017-03-30 07:23:48 -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;
sprang3ea3c772017-03-30 07:23:48 -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);
sprang3ea3c772017-03-30 07:23:48 -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.
sprang3ea3c772017-03-30 07:23:48 -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);
sprang3ea3c772017-03-30 07:23:48 -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(
sprang3ea3c772017-03-30 07:23:48 -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,
sprang3ea3c772017-03-30 07:23:48 -0700759 video_source_.sink_wants().max_pixel_count);
perkj803d97f2016-11-01 11:45:46 -0700760
761 vie_encoder_->Stop();
762}
763
sprang3ea3c772017-03-30 07:23:48 -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);
sprang3ea3c772017-03-30 07:23:48 -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
sprang3ea3c772017-03-30 07:23:48 -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(
sprang3ea3c772017-03-30 07:23:48 -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(
sprang3ea3c772017-03-30 07:23:48 -0700787 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
788 sink_.WaitForEncodedFrame(frame_timestamp);
789 frame_timestamp += kFrameIntervalMs;
sprang72acf252017-03-21 11:54:11 -0700790
sprang3ea3c772017-03-30 07:23:48 -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
sprang3ea3c772017-03-30 07:23:48 -0700805 // Initially no degradation registered.
sprang84a37592017-02-10 07:04:27 -0800806 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprang3ea3c772017-03-30 07:23:48 -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
sprang3ea3c772017-03-30 07:23:48 -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(
sprang3ea3c772017-03-30 07:23:48 -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);
sprang3ea3c772017-03-30 07:23:48 -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.
sprang3ea3c772017-03-30 07:23:48 -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);
sprang3ea3c772017-03-30 07:23:48 -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
877TEST_F(ViEEncoderTest, StatsTracksAdaptationStats) {
perkj803d97f2016-11-01 11:45:46 -0700878 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
879
880 int frame_width = 1280;
881 int frame_height = 720;
882
883 video_source_.IncomingCapturedFrame(
884 CreateFrame(1, frame_width, frame_height));
885 sink_.WaitForEncodedFrame(1);
886 VideoSendStream::Stats stats = stats_proxy_->GetStats();
887 EXPECT_FALSE(stats.cpu_limited_resolution);
888 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
889
890 // Trigger CPU overuse.
891 vie_encoder_->TriggerCpuOveruse();
892 video_source_.IncomingCapturedFrame(
893 CreateFrame(2, frame_width, frame_height));
894 sink_.WaitForEncodedFrame(2);
895
896 stats = stats_proxy_->GetStats();
897 EXPECT_TRUE(stats.cpu_limited_resolution);
898 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
899
900 // Trigger CPU normal use.
901 vie_encoder_->TriggerCpuNormalUsage();
902 video_source_.IncomingCapturedFrame(
903 CreateFrame(3, frame_width, frame_height));
904 sink_.WaitForEncodedFrame(3);
905
906 stats = stats_proxy_->GetStats();
907 EXPECT_FALSE(stats.cpu_limited_resolution);
908 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
909
910 vie_encoder_->Stop();
911}
912
kthelgason876222f2016-11-29 01:44:11 -0800913TEST_F(ViEEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
kthelgason876222f2016-11-29 01:44:11 -0800914 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
915
916 int frame_width = 1280;
917 int frame_height = 720;
918 video_source_.IncomingCapturedFrame(
919 CreateFrame(1, frame_width, frame_height));
920 sink_.WaitForEncodedFrame(1);
921
922 VideoSendStream::Stats stats = stats_proxy_->GetStats();
923 EXPECT_FALSE(stats.cpu_limited_resolution);
924 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
925
926 vie_encoder_->TriggerCpuOveruse();
927
928 video_source_.IncomingCapturedFrame(
929 CreateFrame(2, frame_width, frame_height));
930 sink_.WaitForEncodedFrame(2);
931 stats = stats_proxy_->GetStats();
932 EXPECT_TRUE(stats.cpu_limited_resolution);
933 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
934
935 // Set new source with adaptation still enabled.
936 test::FrameForwarder new_video_source;
sprang3ea3c772017-03-30 07:23:48 -0700937 vie_encoder_->SetSource(
938 &new_video_source,
939 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -0800940
941 new_video_source.IncomingCapturedFrame(
942 CreateFrame(3, frame_width, frame_height));
943 sink_.WaitForEncodedFrame(3);
944 stats = stats_proxy_->GetStats();
945 EXPECT_TRUE(stats.cpu_limited_resolution);
946 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
947
948 // Set adaptation disabled.
949 vie_encoder_->SetSource(
950 &new_video_source,
sprang3ea3c772017-03-30 07:23:48 -0700951 VideoSendStream::DegradationPreference::kDegradationDisabled);
kthelgason876222f2016-11-29 01:44:11 -0800952
953 new_video_source.IncomingCapturedFrame(
954 CreateFrame(4, frame_width, frame_height));
955 sink_.WaitForEncodedFrame(4);
956 stats = stats_proxy_->GetStats();
957 EXPECT_FALSE(stats.cpu_limited_resolution);
958 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
959
960 // Set adaptation back to enabled.
sprang3ea3c772017-03-30 07:23:48 -0700961 vie_encoder_->SetSource(
962 &new_video_source,
963 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -0800964
965 new_video_source.IncomingCapturedFrame(
966 CreateFrame(5, frame_width, frame_height));
967 sink_.WaitForEncodedFrame(5);
968 stats = stats_proxy_->GetStats();
969 EXPECT_TRUE(stats.cpu_limited_resolution);
970 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
971
972 vie_encoder_->TriggerCpuNormalUsage();
973
974 new_video_source.IncomingCapturedFrame(
975 CreateFrame(6, frame_width, frame_height));
976 sink_.WaitForEncodedFrame(6);
977 stats = stats_proxy_->GetStats();
978 EXPECT_FALSE(stats.cpu_limited_resolution);
979 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
980
981 vie_encoder_->Stop();
982}
983
984TEST_F(ViEEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
kthelgason876222f2016-11-29 01:44:11 -0800985 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
986
987 int frame_width = 1280;
988 int frame_height = 720;
989 video_source_.IncomingCapturedFrame(
990 CreateFrame(1, frame_width, frame_height));
991 sink_.WaitForEncodedFrame(1);
992
993 VideoSendStream::Stats stats = stats_proxy_->GetStats();
994 EXPECT_FALSE(stats.cpu_limited_resolution);
995 EXPECT_FALSE(stats.bw_limited_resolution);
996 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
997
998 // Set new source with adaptation still enabled.
999 test::FrameForwarder new_video_source;
1000 vie_encoder_->SetSource(&new_video_source,
1001 VideoSendStream::DegradationPreference::kBalanced);
1002
1003 new_video_source.IncomingCapturedFrame(
1004 CreateFrame(2, frame_width, frame_height));
1005 sink_.WaitForEncodedFrame(2);
1006 stats = stats_proxy_->GetStats();
1007 EXPECT_FALSE(stats.cpu_limited_resolution);
1008 EXPECT_FALSE(stats.bw_limited_resolution);
1009 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1010
1011 vie_encoder_->TriggerQualityLow();
1012
1013 new_video_source.IncomingCapturedFrame(
1014 CreateFrame(3, frame_width, frame_height));
1015 sink_.WaitForEncodedFrame(3);
1016 stats = stats_proxy_->GetStats();
1017 EXPECT_FALSE(stats.cpu_limited_resolution);
1018 EXPECT_TRUE(stats.bw_limited_resolution);
1019
1020 vie_encoder_->SetSource(&new_video_source,
1021 VideoSendStream::DegradationPreference::kBalanced);
1022
1023 new_video_source.IncomingCapturedFrame(
1024 CreateFrame(4, frame_width, frame_height));
1025 sink_.WaitForEncodedFrame(4);
1026 stats = stats_proxy_->GetStats();
1027 EXPECT_FALSE(stats.cpu_limited_resolution);
1028 EXPECT_TRUE(stats.bw_limited_resolution);
1029
1030 // Set adaptation disabled.
1031 vie_encoder_->SetSource(
1032 &new_video_source,
1033 VideoSendStream::DegradationPreference::kMaintainResolution);
1034
1035 new_video_source.IncomingCapturedFrame(
1036 CreateFrame(5, frame_width, frame_height));
1037 sink_.WaitForEncodedFrame(5);
1038 stats = stats_proxy_->GetStats();
1039 EXPECT_FALSE(stats.cpu_limited_resolution);
1040 EXPECT_FALSE(stats.bw_limited_resolution);
1041
1042 vie_encoder_->Stop();
1043}
1044
perkj803d97f2016-11-01 11:45:46 -07001045TEST_F(ViEEncoderTest, StatsTracksAdaptationStatsWhenSwitchingSource) {
perkj803d97f2016-11-01 11:45:46 -07001046 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1047
perkj803d97f2016-11-01 11:45:46 -07001048 int frame_width = 1280;
1049 int frame_height = 720;
sprang84a37592017-02-10 07:04:27 -08001050 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001051
1052 video_source_.IncomingCapturedFrame(
sprang84a37592017-02-10 07:04:27 -08001053 CreateFrame(sequence, frame_width, frame_height));
1054 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001055
1056 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001057 EXPECT_FALSE(stats.cpu_limited_resolution);
1058 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1059
1060 // Trigger CPU overuse again, should now adapt down.
1061 vie_encoder_->TriggerCpuOveruse();
1062 video_source_.IncomingCapturedFrame(
1063 CreateFrame(sequence, frame_width, frame_height));
1064 sink_.WaitForEncodedFrame(sequence++);
1065
1066 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001067 EXPECT_TRUE(stats.cpu_limited_resolution);
1068 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1069
1070 // Set new source with adaptation still enabled.
1071 test::FrameForwarder new_video_source;
sprang3ea3c772017-03-30 07:23:48 -07001072 vie_encoder_->SetSource(
1073 &new_video_source,
1074 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001075
1076 new_video_source.IncomingCapturedFrame(
sprang84a37592017-02-10 07:04:27 -08001077 CreateFrame(sequence, frame_width, frame_height));
1078 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001079 stats = stats_proxy_->GetStats();
1080 EXPECT_TRUE(stats.cpu_limited_resolution);
1081 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1082
sprang3ea3c772017-03-30 07:23:48 -07001083 // Set cpu adaptation by frame dropping.
perkj803d97f2016-11-01 11:45:46 -07001084 vie_encoder_->SetSource(
1085 &new_video_source,
1086 VideoSendStream::DegradationPreference::kMaintainResolution);
1087 new_video_source.IncomingCapturedFrame(
sprang84a37592017-02-10 07:04:27 -08001088 CreateFrame(sequence, frame_width, frame_height));
1089 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001090 stats = stats_proxy_->GetStats();
sprang3ea3c772017-03-30 07:23:48 -07001091 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001092 EXPECT_FALSE(stats.cpu_limited_resolution);
1093 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1094
sprang3ea3c772017-03-30 07:23:48 -07001095 // Force an input frame rate to be available, or the adaptation call won't
1096 // know what framerate to adapt form.
1097 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1098 mock_stats.input_frame_rate = 30;
1099 stats_proxy_->SetMockStats(mock_stats);
1100 vie_encoder_->TriggerCpuOveruse();
1101 stats_proxy_->ResetMockStats();
1102
1103 new_video_source.IncomingCapturedFrame(
1104 CreateFrame(sequence, frame_width, frame_height));
1105 sink_.WaitForEncodedFrame(sequence++);
1106
1107 // Framerate now adapted.
1108 stats = stats_proxy_->GetStats();
1109 EXPECT_TRUE(stats.cpu_limited_resolution);
1110 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1111
1112 // Disable CPU adaptation.
1113 vie_encoder_->SetSource(
1114 &new_video_source,
1115 VideoSendStream::DegradationPreference::kDegradationDisabled);
1116 new_video_source.IncomingCapturedFrame(
1117 CreateFrame(sequence, frame_width, frame_height));
1118 sink_.WaitForEncodedFrame(sequence++);
1119
1120 stats = stats_proxy_->GetStats();
1121 EXPECT_FALSE(stats.cpu_limited_resolution);
1122 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1123
1124 // Try to trigger overuse. Should not succeed.
1125 stats_proxy_->SetMockStats(mock_stats);
1126 vie_encoder_->TriggerCpuOveruse();
1127 stats_proxy_->ResetMockStats();
1128
1129 stats = stats_proxy_->GetStats();
1130 EXPECT_FALSE(stats.cpu_limited_resolution);
1131 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1132
1133 // Switch back the source with resolution adaptation enabled.
1134 vie_encoder_->SetSource(
1135 &video_source_,
1136 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001137 video_source_.IncomingCapturedFrame(
sprang84a37592017-02-10 07:04:27 -08001138 CreateFrame(sequence, frame_width, frame_height));
1139 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001140 stats = stats_proxy_->GetStats();
1141 EXPECT_TRUE(stats.cpu_limited_resolution);
sprang3ea3c772017-03-30 07:23:48 -07001142 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001143
1144 // Trigger CPU normal usage.
1145 vie_encoder_->TriggerCpuNormalUsage();
1146 video_source_.IncomingCapturedFrame(
sprang84a37592017-02-10 07:04:27 -08001147 CreateFrame(sequence, frame_width, frame_height));
1148 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001149 stats = stats_proxy_->GetStats();
1150 EXPECT_FALSE(stats.cpu_limited_resolution);
sprang3ea3c772017-03-30 07:23:48 -07001151 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1152
1153 // Back to the source with adaptation off, set it back to maintain-resolution.
1154 vie_encoder_->SetSource(
1155 &new_video_source,
1156 VideoSendStream::DegradationPreference::kMaintainResolution);
1157 new_video_source.IncomingCapturedFrame(
1158 CreateFrame(sequence, frame_width, frame_height));
1159 sink_.WaitForEncodedFrame(sequence++);
1160 stats = stats_proxy_->GetStats();
1161 // Disabled, since we previously switched the source too disabled.
1162 EXPECT_FALSE(stats.cpu_limited_resolution);
1163 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1164
1165 // Trigger CPU normal usage.
1166 vie_encoder_->TriggerCpuNormalUsage();
1167 new_video_source.IncomingCapturedFrame(
1168 CreateFrame(sequence, frame_width, frame_height));
1169 sink_.WaitForEncodedFrame(sequence++);
1170 stats = stats_proxy_->GetStats();
1171 EXPECT_FALSE(stats.cpu_limited_resolution);
1172 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001173
1174 vie_encoder_->Stop();
1175}
1176
Erik Språng08127a92016-11-16 16:41:30 +01001177TEST_F(ViEEncoderTest, StatsTracksPreferredBitrate) {
Erik Språng08127a92016-11-16 16:41:30 +01001178 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1179
1180 video_source_.IncomingCapturedFrame(CreateFrame(1, 1280, 720));
1181 sink_.WaitForEncodedFrame(1);
1182
1183 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1184 EXPECT_EQ(video_encoder_config_.max_bitrate_bps,
1185 stats.preferred_media_bitrate_bps);
1186
1187 vie_encoder_->Stop();
1188}
1189
kthelgason876222f2016-11-29 01:44:11 -08001190TEST_F(ViEEncoderTest, ScalingUpAndDownDoesNothingWithMaintainResolution) {
kthelgason876222f2016-11-29 01:44:11 -08001191 int frame_width = 1280;
1192 int frame_height = 720;
1193 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1194
1195 // Expect no scaling to begin with
sprang84a37592017-02-10 07:04:27 -08001196 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
sprang3ea3c772017-03-30 07:23:48 -07001197 EXPECT_EQ(std::numeric_limits<int>::max(),
1198 video_source_.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001199
kthelgason876222f2016-11-29 01:44:11 -08001200 video_source_.IncomingCapturedFrame(
1201 CreateFrame(1, frame_width, frame_height));
1202 sink_.WaitForEncodedFrame(1);
1203
kthelgason5e13d412016-12-01 03:59:51 -08001204 // Trigger scale down
1205 vie_encoder_->TriggerQualityLow();
1206
1207 video_source_.IncomingCapturedFrame(
1208 CreateFrame(2, frame_width, frame_height));
1209 sink_.WaitForEncodedFrame(2);
1210
kthelgason876222f2016-11-29 01:44:11 -08001211 // Expect a scale down.
1212 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
sprang3ea3c772017-03-30 07:23:48 -07001213 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
kthelgason876222f2016-11-29 01:44:11 -08001214 frame_width * frame_height);
1215
1216 // Set adaptation disabled.
1217 test::FrameForwarder new_video_source;
1218 vie_encoder_->SetSource(
1219 &new_video_source,
1220 VideoSendStream::DegradationPreference::kMaintainResolution);
1221
1222 // Trigger scale down
1223 vie_encoder_->TriggerQualityLow();
1224 new_video_source.IncomingCapturedFrame(
kthelgason5e13d412016-12-01 03:59:51 -08001225 CreateFrame(3, frame_width, frame_height));
1226 sink_.WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001227
1228 // Expect no scaling
sprang3ea3c772017-03-30 07:23:48 -07001229 EXPECT_EQ(std::numeric_limits<int>::max(),
1230 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001231
1232 // Trigger scale up
1233 vie_encoder_->TriggerQualityHigh();
1234 new_video_source.IncomingCapturedFrame(
kthelgason5e13d412016-12-01 03:59:51 -08001235 CreateFrame(4, frame_width, frame_height));
1236 sink_.WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001237
1238 // Expect nothing to change, still no scaling
sprang3ea3c772017-03-30 07:23:48 -07001239 EXPECT_EQ(std::numeric_limits<int>::max(),
1240 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001241
1242 vie_encoder_->Stop();
1243}
1244
kthelgason5e13d412016-12-01 03:59:51 -08001245TEST_F(ViEEncoderTest, DoesNotScaleBelowSetLimit) {
kthelgason5e13d412016-12-01 03:59:51 -08001246 int frame_width = 1280;
1247 int frame_height = 720;
kthelgason5e13d412016-12-01 03:59:51 -08001248 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1249
1250 for (size_t i = 1; i <= 10; i++) {
1251 video_source_.IncomingCapturedFrame(
1252 CreateFrame(i, frame_width, frame_height));
1253 sink_.WaitForEncodedFrame(i);
1254 // Trigger scale down
1255 vie_encoder_->TriggerQualityLow();
sprang3ea3c772017-03-30 07:23:48 -07001256 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
kthelgason5e13d412016-12-01 03:59:51 -08001257 }
1258
1259 vie_encoder_->Stop();
1260}
1261
perkj803d97f2016-11-01 11:45:46 -07001262TEST_F(ViEEncoderTest, UMACpuLimitedResolutionInPercent) {
perkj803d97f2016-11-01 11:45:46 -07001263 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1264
1265 int frame_width = 640;
1266 int frame_height = 360;
1267
1268 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
1269 video_source_.IncomingCapturedFrame(
1270 CreateFrame(i, frame_width, frame_height));
1271 sink_.WaitForEncodedFrame(i);
1272 }
1273
1274 vie_encoder_->TriggerCpuOveruse();
1275 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
1276 video_source_.IncomingCapturedFrame(
1277 CreateFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i,
1278 frame_width, frame_height));
1279 sink_.WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples +
1280 i);
1281 }
1282
1283 vie_encoder_->Stop();
sprangf8ee65e2017-02-28 08:49:33 -08001284 vie_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07001285 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08001286
perkj803d97f2016-11-01 11:45:46 -07001287 EXPECT_EQ(1,
1288 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
1289 EXPECT_EQ(
1290 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
1291}
1292
sprang57c2fff2017-01-16 06:24:02 -08001293TEST_F(ViEEncoderTest, CallsBitrateObserver) {
1294 class MockBitrateObserver : public VideoBitrateAllocationObserver {
1295 public:
1296 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const BitrateAllocation&));
1297 } bitrate_observer;
1298 vie_encoder_->SetBitrateObserver(&bitrate_observer);
1299
1300 const int kDefaultFps = 30;
1301 const BitrateAllocation expected_bitrate =
1302 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08001303 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08001304
1305 // First called on bitrate updated, then again on first frame.
1306 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
1307 .Times(2);
kthelgason2bc68642017-02-07 07:02:22 -08001308 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08001309
1310 const int64_t kStartTimeMs = 1;
1311 video_source_.IncomingCapturedFrame(
1312 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
1313 sink_.WaitForEncodedFrame(kStartTimeMs);
1314
1315 // Not called on second frame.
1316 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
1317 .Times(0);
1318 video_source_.IncomingCapturedFrame(
1319 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
1320 sink_.WaitForEncodedFrame(kStartTimeMs + 1);
1321
1322 // Called after a process interval.
1323 const int64_t kProcessIntervalMs =
1324 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
1325 // TODO(sprang): ViEEncoder should die and/or get injectable clock.
1326 // Sleep for one processing interval plus one frame to avoid flakiness.
1327 SleepMs(kProcessIntervalMs + 1000 / kDefaultFps);
1328 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
1329 .Times(1);
1330 video_source_.IncomingCapturedFrame(CreateFrame(
1331 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
1332 sink_.WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
1333
1334 vie_encoder_->Stop();
1335}
1336
kthelgason2bc68642017-02-07 07:02:22 -08001337TEST_F(ViEEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
1338 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
1339 int frame_width = 640;
1340 int frame_height = 360;
1341
1342 video_source_.IncomingCapturedFrame(
1343 CreateFrame(1, frame_width, frame_height));
1344
1345 // Expect to drop this frame, the wait should time out.
1346 sink_.ExpectDroppedFrame();
1347
1348 // Expect the sink_wants to specify a scaled frame.
sprang3ea3c772017-03-30 07:23:48 -07001349 EXPECT_LT(video_source_.sink_wants().max_pixel_count, 1000 * 1000);
kthelgason2bc68642017-02-07 07:02:22 -08001350
sprang3ea3c772017-03-30 07:23:48 -07001351 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08001352
1353 // Next frame is scaled
1354 video_source_.IncomingCapturedFrame(
1355 CreateFrame(2, frame_width * 3 / 4, frame_height * 3 / 4));
1356
1357 // Expect to drop this frame, the wait should time out.
1358 sink_.ExpectDroppedFrame();
1359
sprang3ea3c772017-03-30 07:23:48 -07001360 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08001361
1362 vie_encoder_->Stop();
1363}
1364
kthelgason2fc52542017-03-03 00:24:41 -08001365TEST_F(ViEEncoderTest, NrOfDroppedFramesLimited) {
kthelgason2bc68642017-02-07 07:02:22 -08001366 // 1kbps. This can never be achieved.
1367 vie_encoder_->OnBitrateUpdated(1000, 0, 0);
1368 int frame_width = 640;
1369 int frame_height = 360;
1370
1371 // We expect the n initial frames to get dropped.
1372 int i;
1373 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
1374 video_source_.IncomingCapturedFrame(
1375 CreateFrame(i, frame_width, frame_height));
1376 sink_.ExpectDroppedFrame();
1377 }
1378 // The n+1th frame should not be dropped, even though it's size is too large.
1379 video_source_.IncomingCapturedFrame(
1380 CreateFrame(i, frame_width, frame_height));
1381 sink_.WaitForEncodedFrame(i);
1382
1383 // Expect the sink_wants to specify a scaled frame.
sprang3ea3c772017-03-30 07:23:48 -07001384 EXPECT_LT(video_source_.sink_wants().max_pixel_count, 1000 * 1000);
kthelgason2bc68642017-02-07 07:02:22 -08001385
1386 vie_encoder_->Stop();
1387}
1388
1389TEST_F(ViEEncoderTest, InitialFrameDropOffWithMaintainResolutionPreference) {
1390 int frame_width = 640;
1391 int frame_height = 360;
1392 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
1393
1394 // Set degradation preference.
1395 vie_encoder_->SetSource(
1396 &video_source_,
1397 VideoSendStream::DegradationPreference::kMaintainResolution);
1398
1399 video_source_.IncomingCapturedFrame(
1400 CreateFrame(1, frame_width, frame_height));
1401 // Frame should not be dropped, even if it's too large.
1402 sink_.WaitForEncodedFrame(1);
1403
1404 vie_encoder_->Stop();
1405}
1406
kthelgason2fc52542017-03-03 00:24:41 -08001407TEST_F(ViEEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
kthelgasonad9010c2017-02-14 00:46:51 -08001408 int frame_width = 640;
1409 int frame_height = 360;
1410 fake_encoder_.SetQualityScaling(false);
1411 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgasonb83797b2017-02-14 11:57:25 -08001412 // Force quality scaler reconfiguration by resetting the source.
1413 vie_encoder_->SetSource(&video_source_,
1414 VideoSendStream::DegradationPreference::kBalanced);
kthelgasonad9010c2017-02-14 00:46:51 -08001415
1416 video_source_.IncomingCapturedFrame(
1417 CreateFrame(1, frame_width, frame_height));
1418 // Frame should not be dropped, even if it's too large.
1419 sink_.WaitForEncodedFrame(1);
1420
1421 vie_encoder_->Stop();
1422 fake_encoder_.SetQualityScaling(true);
1423}
1424
sprangb1ca0732017-02-01 08:38:12 -08001425// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
1426TEST_F(ViEEncoderTest, AdaptsResolutionOnOveruse) {
1427 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1428
1429 const int kFrameWidth = 1280;
1430 const int kFrameHeight = 720;
1431 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
1432 // requested by ViEEncoder::VideoSourceProxy::RequestResolutionLowerThan().
1433 video_source_.set_adaptation_enabled(true);
1434
1435 video_source_.IncomingCapturedFrame(
1436 CreateFrame(1, kFrameWidth, kFrameHeight));
1437 sink_.WaitForEncodedFrame(kFrameWidth, kFrameHeight);
1438
1439 // Trigger CPU overuse, downscale by 3/4.
1440 vie_encoder_->TriggerCpuOveruse();
1441 video_source_.IncomingCapturedFrame(
1442 CreateFrame(2, kFrameWidth, kFrameHeight));
1443 sink_.WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
1444
sprang3ea3c772017-03-30 07:23:48 -07001445 // Trigger CPU normal use, return to original resolution;
sprangb1ca0732017-02-01 08:38:12 -08001446 vie_encoder_->TriggerCpuNormalUsage();
1447 video_source_.IncomingCapturedFrame(
1448 CreateFrame(3, kFrameWidth, kFrameHeight));
1449 sink_.WaitForEncodedFrame(kFrameWidth, kFrameHeight);
1450
1451 vie_encoder_->Stop();
1452}
sprangfe627f32017-03-29 08:24:59 -07001453
1454TEST_F(ViEEncoderTest, FailingInitEncodeDoesntCauseCrash) {
1455 fake_encoder_.ForceInitEncodeFailure(true);
1456 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1457 ResetEncoder("VP8", 2, 1, true);
1458 const int kFrameWidth = 1280;
1459 const int kFrameHeight = 720;
1460 video_source_.IncomingCapturedFrame(
1461 CreateFrame(1, kFrameWidth, kFrameHeight));
1462 sink_.ExpectDroppedFrame();
1463 vie_encoder_->Stop();
1464}
sprang3ea3c772017-03-30 07:23:48 -07001465
1466TEST_F(ViEEncoderTest, AdaptsFrameOnOveruseWithMaintainResolution) {
1467 const int kDefaultFramerateFps = 30;
1468 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kDefaultFramerateFps;
1469 const int kFrameWidth = 1280;
1470 const int kFrameHeight = 720;
1471 rtc::ScopedFakeClock fake_clock;
1472
1473 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1474 vie_encoder_->SetSource(
1475 &video_source_,
1476 VideoSendStream::DegradationPreference::kMaintainResolution);
1477 video_source_.set_adaptation_enabled(true);
1478
1479 fake_clock.SetTimeMicros(kFrameIntervalMs * 1000);
1480 int64_t timestamp_ms = kFrameIntervalMs;
1481
1482 video_source_.IncomingCapturedFrame(
1483 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1484 sink_.WaitForEncodedFrame(timestamp_ms);
1485
1486 // Try to trigger overuse. No fps estimate available => no effect.
1487 vie_encoder_->TriggerCpuOveruse();
1488
1489 // Insert frames for one second to get a stable estimate.
1490 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1491 timestamp_ms += kFrameIntervalMs;
1492 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1493 video_source_.IncomingCapturedFrame(
1494 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1495 sink_.WaitForEncodedFrame(timestamp_ms);
1496 }
1497
1498 // Trigger CPU overuse, reduce framerate by 2/3.
1499 vie_encoder_->TriggerCpuOveruse();
1500 int num_frames_dropped = 0;
1501 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1502 timestamp_ms += kFrameIntervalMs;
1503 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1504 video_source_.IncomingCapturedFrame(
1505 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1506 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
1507 ++num_frames_dropped;
1508 } else {
1509 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
1510 }
1511 }
1512
1513 // TODO(sprang): Find where there's rounding errors or stuff causing the
1514 // margin here to be a little larger than we'd like (input fps estimate is
1515 // off) and the frame dropping is a little too aggressive.
1516 const int kErrorMargin = 5;
1517 EXPECT_NEAR(num_frames_dropped,
1518 kDefaultFramerateFps - (kDefaultFramerateFps * 2 / 3),
1519 kErrorMargin);
1520
1521 // Trigger CPU overuse, reduce framerate by 2/3 again.
1522 vie_encoder_->TriggerCpuOveruse();
1523 num_frames_dropped = 0;
1524 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1525 timestamp_ms += kFrameIntervalMs;
1526 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1527 video_source_.IncomingCapturedFrame(
1528 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1529 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
1530 ++num_frames_dropped;
1531 } else {
1532 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
1533 }
1534 }
1535 EXPECT_NEAR(num_frames_dropped,
1536 kDefaultFramerateFps - (kDefaultFramerateFps * 4 / 9),
1537 kErrorMargin);
1538
1539 // Go back up one step.
1540 vie_encoder_->TriggerCpuNormalUsage();
1541 num_frames_dropped = 0;
1542 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1543 timestamp_ms += kFrameIntervalMs;
1544 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1545 video_source_.IncomingCapturedFrame(
1546 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1547 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
1548 ++num_frames_dropped;
1549 } else {
1550 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
1551 }
1552 }
1553 EXPECT_NEAR(num_frames_dropped,
1554 kDefaultFramerateFps - (kDefaultFramerateFps * 2 / 3),
1555 kErrorMargin);
1556
1557 // Go back up to original mode.
1558 vie_encoder_->TriggerCpuNormalUsage();
1559 num_frames_dropped = 0;
1560 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1561 timestamp_ms += kFrameIntervalMs;
1562 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1563 video_source_.IncomingCapturedFrame(
1564 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1565 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
1566 ++num_frames_dropped;
1567 } else {
1568 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
1569 }
1570 }
1571 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
1572
1573 vie_encoder_->Stop();
1574}
1575
1576TEST_F(ViEEncoderTest, DoesntAdaptDownPastMinFramerate) {
1577 const int kFramerateFps = 5;
1578 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
1579 const int kMinFpsFrameInterval = rtc::kNumMillisecsPerSec / kMinFramerateFps;
1580 const int kFrameWidth = 1280;
1581 const int kFrameHeight = 720;
1582
1583 rtc::ScopedFakeClock fake_clock;
1584 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1585 vie_encoder_->SetSource(
1586 &video_source_,
1587 VideoSendStream::DegradationPreference::kMaintainResolution);
1588 video_source_.set_adaptation_enabled(true);
1589
1590 fake_clock.SetTimeMicros(kFrameIntervalMs * 1000);
1591 int64_t timestamp_ms = kFrameIntervalMs;
1592
1593 // Trigger overuse as much as we can.
1594 for (int i = 0; i < ViEEncoder::kMaxCpuResolutionDowngrades; ++i) {
1595 // Insert frames to get a new fps estimate...
1596 for (int j = 0; j < kFramerateFps; ++j) {
1597 video_source_.IncomingCapturedFrame(
1598 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1599 timestamp_ms += kFrameIntervalMs;
1600 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1601 }
1602 // ...and then try to adapt again.
1603 vie_encoder_->TriggerCpuOveruse();
1604 }
1605
1606 // Drain any frame in the pipeline.
1607 sink_.WaitForFrame(kDefaultTimeoutMs);
1608
1609 // Insert frames at min fps, all should go through.
1610 for (int i = 0; i < 10; ++i) {
1611 timestamp_ms += kMinFpsFrameInterval;
1612 fake_clock.AdvanceTimeMicros(kMinFpsFrameInterval * 1000);
1613 video_source_.IncomingCapturedFrame(
1614 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1615 sink_.WaitForEncodedFrame(timestamp_ms);
1616 }
1617 vie_encoder_->Stop();
1618}
perkj26091b12016-09-01 01:17:40 -07001619} // namespace webrtc