blob: d7bddeb695f6e9730a4adbe056eb57e5feb4b6ab [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
perkj803d97f2016-11-01 11:45:46 -070011#include <limits>
Per512ecb32016-09-23 15:52:06 +020012#include <utility>
13
nisseaf916892017-01-10 07:44:26 -080014#include "webrtc/api/video/i420_buffer.h"
sprang72acf252017-03-21 11:54:11 -070015#include "webrtc/base/fakeclock.h"
perkj26091b12016-09-01 01:17:40 -070016#include "webrtc/base/logging.h"
sprangb1ca0732017-02-01 08:38:12 -080017#include "webrtc/media/base/videoadapter.h"
sprang57c2fff2017-01-16 06:24:02 -080018#include "webrtc/modules/video_coding/utility/default_video_bitrate_allocator.h"
perkj803d97f2016-11-01 11:45:46 -070019#include "webrtc/system_wrappers/include/metrics_default.h"
sprang57c2fff2017-01-16 06:24:02 -080020#include "webrtc/system_wrappers/include/sleep.h"
perkj26091b12016-09-01 01:17:40 -070021#include "webrtc/test/encoder_settings.h"
22#include "webrtc/test/fake_encoder.h"
perkja49cbd32016-09-16 07:53:41 -070023#include "webrtc/test/frame_generator.h"
sprang57c2fff2017-01-16 06:24:02 -080024#include "webrtc/test/gmock.h"
kwibergac9f8762016-09-30 22:29:43 -070025#include "webrtc/test/gtest.h"
perkj26091b12016-09-01 01:17:40 -070026#include "webrtc/video/send_statistics_proxy.h"
27#include "webrtc/video/vie_encoder.h"
28
kthelgason33ce8892016-12-09 03:53:59 -080029namespace {
30#if defined(WEBRTC_ANDROID)
31// TODO(kthelgason): Lower this limit when better testing
32// on MediaCodec and fallback implementations are in place.
33const int kMinPixelsPerFrame = 320 * 180;
34#else
35const int kMinPixelsPerFrame = 120 * 90;
36#endif
sprang72acf252017-03-21 11:54:11 -070037const int kMinFramerateFps = 2;
38const int64_t kFrameTimeoutMs = 100;
39} // namespace
kthelgason33ce8892016-12-09 03:53:59 -080040
perkj26091b12016-09-01 01:17:40 -070041namespace webrtc {
42
kthelgason876222f2016-11-29 01:44:11 -080043using DegredationPreference = VideoSendStream::DegradationPreference;
sprangb1ca0732017-02-01 08:38:12 -080044using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080045using ::testing::_;
46using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080047
perkj803d97f2016-11-01 11:45:46 -070048namespace {
asapersson5f7226f2016-11-25 04:37:00 -080049const size_t kMaxPayloadLength = 1440;
kthelgason2bc68642017-02-07 07:02:22 -080050const int kTargetBitrateBps = 1000000;
51const int kLowTargetBitrateBps = kTargetBitrateBps / 10;
52const int kMaxInitialFramedrop = 4;
asapersson5f7226f2016-11-25 04:37:00 -080053
perkj803d97f2016-11-01 11:45:46 -070054class TestBuffer : public webrtc::I420Buffer {
55 public:
56 TestBuffer(rtc::Event* event, int width, int height)
57 : I420Buffer(width, height), event_(event) {}
58
59 private:
60 friend class rtc::RefCountedObject<TestBuffer>;
61 ~TestBuffer() override {
62 if (event_)
63 event_->Set();
64 }
65 rtc::Event* const event_;
66};
67
68class ViEEncoderUnderTest : public ViEEncoder {
69 public:
kthelgason876222f2016-11-29 01:44:11 -080070 ViEEncoderUnderTest(SendStatisticsProxy* stats_proxy,
71 const VideoSendStream::Config::EncoderSettings& settings)
perkj803d97f2016-11-01 11:45:46 -070072 : ViEEncoder(1 /* number_of_cores */,
73 stats_proxy,
74 settings,
75 nullptr /* pre_encode_callback */,
76 nullptr /* encoder_timing */) {}
77
sprangb1ca0732017-02-01 08:38:12 -080078 void PostTaskAndWait(bool down, AdaptReason reason) {
perkj803d97f2016-11-01 11:45:46 -070079 rtc::Event event(false, false);
kthelgason876222f2016-11-29 01:44:11 -080080 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -080081 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -070082 event.Set();
83 });
perkj070ba852017-02-16 15:46:27 -080084 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -070085 }
86
kthelgason2fc52542017-03-03 00:24:41 -080087 // This is used as a synchronisation mechanism, to make sure that the
88 // encoder queue is not blocked before we start sending it frames.
89 void WaitUntilTaskQueueIsIdle() {
90 rtc::Event event(false, false);
91 encoder_queue()->PostTask([&event] {
92 event.Set();
93 });
94 ASSERT_TRUE(event.Wait(5000));
95 }
96
sprangb1ca0732017-02-01 08:38:12 -080097 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -080098
sprangb1ca0732017-02-01 08:38:12 -080099 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800100
sprangb1ca0732017-02-01 08:38:12 -0800101 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800102
sprangb1ca0732017-02-01 08:38:12 -0800103 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
perkj803d97f2016-11-01 11:45:46 -0700104};
105
asapersson5f7226f2016-11-25 04:37:00 -0800106class VideoStreamFactory
107 : public VideoEncoderConfig::VideoStreamFactoryInterface {
108 public:
109 explicit VideoStreamFactory(size_t num_temporal_layers)
110 : num_temporal_layers_(num_temporal_layers) {
111 EXPECT_GT(num_temporal_layers, 0u);
112 }
113
114 private:
115 std::vector<VideoStream> CreateEncoderStreams(
116 int width,
117 int height,
118 const VideoEncoderConfig& encoder_config) override {
119 std::vector<VideoStream> streams =
120 test::CreateVideoStreams(width, height, encoder_config);
121 for (VideoStream& stream : streams) {
122 stream.temporal_layer_thresholds_bps.resize(num_temporal_layers_ - 1);
123 }
124 return streams;
125 }
126 const size_t num_temporal_layers_;
127};
128
sprangb1ca0732017-02-01 08:38:12 -0800129class AdaptingFrameForwarder : public test::FrameForwarder {
130 public:
131 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
132 virtual ~AdaptingFrameForwarder() {}
133
134 void set_adaptation_enabled(bool enabled) {
135 rtc::CritScope cs(&crit_);
136 adaptation_enabled_ = enabled;
137 }
138
139 bool adaption_enabled() {
140 rtc::CritScope cs(&crit_);
141 return adaptation_enabled_;
142 }
143
144 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
145 int cropped_width = 0;
146 int cropped_height = 0;
147 int out_width = 0;
148 int out_height = 0;
sprang72acf252017-03-21 11:54:11 -0700149 if (adaption_enabled()) {
150 if (adapter_.AdaptFrameResolution(
151 video_frame.width(), video_frame.height(),
152 video_frame.timestamp_us() * 1000, &cropped_width,
153 &cropped_height, &out_width, &out_height)) {
154 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
155 nullptr, out_width, out_height),
156 99, 99, kVideoRotation_0);
157 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
158 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
159 }
sprangb1ca0732017-02-01 08:38:12 -0800160 } else {
161 test::FrameForwarder::IncomingCapturedFrame(video_frame);
162 }
163 }
164
165 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
166 const rtc::VideoSinkWants& wants) override {
167 rtc::CritScope cs(&crit_);
sprang72acf252017-03-21 11:54:11 -0700168 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
169 wants.max_pixel_count,
170 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800171 test::FrameForwarder::AddOrUpdateSink(sink, wants);
172 }
173
174 cricket::VideoAdapter adapter_;
175 bool adaptation_enabled_ GUARDED_BY(crit_);
176};
sprang72acf252017-03-21 11:54:11 -0700177
178class MockableSendStatisticsProxy : public SendStatisticsProxy {
179 public:
180 MockableSendStatisticsProxy(Clock* clock,
181 const VideoSendStream::Config& config,
182 VideoEncoderConfig::ContentType content_type)
183 : SendStatisticsProxy(clock, config, content_type) {}
184
185 VideoSendStream::Stats GetStats() override {
186 rtc::CritScope cs(&lock_);
187 if (mock_stats_)
188 return *mock_stats_;
189 return SendStatisticsProxy::GetStats();
190 }
191
192 void SetMockStats(const VideoSendStream::Stats& stats) {
193 rtc::CritScope cs(&lock_);
194 mock_stats_.emplace(stats);
195 }
196
197 void ResetMockStats() {
198 rtc::CritScope cs(&lock_);
199 mock_stats_.reset();
200 }
201
202 private:
203 rtc::CriticalSection lock_;
204 rtc::Optional<VideoSendStream::Stats> mock_stats_ GUARDED_BY(lock_);
205};
206
perkj803d97f2016-11-01 11:45:46 -0700207} // namespace
208
perkj26091b12016-09-01 01:17:40 -0700209class ViEEncoderTest : public ::testing::Test {
210 public:
211 static const int kDefaultTimeoutMs = 30 * 1000;
212
213 ViEEncoderTest()
214 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700215 codec_width_(320),
216 codec_height_(240),
perkj26091b12016-09-01 01:17:40 -0700217 fake_encoder_(),
sprang72acf252017-03-21 11:54:11 -0700218 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700219 Clock::GetRealTimeClock(),
220 video_send_config_,
221 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700222 sink_(&fake_encoder_) {}
223
224 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700225 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700226 video_send_config_ = VideoSendStream::Config(nullptr);
227 video_send_config_.encoder_settings.encoder = &fake_encoder_;
228 video_send_config_.encoder_settings.payload_name = "FAKE";
229 video_send_config_.encoder_settings.payload_type = 125;
230
Per512ecb32016-09-23 15:52:06 +0200231 VideoEncoderConfig video_encoder_config;
perkjfa10b552016-10-02 23:45:26 -0700232 test::FillEncoderConfiguration(1, &video_encoder_config);
Erik Språng08127a92016-11-16 16:41:30 +0100233 video_encoder_config_ = video_encoder_config.Copy();
asapersson5f7226f2016-11-25 04:37:00 -0800234 ConfigureEncoder(std::move(video_encoder_config), true /* nack_enabled */);
235 }
236
237 void ConfigureEncoder(VideoEncoderConfig video_encoder_config,
238 bool nack_enabled) {
239 if (vie_encoder_)
240 vie_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700241 vie_encoder_.reset(new ViEEncoderUnderTest(
242 stats_proxy_.get(), video_send_config_.encoder_settings));
243 vie_encoder_->SetSink(&sink_, false /* rotation_applied */);
sprang72acf252017-03-21 11:54:11 -0700244 vie_encoder_->SetSource(
245 &video_source_,
246 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason2bc68642017-02-07 07:02:22 -0800247 vie_encoder_->SetStartBitrate(kTargetBitrateBps);
asapersson5f7226f2016-11-25 04:37:00 -0800248 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
249 kMaxPayloadLength, nack_enabled);
kthelgason2fc52542017-03-03 00:24:41 -0800250 vie_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800251 }
252
253 void ResetEncoder(const std::string& payload_name,
254 size_t num_streams,
255 size_t num_temporal_layers,
256 bool nack_enabled) {
257 video_send_config_.encoder_settings.payload_name = payload_name;
258
259 VideoEncoderConfig video_encoder_config;
260 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800261 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800262 video_encoder_config.video_stream_factory =
263 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers);
264 ConfigureEncoder(std::move(video_encoder_config), nack_enabled);
perkj26091b12016-09-01 01:17:40 -0700265 }
266
sprang57c2fff2017-01-16 06:24:02 -0800267 VideoFrame CreateFrame(int64_t ntp_time_ms,
268 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200269 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
270 destruction_event, codec_width_, codec_height_),
271 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800272 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700273 return frame;
274 }
275
sprang57c2fff2017-01-16 06:24:02 -0800276 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700277 VideoFrame frame(
278 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
279 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800280 frame.set_ntp_time_ms(ntp_time_ms);
sprang72acf252017-03-21 11:54:11 -0700281 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700282 return frame;
283 }
284
perkj26091b12016-09-01 01:17:40 -0700285 class TestEncoder : public test::FakeEncoder {
286 public:
287 TestEncoder()
288 : FakeEncoder(Clock::GetRealTimeClock()),
289 continue_encode_event_(false, false) {}
290
perkjfa10b552016-10-02 23:45:26 -0700291 VideoCodec codec_config() {
brandtre78d2662017-01-16 05:57:16 -0800292 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700293 return config_;
294 }
295
296 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800297 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700298 block_next_encode_ = true;
299 }
300
kthelgason876222f2016-11-29 01:44:11 -0800301 VideoEncoder::ScalingSettings GetScalingSettings() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800302 rtc::CritScope lock(&local_crit_sect_);
kthelgasonad9010c2017-02-14 00:46:51 -0800303 if (quality_scaling_)
304 return VideoEncoder::ScalingSettings(true, 1, 2);
305 return VideoEncoder::ScalingSettings(false);
kthelgason876222f2016-11-29 01:44:11 -0800306 }
307
perkjfa10b552016-10-02 23:45:26 -0700308 void ContinueEncode() { continue_encode_event_.Set(); }
309
310 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
311 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800312 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700313 EXPECT_EQ(timestamp_, timestamp);
314 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
315 }
316
kthelgason2fc52542017-03-03 00:24:41 -0800317 void SetQualityScaling(bool b) {
318 rtc::CritScope lock(&local_crit_sect_);
319 quality_scaling_ = b;
320 }
kthelgasonad9010c2017-02-14 00:46:51 -0800321
perkjfa10b552016-10-02 23:45:26 -0700322 private:
perkj26091b12016-09-01 01:17:40 -0700323 int32_t Encode(const VideoFrame& input_image,
324 const CodecSpecificInfo* codec_specific_info,
325 const std::vector<FrameType>* frame_types) override {
326 bool block_encode;
327 {
brandtre78d2662017-01-16 05:57:16 -0800328 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700329 EXPECT_GT(input_image.timestamp(), timestamp_);
330 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
331 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
332
333 timestamp_ = input_image.timestamp();
334 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700335 last_input_width_ = input_image.width();
336 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700337 block_encode = block_next_encode_;
338 block_next_encode_ = false;
339 }
340 int32_t result =
341 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
342 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700343 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700344 return result;
345 }
346
brandtre78d2662017-01-16 05:57:16 -0800347 rtc::CriticalSection local_crit_sect_;
perkj26091b12016-09-01 01:17:40 -0700348 bool block_next_encode_ = false;
349 rtc::Event continue_encode_event_;
350 uint32_t timestamp_ = 0;
351 int64_t ntp_time_ms_ = 0;
perkj803d97f2016-11-01 11:45:46 -0700352 int last_input_width_ = 0;
353 int last_input_height_ = 0;
kthelgasonad9010c2017-02-14 00:46:51 -0800354 bool quality_scaling_ = true;
perkj26091b12016-09-01 01:17:40 -0700355 };
356
Per512ecb32016-09-23 15:52:06 +0200357 class TestSink : public ViEEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700358 public:
359 explicit TestSink(TestEncoder* test_encoder)
360 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
361
perkj26091b12016-09-01 01:17:40 -0700362 void WaitForEncodedFrame(int64_t expected_ntp_time) {
363 uint32_t timestamp = 0;
perkja49cbd32016-09-16 07:53:41 -0700364 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700365 {
366 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800367 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700368 }
369 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
370 }
371
sprangb1ca0732017-02-01 08:38:12 -0800372 void WaitForEncodedFrame(uint32_t expected_width,
373 uint32_t expected_height) {
sprang72acf252017-03-21 11:54:11 -0700374 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
375 CheckLastFrameSizeMathces(expected_width, expected_height);
376 }
377
378 void CheckLastFrameSizeMathces(uint32_t expected_width,
379 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800380 uint32_t width = 0;
381 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800382 {
383 rtc::CritScope lock(&crit_);
384 width = last_width_;
385 height = last_height_;
386 }
387 EXPECT_EQ(expected_height, height);
388 EXPECT_EQ(expected_width, width);
389 }
390
kthelgason2fc52542017-03-03 00:24:41 -0800391 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800392
sprang72acf252017-03-21 11:54:11 -0700393 bool WaitForFrame(int64_t timeout_ms) {
394 return encoded_frame_event_.Wait(timeout_ms);
395 }
396
perkj26091b12016-09-01 01:17:40 -0700397 void SetExpectNoFrames() {
398 rtc::CritScope lock(&crit_);
399 expect_frames_ = false;
400 }
401
Per512ecb32016-09-23 15:52:06 +0200402 int number_of_reconfigurations() {
403 rtc::CritScope lock(&crit_);
404 return number_of_reconfigurations_;
405 }
406
407 int last_min_transmit_bitrate() {
408 rtc::CritScope lock(&crit_);
409 return min_transmit_bitrate_bps_;
410 }
411
perkj26091b12016-09-01 01:17:40 -0700412 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700413 Result OnEncodedImage(
414 const EncodedImage& encoded_image,
415 const CodecSpecificInfo* codec_specific_info,
416 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200417 rtc::CritScope lock(&crit_);
418 EXPECT_TRUE(expect_frames_);
sprangb1ca0732017-02-01 08:38:12 -0800419 last_timestamp_ = encoded_image._timeStamp;
420 last_width_ = encoded_image._encodedWidth;
421 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200422 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800423 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200424 }
425
426 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
427 int min_transmit_bitrate_bps) override {
428 rtc::CriticalSection crit_;
429 ++number_of_reconfigurations_;
430 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
431 }
432
perkj26091b12016-09-01 01:17:40 -0700433 rtc::CriticalSection crit_;
434 TestEncoder* test_encoder_;
435 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800436 uint32_t last_timestamp_ = 0;
437 uint32_t last_height_ = 0;
438 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700439 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200440 int number_of_reconfigurations_ = 0;
441 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700442 };
443
444 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100445 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200446 int codec_width_;
447 int codec_height_;
perkj26091b12016-09-01 01:17:40 -0700448 TestEncoder fake_encoder_;
sprang72acf252017-03-21 11:54:11 -0700449 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700450 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800451 AdaptingFrameForwarder video_source_;
perkj803d97f2016-11-01 11:45:46 -0700452 std::unique_ptr<ViEEncoderUnderTest> vie_encoder_;
perkj26091b12016-09-01 01:17:40 -0700453};
454
455TEST_F(ViEEncoderTest, EncodeOneFrame) {
perkj26091b12016-09-01 01:17:40 -0700456 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
457 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700458 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
perkj26091b12016-09-01 01:17:40 -0700459 sink_.WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700460 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700461 vie_encoder_->Stop();
462}
463
464TEST_F(ViEEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
465 // Dropped since no target bitrate has been set.
466 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700467 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
468 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700469
perkj26091b12016-09-01 01:17:40 -0700470 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
471
perkja49cbd32016-09-16 07:53:41 -0700472 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkj26091b12016-09-01 01:17:40 -0700473 sink_.WaitForEncodedFrame(2);
474 vie_encoder_->Stop();
475}
476
477TEST_F(ViEEncoderTest, DropsFramesWhenRateSetToZero) {
perkj26091b12016-09-01 01:17:40 -0700478 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700479 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700480 sink_.WaitForEncodedFrame(1);
481
482 vie_encoder_->OnBitrateUpdated(0, 0, 0);
483 // Dropped since bitrate is zero.
perkja49cbd32016-09-16 07:53:41 -0700484 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkj26091b12016-09-01 01:17:40 -0700485
486 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700487 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700488 sink_.WaitForEncodedFrame(3);
489 vie_encoder_->Stop();
490}
491
492TEST_F(ViEEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
perkj26091b12016-09-01 01:17:40 -0700493 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700494 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700495 sink_.WaitForEncodedFrame(1);
496
497 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700498 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700499
perkja49cbd32016-09-16 07:53:41 -0700500 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkj26091b12016-09-01 01:17:40 -0700501 sink_.WaitForEncodedFrame(2);
502 vie_encoder_->Stop();
503}
504
505TEST_F(ViEEncoderTest, DropsFrameAfterStop) {
perkj26091b12016-09-01 01:17:40 -0700506 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
507
perkja49cbd32016-09-16 07:53:41 -0700508 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700509 sink_.WaitForEncodedFrame(1);
510
511 vie_encoder_->Stop();
512 sink_.SetExpectNoFrames();
513 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700514 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
515 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700516}
517
518TEST_F(ViEEncoderTest, DropsPendingFramesOnSlowEncode) {
perkj26091b12016-09-01 01:17:40 -0700519 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
520
521 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700522 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700523 sink_.WaitForEncodedFrame(1);
524 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
525 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700526 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
527 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700528 fake_encoder_.ContinueEncode();
529 sink_.WaitForEncodedFrame(3);
530
531 vie_encoder_->Stop();
532}
533
Per512ecb32016-09-23 15:52:06 +0200534TEST_F(ViEEncoderTest, ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
Per512ecb32016-09-23 15:52:06 +0200535 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100536 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200537
538 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200539 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
Per512ecb32016-09-23 15:52:06 +0200540 sink_.WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100541 // The encoder will have been configured once when the first frame is
542 // received.
543 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200544
545 VideoEncoderConfig video_encoder_config;
perkjfa10b552016-10-02 23:45:26 -0700546 test::FillEncoderConfiguration(1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200547 video_encoder_config.min_transmit_bitrate_bps = 9999;
asapersson5f7226f2016-11-25 04:37:00 -0800548 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
549 kMaxPayloadLength, true /* nack_enabled */);
Per512ecb32016-09-23 15:52:06 +0200550
551 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200552 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Per512ecb32016-09-23 15:52:06 +0200553 sink_.WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100554 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700555 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700556
557 vie_encoder_->Stop();
558}
559
perkjfa10b552016-10-02 23:45:26 -0700560TEST_F(ViEEncoderTest, FrameResolutionChangeReconfigureEncoder) {
perkjfa10b552016-10-02 23:45:26 -0700561 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
562
563 // Capture a frame and wait for it to synchronize with the encoder thread.
564 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
565 sink_.WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100566 // The encoder will have been configured once.
567 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700568 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
569 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
570
571 codec_width_ *= 2;
572 codec_height_ *= 2;
573 // Capture a frame with a higher resolution and wait for it to synchronize
574 // with the encoder thread.
575 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
576 sink_.WaitForEncodedFrame(2);
577 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
578 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100579 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700580
581 vie_encoder_->Stop();
582}
583
asapersson5f7226f2016-11-25 04:37:00 -0800584TEST_F(ViEEncoderTest, Vp8ResilienceIsOffFor1S1TLWithNackEnabled) {
585 const bool kNackEnabled = true;
586 const size_t kNumStreams = 1;
587 const size_t kNumTl = 1;
asaperssona90799d2016-12-09 02:35:20 -0800588 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800589 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
590
591 // Capture a frame and wait for it to synchronize with the encoder thread.
592 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
593 sink_.WaitForEncodedFrame(1);
594 // The encoder have been configured once when the first frame is received.
595 EXPECT_EQ(1, sink_.number_of_reconfigurations());
596 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
597 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
598 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
599 // Resilience is off for no temporal layers with nack on.
600 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
601 vie_encoder_->Stop();
602}
603
604TEST_F(ViEEncoderTest, Vp8ResilienceIsOffFor2S1TlWithNackEnabled) {
605 const bool kNackEnabled = true;
606 const size_t kNumStreams = 2;
607 const size_t kNumTl = 1;
asaperssona90799d2016-12-09 02:35:20 -0800608 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800609 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
610
611 // Capture a frame and wait for it to synchronize with the encoder thread.
612 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
613 sink_.WaitForEncodedFrame(1);
614 // The encoder have been configured once when the first frame is received.
615 EXPECT_EQ(1, sink_.number_of_reconfigurations());
616 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
617 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
618 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
619 // Resilience is off for no temporal layers and >1 streams with nack on.
620 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
621 vie_encoder_->Stop();
622}
623
624TEST_F(ViEEncoderTest, Vp8ResilienceIsOnFor1S1TLWithNackDisabled) {
625 const bool kNackEnabled = false;
626 const size_t kNumStreams = 1;
627 const size_t kNumTl = 1;
asaperssona90799d2016-12-09 02:35:20 -0800628 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800629 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
630
631 // Capture a frame and wait for it to synchronize with the encoder thread.
632 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
633 sink_.WaitForEncodedFrame(1);
634 // The encoder have been configured once when the first frame is received.
635 EXPECT_EQ(1, sink_.number_of_reconfigurations());
636 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
637 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
638 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
639 // Resilience is on for no temporal layers with nack off.
640 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
641 vie_encoder_->Stop();
642}
643
644TEST_F(ViEEncoderTest, Vp8ResilienceIsOnFor1S2TlWithNackEnabled) {
645 const bool kNackEnabled = true;
646 const size_t kNumStreams = 1;
647 const size_t kNumTl = 2;
asaperssona90799d2016-12-09 02:35:20 -0800648 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800649 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
650
651 // Capture a frame and wait for it to synchronize with the encoder thread.
652 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
653 sink_.WaitForEncodedFrame(1);
654 // The encoder have been configured once when the first frame is received.
655 EXPECT_EQ(1, sink_.number_of_reconfigurations());
656 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
657 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
658 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
659 // Resilience is on for temporal layers.
660 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
661 vie_encoder_->Stop();
662}
663
perkj803d97f2016-11-01 11:45:46 -0700664TEST_F(ViEEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
665 EXPECT_TRUE(video_source_.has_sinks());
666 test::FrameForwarder new_video_source;
sprang72acf252017-03-21 11:54:11 -0700667 vie_encoder_->SetSource(
668 &new_video_source,
669 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -0700670 EXPECT_FALSE(video_source_.has_sinks());
671 EXPECT_TRUE(new_video_source.has_sinks());
672
673 vie_encoder_->Stop();
674}
675
676TEST_F(ViEEncoderTest, SinkWantsRotationApplied) {
677 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
678 vie_encoder_->SetSink(&sink_, true /*rotation_applied*/);
679 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
680 vie_encoder_->Stop();
681}
682
683TEST_F(ViEEncoderTest, SinkWantsFromOveruseDetector) {
perkj803d97f2016-11-01 11:45:46 -0700684 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
685
sprang84a37592017-02-10 07:04:27 -0800686 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
sprang72acf252017-03-21 11:54:11 -0700687 EXPECT_EQ(std::numeric_limits<int>::max(),
688 video_source_.sink_wants().max_pixel_count);
perkj803d97f2016-11-01 11:45:46 -0700689
690 int frame_width = 1280;
691 int frame_height = 720;
692
693 // Trigger CPU overuse kMaxCpuDowngrades times. Every time, ViEEncoder should
694 // request lower resolution.
sprang72acf252017-03-21 11:54:11 -0700695 for (int i = 1; i <= ViEEncoder::kMaxCpuResolutionDowngrades; ++i) {
perkj803d97f2016-11-01 11:45:46 -0700696 video_source_.IncomingCapturedFrame(
697 CreateFrame(i, frame_width, frame_height));
698 sink_.WaitForEncodedFrame(i);
699
700 vie_encoder_->TriggerCpuOveruse();
701
sprang84a37592017-02-10 07:04:27 -0800702 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
sprang72acf252017-03-21 11:54:11 -0700703 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
perkj803d97f2016-11-01 11:45:46 -0700704 frame_width * frame_height);
perkj803d97f2016-11-01 11:45:46 -0700705
706 frame_width /= 2;
707 frame_height /= 2;
708 }
709
kthelgason876222f2016-11-29 01:44:11 -0800710 // Trigger CPU overuse one more time. This should not trigger a request for
perkj803d97f2016-11-01 11:45:46 -0700711 // lower resolution.
712 rtc::VideoSinkWants current_wants = video_source_.sink_wants();
713 video_source_.IncomingCapturedFrame(CreateFrame(
sprang72acf252017-03-21 11:54:11 -0700714 ViEEncoder::kMaxCpuResolutionDowngrades + 1, frame_width, frame_height));
715 sink_.WaitForEncodedFrame(ViEEncoder::kMaxCpuResolutionDowngrades + 1);
perkj803d97f2016-11-01 11:45:46 -0700716 vie_encoder_->TriggerCpuOveruse();
sprang84a37592017-02-10 07:04:27 -0800717 EXPECT_EQ(video_source_.sink_wants().target_pixel_count,
718 current_wants.target_pixel_count);
perkj803d97f2016-11-01 11:45:46 -0700719 EXPECT_EQ(video_source_.sink_wants().max_pixel_count,
720 current_wants.max_pixel_count);
perkj803d97f2016-11-01 11:45:46 -0700721
722 // Trigger CPU normal use.
723 vie_encoder_->TriggerCpuNormalUsage();
sprang84a37592017-02-10 07:04:27 -0800724 EXPECT_EQ(frame_width * frame_height * 5 / 3,
725 video_source_.sink_wants().target_pixel_count.value_or(0));
726 EXPECT_EQ(frame_width * frame_height * 4,
sprang72acf252017-03-21 11:54:11 -0700727 video_source_.sink_wants().max_pixel_count);
perkj803d97f2016-11-01 11:45:46 -0700728
729 vie_encoder_->Stop();
730}
731
sprang72acf252017-03-21 11:54:11 -0700732TEST_F(ViEEncoderTest, SinkWantsStoredByDegradationPreference) {
perkj803d97f2016-11-01 11:45:46 -0700733 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
734
sprang84a37592017-02-10 07:04:27 -0800735 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
sprang72acf252017-03-21 11:54:11 -0700736 EXPECT_EQ(std::numeric_limits<int>::max(),
737 video_source_.sink_wants().max_pixel_count);
738 EXPECT_EQ(std::numeric_limits<int>::max(),
739 video_source_.sink_wants().max_framerate_fps);
perkj803d97f2016-11-01 11:45:46 -0700740
sprang72acf252017-03-21 11:54:11 -0700741 const int kFrameWidth = 1280;
742 const int kFrameHeight = 720;
743 const int kFrameIntervalMs = 1000 / 30;
744
745 int frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -0700746
kthelgason5e13d412016-12-01 03:59:51 -0800747 video_source_.IncomingCapturedFrame(
sprang72acf252017-03-21 11:54:11 -0700748 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
749 sink_.WaitForEncodedFrame(frame_timestamp);
750 frame_timestamp += kFrameIntervalMs;
751
perkj803d97f2016-11-01 11:45:46 -0700752 // Trigger CPU overuse.
753 vie_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700754 video_source_.IncomingCapturedFrame(
sprang72acf252017-03-21 11:54:11 -0700755 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
756 sink_.WaitForEncodedFrame(frame_timestamp);
757 frame_timestamp += kFrameIntervalMs;
perkj803d97f2016-11-01 11:45:46 -0700758
sprang72acf252017-03-21 11:54:11 -0700759 // Default degradation preference in maintain-framerate, so will lower max
760 // wanted resolution.
761 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
762 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
763 kFrameWidth * kFrameHeight);
764 EXPECT_EQ(std::numeric_limits<int>::max(),
765 video_source_.sink_wants().max_framerate_fps);
766
767 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -0700768 test::FrameForwarder new_video_source;
769 vie_encoder_->SetSource(
770 &new_video_source,
771 VideoSendStream::DegradationPreference::kMaintainResolution);
772
sprang72acf252017-03-21 11:54:11 -0700773 // Initially no degradation registered.
sprang84a37592017-02-10 07:04:27 -0800774 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprang72acf252017-03-21 11:54:11 -0700775 EXPECT_EQ(std::numeric_limits<int>::max(),
776 new_video_source.sink_wants().max_pixel_count);
777 EXPECT_EQ(std::numeric_limits<int>::max(),
778 new_video_source.sink_wants().max_framerate_fps);
perkj803d97f2016-11-01 11:45:46 -0700779
sprang72acf252017-03-21 11:54:11 -0700780 // Force an input frame rate to be available, or the adaptation call won't
781 // know what framerate to adapt form.
782 VideoSendStream::Stats stats = stats_proxy_->GetStats();
783 stats.input_frame_rate = 30;
784 stats_proxy_->SetMockStats(stats);
785
786 vie_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700787 new_video_source.IncomingCapturedFrame(
sprang72acf252017-03-21 11:54:11 -0700788 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
789 sink_.WaitForEncodedFrame(frame_timestamp);
790 frame_timestamp += kFrameIntervalMs;
791
792 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -0800793 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprang72acf252017-03-21 11:54:11 -0700794 EXPECT_EQ(std::numeric_limits<int>::max(),
795 new_video_source.sink_wants().max_pixel_count);
796 EXPECT_TRUE(new_video_source.sink_wants().max_framerate_fps);
797
798 // Turn of degradation completely.
799 vie_encoder_->SetSource(
800 &new_video_source,
801 VideoSendStream::DegradationPreference::kDegradationDisabled);
802
803 // Initially no degradation registered.
804 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
805 EXPECT_EQ(std::numeric_limits<int>::max(),
806 new_video_source.sink_wants().max_pixel_count);
807 EXPECT_EQ(std::numeric_limits<int>::max(),
808 new_video_source.sink_wants().max_framerate_fps);
809
810 vie_encoder_->TriggerCpuOveruse();
811 new_video_source.IncomingCapturedFrame(
812 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
813 sink_.WaitForEncodedFrame(frame_timestamp);
814 frame_timestamp += kFrameIntervalMs;
815
816 // Still no degradation.
817 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
818 EXPECT_EQ(std::numeric_limits<int>::max(),
819 new_video_source.sink_wants().max_pixel_count);
820 EXPECT_EQ(std::numeric_limits<int>::max(),
821 new_video_source.sink_wants().max_framerate_fps);
perkj803d97f2016-11-01 11:45:46 -0700822
823 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
sprang72acf252017-03-21 11:54:11 -0700824 vie_encoder_->SetSource(
825 &new_video_source,
826 VideoSendStream::DegradationPreference::kMaintainFramerate);
827 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
828 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -0800829 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprang72acf252017-03-21 11:54:11 -0700830 EXPECT_EQ(std::numeric_limits<int>::max(),
831 new_video_source.sink_wants().max_framerate_fps);
832
833 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
834 vie_encoder_->SetSource(
835 &new_video_source,
836 VideoSendStream::DegradationPreference::kMaintainResolution);
837 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
838 EXPECT_EQ(std::numeric_limits<int>::max(),
839 new_video_source.sink_wants().max_pixel_count);
840 EXPECT_TRUE(new_video_source.sink_wants().max_framerate_fps);
perkj803d97f2016-11-01 11:45:46 -0700841
842 vie_encoder_->Stop();
843}
844
845TEST_F(ViEEncoderTest, StatsTracksAdaptationStats) {
perkj803d97f2016-11-01 11:45:46 -0700846 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
847
848 int frame_width = 1280;
849 int frame_height = 720;
850
851 video_source_.IncomingCapturedFrame(
852 CreateFrame(1, frame_width, frame_height));
853 sink_.WaitForEncodedFrame(1);
854 VideoSendStream::Stats stats = stats_proxy_->GetStats();
855 EXPECT_FALSE(stats.cpu_limited_resolution);
856 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
857
858 // Trigger CPU overuse.
859 vie_encoder_->TriggerCpuOveruse();
860 video_source_.IncomingCapturedFrame(
861 CreateFrame(2, frame_width, frame_height));
862 sink_.WaitForEncodedFrame(2);
863
864 stats = stats_proxy_->GetStats();
865 EXPECT_TRUE(stats.cpu_limited_resolution);
866 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
867
868 // Trigger CPU normal use.
869 vie_encoder_->TriggerCpuNormalUsage();
870 video_source_.IncomingCapturedFrame(
871 CreateFrame(3, frame_width, frame_height));
872 sink_.WaitForEncodedFrame(3);
873
874 stats = stats_proxy_->GetStats();
875 EXPECT_FALSE(stats.cpu_limited_resolution);
876 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
877
878 vie_encoder_->Stop();
879}
880
kthelgason876222f2016-11-29 01:44:11 -0800881TEST_F(ViEEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
kthelgason876222f2016-11-29 01:44:11 -0800882 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
883
884 int frame_width = 1280;
885 int frame_height = 720;
886 video_source_.IncomingCapturedFrame(
887 CreateFrame(1, frame_width, frame_height));
888 sink_.WaitForEncodedFrame(1);
889
890 VideoSendStream::Stats stats = stats_proxy_->GetStats();
891 EXPECT_FALSE(stats.cpu_limited_resolution);
892 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
893
894 vie_encoder_->TriggerCpuOveruse();
895
896 video_source_.IncomingCapturedFrame(
897 CreateFrame(2, frame_width, frame_height));
898 sink_.WaitForEncodedFrame(2);
899 stats = stats_proxy_->GetStats();
900 EXPECT_TRUE(stats.cpu_limited_resolution);
901 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
902
903 // Set new source with adaptation still enabled.
904 test::FrameForwarder new_video_source;
sprang72acf252017-03-21 11:54:11 -0700905 vie_encoder_->SetSource(
906 &new_video_source,
907 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -0800908
909 new_video_source.IncomingCapturedFrame(
910 CreateFrame(3, frame_width, frame_height));
911 sink_.WaitForEncodedFrame(3);
912 stats = stats_proxy_->GetStats();
913 EXPECT_TRUE(stats.cpu_limited_resolution);
914 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
915
916 // Set adaptation disabled.
917 vie_encoder_->SetSource(
918 &new_video_source,
sprang72acf252017-03-21 11:54:11 -0700919 VideoSendStream::DegradationPreference::kDegradationDisabled);
kthelgason876222f2016-11-29 01:44:11 -0800920
921 new_video_source.IncomingCapturedFrame(
922 CreateFrame(4, frame_width, frame_height));
923 sink_.WaitForEncodedFrame(4);
924 stats = stats_proxy_->GetStats();
925 EXPECT_FALSE(stats.cpu_limited_resolution);
926 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
927
928 // Set adaptation back to enabled.
sprang72acf252017-03-21 11:54:11 -0700929 vie_encoder_->SetSource(
930 &new_video_source,
931 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -0800932
933 new_video_source.IncomingCapturedFrame(
934 CreateFrame(5, frame_width, frame_height));
935 sink_.WaitForEncodedFrame(5);
936 stats = stats_proxy_->GetStats();
937 EXPECT_TRUE(stats.cpu_limited_resolution);
938 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
939
940 vie_encoder_->TriggerCpuNormalUsage();
941
942 new_video_source.IncomingCapturedFrame(
943 CreateFrame(6, frame_width, frame_height));
944 sink_.WaitForEncodedFrame(6);
945 stats = stats_proxy_->GetStats();
946 EXPECT_FALSE(stats.cpu_limited_resolution);
947 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
948
949 vie_encoder_->Stop();
950}
951
952TEST_F(ViEEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
kthelgason876222f2016-11-29 01:44:11 -0800953 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
954
955 int frame_width = 1280;
956 int frame_height = 720;
957 video_source_.IncomingCapturedFrame(
958 CreateFrame(1, frame_width, frame_height));
959 sink_.WaitForEncodedFrame(1);
960
961 VideoSendStream::Stats stats = stats_proxy_->GetStats();
962 EXPECT_FALSE(stats.cpu_limited_resolution);
963 EXPECT_FALSE(stats.bw_limited_resolution);
964 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
965
966 // Set new source with adaptation still enabled.
967 test::FrameForwarder new_video_source;
968 vie_encoder_->SetSource(&new_video_source,
969 VideoSendStream::DegradationPreference::kBalanced);
970
971 new_video_source.IncomingCapturedFrame(
972 CreateFrame(2, frame_width, frame_height));
973 sink_.WaitForEncodedFrame(2);
974 stats = stats_proxy_->GetStats();
975 EXPECT_FALSE(stats.cpu_limited_resolution);
976 EXPECT_FALSE(stats.bw_limited_resolution);
977 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
978
979 vie_encoder_->TriggerQualityLow();
980
981 new_video_source.IncomingCapturedFrame(
982 CreateFrame(3, frame_width, frame_height));
983 sink_.WaitForEncodedFrame(3);
984 stats = stats_proxy_->GetStats();
985 EXPECT_FALSE(stats.cpu_limited_resolution);
986 EXPECT_TRUE(stats.bw_limited_resolution);
987
988 vie_encoder_->SetSource(&new_video_source,
989 VideoSendStream::DegradationPreference::kBalanced);
990
991 new_video_source.IncomingCapturedFrame(
992 CreateFrame(4, frame_width, frame_height));
993 sink_.WaitForEncodedFrame(4);
994 stats = stats_proxy_->GetStats();
995 EXPECT_FALSE(stats.cpu_limited_resolution);
996 EXPECT_TRUE(stats.bw_limited_resolution);
997
998 // Set adaptation disabled.
999 vie_encoder_->SetSource(
1000 &new_video_source,
1001 VideoSendStream::DegradationPreference::kMaintainResolution);
1002
1003 new_video_source.IncomingCapturedFrame(
1004 CreateFrame(5, frame_width, frame_height));
1005 sink_.WaitForEncodedFrame(5);
1006 stats = stats_proxy_->GetStats();
1007 EXPECT_FALSE(stats.cpu_limited_resolution);
1008 EXPECT_FALSE(stats.bw_limited_resolution);
1009
1010 vie_encoder_->Stop();
1011}
1012
perkj803d97f2016-11-01 11:45:46 -07001013TEST_F(ViEEncoderTest, StatsTracksAdaptationStatsWhenSwitchingSource) {
perkj803d97f2016-11-01 11:45:46 -07001014 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1015
perkj803d97f2016-11-01 11:45:46 -07001016 int frame_width = 1280;
1017 int frame_height = 720;
sprang84a37592017-02-10 07:04:27 -08001018 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001019
1020 video_source_.IncomingCapturedFrame(
sprang84a37592017-02-10 07:04:27 -08001021 CreateFrame(sequence, frame_width, frame_height));
1022 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001023
1024 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001025 EXPECT_FALSE(stats.cpu_limited_resolution);
1026 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1027
1028 // Trigger CPU overuse again, should now adapt down.
1029 vie_encoder_->TriggerCpuOveruse();
1030 video_source_.IncomingCapturedFrame(
1031 CreateFrame(sequence, frame_width, frame_height));
1032 sink_.WaitForEncodedFrame(sequence++);
1033
1034 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001035 EXPECT_TRUE(stats.cpu_limited_resolution);
1036 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1037
1038 // Set new source with adaptation still enabled.
1039 test::FrameForwarder new_video_source;
sprang72acf252017-03-21 11:54:11 -07001040 vie_encoder_->SetSource(
1041 &new_video_source,
1042 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001043
1044 new_video_source.IncomingCapturedFrame(
sprang84a37592017-02-10 07:04:27 -08001045 CreateFrame(sequence, frame_width, frame_height));
1046 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001047 stats = stats_proxy_->GetStats();
1048 EXPECT_TRUE(stats.cpu_limited_resolution);
1049 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1050
sprang72acf252017-03-21 11:54:11 -07001051 // Set cpu adaptation by frame dropping.
perkj803d97f2016-11-01 11:45:46 -07001052 vie_encoder_->SetSource(
1053 &new_video_source,
1054 VideoSendStream::DegradationPreference::kMaintainResolution);
1055 new_video_source.IncomingCapturedFrame(
sprang84a37592017-02-10 07:04:27 -08001056 CreateFrame(sequence, frame_width, frame_height));
1057 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001058 stats = stats_proxy_->GetStats();
sprang72acf252017-03-21 11:54:11 -07001059 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001060 EXPECT_FALSE(stats.cpu_limited_resolution);
1061 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1062
sprang72acf252017-03-21 11:54:11 -07001063 // Force an input frame rate to be available, or the adaptation call won't
1064 // know what framerate to adapt form.
1065 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1066 mock_stats.input_frame_rate = 30;
1067 stats_proxy_->SetMockStats(mock_stats);
1068 vie_encoder_->TriggerCpuOveruse();
1069 stats_proxy_->ResetMockStats();
1070
1071 new_video_source.IncomingCapturedFrame(
1072 CreateFrame(sequence, frame_width, frame_height));
1073 sink_.WaitForEncodedFrame(sequence++);
1074
1075 // Framerate now adapted.
1076 stats = stats_proxy_->GetStats();
1077 EXPECT_TRUE(stats.cpu_limited_resolution);
1078 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1079
1080 // Disable CPU adaptation.
1081 vie_encoder_->SetSource(
1082 &new_video_source,
1083 VideoSendStream::DegradationPreference::kDegradationDisabled);
1084 new_video_source.IncomingCapturedFrame(
1085 CreateFrame(sequence, frame_width, frame_height));
1086 sink_.WaitForEncodedFrame(sequence++);
1087
1088 stats = stats_proxy_->GetStats();
1089 EXPECT_FALSE(stats.cpu_limited_resolution);
1090 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1091
1092 // Try to trigger overuse. Should not succeed.
1093 stats_proxy_->SetMockStats(mock_stats);
1094 vie_encoder_->TriggerCpuOveruse();
1095 stats_proxy_->ResetMockStats();
1096
1097 stats = stats_proxy_->GetStats();
1098 EXPECT_FALSE(stats.cpu_limited_resolution);
1099 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1100
1101 // Switch back the source with resolution adaptation enabled.
1102 vie_encoder_->SetSource(
1103 &video_source_,
1104 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001105 video_source_.IncomingCapturedFrame(
sprang84a37592017-02-10 07:04:27 -08001106 CreateFrame(sequence, frame_width, frame_height));
1107 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001108 stats = stats_proxy_->GetStats();
1109 EXPECT_TRUE(stats.cpu_limited_resolution);
sprang72acf252017-03-21 11:54:11 -07001110 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001111
1112 // Trigger CPU normal usage.
1113 vie_encoder_->TriggerCpuNormalUsage();
1114 video_source_.IncomingCapturedFrame(
sprang84a37592017-02-10 07:04:27 -08001115 CreateFrame(sequence, frame_width, frame_height));
1116 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001117 stats = stats_proxy_->GetStats();
1118 EXPECT_FALSE(stats.cpu_limited_resolution);
sprang72acf252017-03-21 11:54:11 -07001119 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1120
1121 // Back to the source with adaptation off, set it back to maintain-resolution.
1122 vie_encoder_->SetSource(
1123 &new_video_source,
1124 VideoSendStream::DegradationPreference::kMaintainResolution);
1125 new_video_source.IncomingCapturedFrame(
1126 CreateFrame(sequence, frame_width, frame_height));
1127 sink_.WaitForEncodedFrame(sequence++);
1128 stats = stats_proxy_->GetStats();
1129 // Disabled, since we previously switched the source too disabled.
1130 EXPECT_FALSE(stats.cpu_limited_resolution);
1131 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1132
1133 // Trigger CPU normal usage.
1134 vie_encoder_->TriggerCpuNormalUsage();
1135 new_video_source.IncomingCapturedFrame(
1136 CreateFrame(sequence, frame_width, frame_height));
1137 sink_.WaitForEncodedFrame(sequence++);
1138 stats = stats_proxy_->GetStats();
1139 EXPECT_FALSE(stats.cpu_limited_resolution);
1140 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001141
1142 vie_encoder_->Stop();
1143}
1144
Erik Språng08127a92016-11-16 16:41:30 +01001145TEST_F(ViEEncoderTest, StatsTracksPreferredBitrate) {
Erik Språng08127a92016-11-16 16:41:30 +01001146 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1147
1148 video_source_.IncomingCapturedFrame(CreateFrame(1, 1280, 720));
1149 sink_.WaitForEncodedFrame(1);
1150
1151 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1152 EXPECT_EQ(video_encoder_config_.max_bitrate_bps,
1153 stats.preferred_media_bitrate_bps);
1154
1155 vie_encoder_->Stop();
1156}
1157
kthelgason876222f2016-11-29 01:44:11 -08001158TEST_F(ViEEncoderTest, ScalingUpAndDownDoesNothingWithMaintainResolution) {
kthelgason876222f2016-11-29 01:44:11 -08001159 int frame_width = 1280;
1160 int frame_height = 720;
1161 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1162
1163 // Expect no scaling to begin with
sprang84a37592017-02-10 07:04:27 -08001164 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
sprang72acf252017-03-21 11:54:11 -07001165 EXPECT_EQ(std::numeric_limits<int>::max(),
1166 video_source_.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001167
kthelgason876222f2016-11-29 01:44:11 -08001168 video_source_.IncomingCapturedFrame(
1169 CreateFrame(1, frame_width, frame_height));
1170 sink_.WaitForEncodedFrame(1);
1171
kthelgason5e13d412016-12-01 03:59:51 -08001172 // Trigger scale down
1173 vie_encoder_->TriggerQualityLow();
1174
1175 video_source_.IncomingCapturedFrame(
1176 CreateFrame(2, frame_width, frame_height));
1177 sink_.WaitForEncodedFrame(2);
1178
kthelgason876222f2016-11-29 01:44:11 -08001179 // Expect a scale down.
1180 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
sprang72acf252017-03-21 11:54:11 -07001181 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
kthelgason876222f2016-11-29 01:44:11 -08001182 frame_width * frame_height);
1183
1184 // Set adaptation disabled.
1185 test::FrameForwarder new_video_source;
1186 vie_encoder_->SetSource(
1187 &new_video_source,
1188 VideoSendStream::DegradationPreference::kMaintainResolution);
1189
1190 // Trigger scale down
1191 vie_encoder_->TriggerQualityLow();
1192 new_video_source.IncomingCapturedFrame(
kthelgason5e13d412016-12-01 03:59:51 -08001193 CreateFrame(3, frame_width, frame_height));
1194 sink_.WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001195
1196 // Expect no scaling
sprang72acf252017-03-21 11:54:11 -07001197 EXPECT_EQ(std::numeric_limits<int>::max(),
1198 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001199
1200 // Trigger scale up
1201 vie_encoder_->TriggerQualityHigh();
1202 new_video_source.IncomingCapturedFrame(
kthelgason5e13d412016-12-01 03:59:51 -08001203 CreateFrame(4, frame_width, frame_height));
1204 sink_.WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001205
1206 // Expect nothing to change, still no scaling
sprang72acf252017-03-21 11:54:11 -07001207 EXPECT_EQ(std::numeric_limits<int>::max(),
1208 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001209
1210 vie_encoder_->Stop();
1211}
1212
kthelgason5e13d412016-12-01 03:59:51 -08001213TEST_F(ViEEncoderTest, DoesNotScaleBelowSetLimit) {
kthelgason5e13d412016-12-01 03:59:51 -08001214 int frame_width = 1280;
1215 int frame_height = 720;
kthelgason5e13d412016-12-01 03:59:51 -08001216 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1217
1218 for (size_t i = 1; i <= 10; i++) {
1219 video_source_.IncomingCapturedFrame(
1220 CreateFrame(i, frame_width, frame_height));
1221 sink_.WaitForEncodedFrame(i);
1222 // Trigger scale down
1223 vie_encoder_->TriggerQualityLow();
sprang72acf252017-03-21 11:54:11 -07001224 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
kthelgason5e13d412016-12-01 03:59:51 -08001225 }
1226
1227 vie_encoder_->Stop();
1228}
1229
perkj803d97f2016-11-01 11:45:46 -07001230TEST_F(ViEEncoderTest, UMACpuLimitedResolutionInPercent) {
perkj803d97f2016-11-01 11:45:46 -07001231 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1232
1233 int frame_width = 640;
1234 int frame_height = 360;
1235
1236 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
1237 video_source_.IncomingCapturedFrame(
1238 CreateFrame(i, frame_width, frame_height));
1239 sink_.WaitForEncodedFrame(i);
1240 }
1241
1242 vie_encoder_->TriggerCpuOveruse();
1243 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
1244 video_source_.IncomingCapturedFrame(
1245 CreateFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i,
1246 frame_width, frame_height));
1247 sink_.WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples +
1248 i);
1249 }
1250
1251 vie_encoder_->Stop();
sprangf8ee65e2017-02-28 08:49:33 -08001252 vie_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07001253 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08001254
perkj803d97f2016-11-01 11:45:46 -07001255 EXPECT_EQ(1,
1256 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
1257 EXPECT_EQ(
1258 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
1259}
1260
sprang57c2fff2017-01-16 06:24:02 -08001261TEST_F(ViEEncoderTest, CallsBitrateObserver) {
1262 class MockBitrateObserver : public VideoBitrateAllocationObserver {
1263 public:
1264 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const BitrateAllocation&));
1265 } bitrate_observer;
1266 vie_encoder_->SetBitrateObserver(&bitrate_observer);
1267
1268 const int kDefaultFps = 30;
1269 const BitrateAllocation expected_bitrate =
1270 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08001271 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08001272
1273 // First called on bitrate updated, then again on first frame.
1274 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
1275 .Times(2);
kthelgason2bc68642017-02-07 07:02:22 -08001276 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08001277
1278 const int64_t kStartTimeMs = 1;
1279 video_source_.IncomingCapturedFrame(
1280 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
1281 sink_.WaitForEncodedFrame(kStartTimeMs);
1282
1283 // Not called on second frame.
1284 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
1285 .Times(0);
1286 video_source_.IncomingCapturedFrame(
1287 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
1288 sink_.WaitForEncodedFrame(kStartTimeMs + 1);
1289
1290 // Called after a process interval.
1291 const int64_t kProcessIntervalMs =
1292 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
1293 // TODO(sprang): ViEEncoder should die and/or get injectable clock.
1294 // Sleep for one processing interval plus one frame to avoid flakiness.
1295 SleepMs(kProcessIntervalMs + 1000 / kDefaultFps);
1296 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
1297 .Times(1);
1298 video_source_.IncomingCapturedFrame(CreateFrame(
1299 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
1300 sink_.WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
1301
1302 vie_encoder_->Stop();
1303}
1304
kthelgason2bc68642017-02-07 07:02:22 -08001305TEST_F(ViEEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
1306 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
1307 int frame_width = 640;
1308 int frame_height = 360;
1309
1310 video_source_.IncomingCapturedFrame(
1311 CreateFrame(1, frame_width, frame_height));
1312
1313 // Expect to drop this frame, the wait should time out.
1314 sink_.ExpectDroppedFrame();
1315
1316 // Expect the sink_wants to specify a scaled frame.
sprang72acf252017-03-21 11:54:11 -07001317 EXPECT_LT(video_source_.sink_wants().max_pixel_count, 1000 * 1000);
kthelgason2bc68642017-02-07 07:02:22 -08001318
sprang72acf252017-03-21 11:54:11 -07001319 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08001320
1321 // Next frame is scaled
1322 video_source_.IncomingCapturedFrame(
1323 CreateFrame(2, frame_width * 3 / 4, frame_height * 3 / 4));
1324
1325 // Expect to drop this frame, the wait should time out.
1326 sink_.ExpectDroppedFrame();
1327
sprang72acf252017-03-21 11:54:11 -07001328 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08001329
1330 vie_encoder_->Stop();
1331}
1332
kthelgason2fc52542017-03-03 00:24:41 -08001333TEST_F(ViEEncoderTest, NrOfDroppedFramesLimited) {
kthelgason2bc68642017-02-07 07:02:22 -08001334 // 1kbps. This can never be achieved.
1335 vie_encoder_->OnBitrateUpdated(1000, 0, 0);
1336 int frame_width = 640;
1337 int frame_height = 360;
1338
1339 // We expect the n initial frames to get dropped.
1340 int i;
1341 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
1342 video_source_.IncomingCapturedFrame(
1343 CreateFrame(i, frame_width, frame_height));
1344 sink_.ExpectDroppedFrame();
1345 }
1346 // The n+1th frame should not be dropped, even though it's size is too large.
1347 video_source_.IncomingCapturedFrame(
1348 CreateFrame(i, frame_width, frame_height));
1349 sink_.WaitForEncodedFrame(i);
1350
1351 // Expect the sink_wants to specify a scaled frame.
sprang72acf252017-03-21 11:54:11 -07001352 EXPECT_LT(video_source_.sink_wants().max_pixel_count, 1000 * 1000);
kthelgason2bc68642017-02-07 07:02:22 -08001353
1354 vie_encoder_->Stop();
1355}
1356
1357TEST_F(ViEEncoderTest, InitialFrameDropOffWithMaintainResolutionPreference) {
1358 int frame_width = 640;
1359 int frame_height = 360;
1360 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
1361
1362 // Set degradation preference.
1363 vie_encoder_->SetSource(
1364 &video_source_,
1365 VideoSendStream::DegradationPreference::kMaintainResolution);
1366
1367 video_source_.IncomingCapturedFrame(
1368 CreateFrame(1, frame_width, frame_height));
1369 // Frame should not be dropped, even if it's too large.
1370 sink_.WaitForEncodedFrame(1);
1371
1372 vie_encoder_->Stop();
1373}
1374
kthelgason2fc52542017-03-03 00:24:41 -08001375TEST_F(ViEEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
kthelgasonad9010c2017-02-14 00:46:51 -08001376 int frame_width = 640;
1377 int frame_height = 360;
1378 fake_encoder_.SetQualityScaling(false);
1379 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgasonb83797b2017-02-14 11:57:25 -08001380 // Force quality scaler reconfiguration by resetting the source.
1381 vie_encoder_->SetSource(&video_source_,
1382 VideoSendStream::DegradationPreference::kBalanced);
kthelgasonad9010c2017-02-14 00:46:51 -08001383
1384 video_source_.IncomingCapturedFrame(
1385 CreateFrame(1, frame_width, frame_height));
1386 // Frame should not be dropped, even if it's too large.
1387 sink_.WaitForEncodedFrame(1);
1388
1389 vie_encoder_->Stop();
1390 fake_encoder_.SetQualityScaling(true);
1391}
1392
sprangb1ca0732017-02-01 08:38:12 -08001393// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
1394TEST_F(ViEEncoderTest, AdaptsResolutionOnOveruse) {
1395 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1396
1397 const int kFrameWidth = 1280;
1398 const int kFrameHeight = 720;
1399 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
1400 // requested by ViEEncoder::VideoSourceProxy::RequestResolutionLowerThan().
1401 video_source_.set_adaptation_enabled(true);
1402
1403 video_source_.IncomingCapturedFrame(
1404 CreateFrame(1, kFrameWidth, kFrameHeight));
1405 sink_.WaitForEncodedFrame(kFrameWidth, kFrameHeight);
1406
1407 // Trigger CPU overuse, downscale by 3/4.
1408 vie_encoder_->TriggerCpuOveruse();
1409 video_source_.IncomingCapturedFrame(
1410 CreateFrame(2, kFrameWidth, kFrameHeight));
1411 sink_.WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
1412
sprang72acf252017-03-21 11:54:11 -07001413 // Trigger CPU normal use, return to original resolution;
sprangb1ca0732017-02-01 08:38:12 -08001414 vie_encoder_->TriggerCpuNormalUsage();
1415 video_source_.IncomingCapturedFrame(
1416 CreateFrame(3, kFrameWidth, kFrameHeight));
1417 sink_.WaitForEncodedFrame(kFrameWidth, kFrameHeight);
1418
1419 vie_encoder_->Stop();
1420}
sprang72acf252017-03-21 11:54:11 -07001421
1422TEST_F(ViEEncoderTest, AdaptsFrameOnOveruseWithMaintainResolution) {
1423 const int kDefaultFramerateFps = 30;
1424 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kDefaultFramerateFps;
1425 const int kFrameWidth = 1280;
1426 const int kFrameHeight = 720;
1427 rtc::ScopedFakeClock fake_clock;
1428
1429 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1430 vie_encoder_->SetSource(
1431 &video_source_,
1432 VideoSendStream::DegradationPreference::kMaintainResolution);
1433 video_source_.set_adaptation_enabled(true);
1434
1435 fake_clock.SetTimeMicros(kFrameIntervalMs * 1000);
1436 int64_t timestamp_ms = kFrameIntervalMs;
1437
1438 video_source_.IncomingCapturedFrame(
1439 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1440 sink_.WaitForEncodedFrame(timestamp_ms);
1441
1442 // Try to trigger overuse. No fps estimate available => no effect.
1443 vie_encoder_->TriggerCpuOveruse();
1444
1445 // Insert frames for one second to get a stable estimate.
1446 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1447 timestamp_ms += kFrameIntervalMs;
1448 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1449 video_source_.IncomingCapturedFrame(
1450 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1451 sink_.WaitForEncodedFrame(timestamp_ms);
1452 }
1453
1454 // Trigger CPU overuse, reduce framerate by 2/3.
1455 vie_encoder_->TriggerCpuOveruse();
1456 int num_frames_dropped = 0;
1457 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1458 timestamp_ms += kFrameIntervalMs;
1459 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1460 video_source_.IncomingCapturedFrame(
1461 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1462 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
1463 ++num_frames_dropped;
1464 } else {
1465 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
1466 }
1467 }
1468
1469 // TODO(sprang): Find where there's rounding errors or stuff causing the
1470 // margin here to be a little larger than we'd like (input fps estimate is
1471 // off) and the frame dropping is a little too aggressive.
1472 const int kErrorMargin = 5;
1473 EXPECT_NEAR(num_frames_dropped,
1474 kDefaultFramerateFps - (kDefaultFramerateFps * 2 / 3),
1475 kErrorMargin);
1476
1477 // Trigger CPU overuse, reduce framerate by 2/3 again.
1478 vie_encoder_->TriggerCpuOveruse();
1479 num_frames_dropped = 0;
1480 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1481 timestamp_ms += kFrameIntervalMs;
1482 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1483 video_source_.IncomingCapturedFrame(
1484 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1485 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
1486 ++num_frames_dropped;
1487 } else {
1488 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
1489 }
1490 }
1491 EXPECT_NEAR(num_frames_dropped,
1492 kDefaultFramerateFps - (kDefaultFramerateFps * 4 / 9),
1493 kErrorMargin);
1494
1495 // Go back up one step.
1496 vie_encoder_->TriggerCpuNormalUsage();
1497 num_frames_dropped = 0;
1498 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1499 timestamp_ms += kFrameIntervalMs;
1500 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1501 video_source_.IncomingCapturedFrame(
1502 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1503 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
1504 ++num_frames_dropped;
1505 } else {
1506 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
1507 }
1508 }
1509 EXPECT_NEAR(num_frames_dropped,
1510 kDefaultFramerateFps - (kDefaultFramerateFps * 2 / 3),
1511 kErrorMargin);
1512
1513 // Go back up to original mode.
1514 vie_encoder_->TriggerCpuNormalUsage();
1515 num_frames_dropped = 0;
1516 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1517 timestamp_ms += kFrameIntervalMs;
1518 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1519 video_source_.IncomingCapturedFrame(
1520 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1521 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
1522 ++num_frames_dropped;
1523 } else {
1524 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
1525 }
1526 }
1527 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
1528
1529 vie_encoder_->Stop();
1530}
1531
1532TEST_F(ViEEncoderTest, DoesntAdaptDownPastMinFramerate) {
1533 const int kFramerateFps = 5;
1534 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
1535 const int kMinFpsFrameInterval = rtc::kNumMillisecsPerSec / kMinFramerateFps;
1536 const int kFrameWidth = 1280;
1537 const int kFrameHeight = 720;
1538
1539 rtc::ScopedFakeClock fake_clock;
1540 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1541 vie_encoder_->SetSource(
1542 &video_source_,
1543 VideoSendStream::DegradationPreference::kMaintainResolution);
1544 video_source_.set_adaptation_enabled(true);
1545
1546 fake_clock.SetTimeMicros(kFrameIntervalMs * 1000);
1547 int64_t timestamp_ms = kFrameIntervalMs;
1548
1549 // Trigger overuse as much as we can.
1550 for (int i = 0; i < ViEEncoder::kMaxCpuResolutionDowngrades; ++i) {
1551 // Insert frames to get a new fps estimate...
1552 for (int j = 0; j < kFramerateFps; ++j) {
1553 video_source_.IncomingCapturedFrame(
1554 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1555 timestamp_ms += kFrameIntervalMs;
1556 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1557 }
1558 // ...and then try to adapt again.
1559 vie_encoder_->TriggerCpuOveruse();
1560 }
1561
1562 // Drain any frame in the pipeline.
1563 sink_.WaitForFrame(kDefaultTimeoutMs);
1564
1565 // Insert frames at min fps, all should go through.
1566 for (int i = 0; i < 10; ++i) {
1567 timestamp_ms += kMinFpsFrameInterval;
1568 fake_clock.AdvanceTimeMicros(kMinFpsFrameInterval * 1000);
1569 video_source_.IncomingCapturedFrame(
1570 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1571 sink_.WaitForEncodedFrame(timestamp_ms);
1572 }
1573
1574 vie_encoder_->Stop();
1575}
perkj26091b12016-09-01 01:17:40 -07001576} // namespace webrtc