blob: 8c57d885be3193234935d85707a2813c4ddd8e7b [file] [log] [blame]
perkj26091b12016-09-01 01:17:40 -07001/*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
sprangfe627f32017-03-29 08:24:59 -070011#include <algorithm>
perkj803d97f2016-11-01 11:45:46 -070012#include <limits>
Per512ecb32016-09-23 15:52:06 +020013#include <utility>
14
nisseaf916892017-01-10 07:44:26 -080015#include "webrtc/api/video/i420_buffer.h"
sprangc5d62e22017-04-02 23:53:04 -070016#include "webrtc/base/fakeclock.h"
perkj26091b12016-09-01 01:17:40 -070017#include "webrtc/base/logging.h"
sprangb1ca0732017-02-01 08:38:12 -080018#include "webrtc/media/base/videoadapter.h"
sprangfe627f32017-03-29 08:24:59 -070019#include "webrtc/modules/video_coding/codecs/vp8/temporal_layers.h"
sprang57c2fff2017-01-16 06:24:02 -080020#include "webrtc/modules/video_coding/utility/default_video_bitrate_allocator.h"
perkj803d97f2016-11-01 11:45:46 -070021#include "webrtc/system_wrappers/include/metrics_default.h"
sprang57c2fff2017-01-16 06:24:02 -080022#include "webrtc/system_wrappers/include/sleep.h"
perkj26091b12016-09-01 01:17:40 -070023#include "webrtc/test/encoder_settings.h"
24#include "webrtc/test/fake_encoder.h"
perkja49cbd32016-09-16 07:53:41 -070025#include "webrtc/test/frame_generator.h"
sprang57c2fff2017-01-16 06:24:02 -080026#include "webrtc/test/gmock.h"
kwibergac9f8762016-09-30 22:29:43 -070027#include "webrtc/test/gtest.h"
perkj26091b12016-09-01 01:17:40 -070028#include "webrtc/video/send_statistics_proxy.h"
29#include "webrtc/video/vie_encoder.h"
30
kthelgason33ce8892016-12-09 03:53:59 -080031namespace {
32#if defined(WEBRTC_ANDROID)
33// TODO(kthelgason): Lower this limit when better testing
34// on MediaCodec and fallback implementations are in place.
35const int kMinPixelsPerFrame = 320 * 180;
36#else
37const int kMinPixelsPerFrame = 120 * 90;
38#endif
sprangc5d62e22017-04-02 23:53:04 -070039const int kMinFramerateFps = 2;
40const int64_t kFrameTimeoutMs = 100;
41} // namespace
kthelgason33ce8892016-12-09 03:53:59 -080042
perkj26091b12016-09-01 01:17:40 -070043namespace webrtc {
44
kthelgason876222f2016-11-29 01:44:11 -080045using DegredationPreference = VideoSendStream::DegradationPreference;
sprangb1ca0732017-02-01 08:38:12 -080046using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080047using ::testing::_;
48using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080049
perkj803d97f2016-11-01 11:45:46 -070050namespace {
asapersson5f7226f2016-11-25 04:37:00 -080051const size_t kMaxPayloadLength = 1440;
kthelgason2bc68642017-02-07 07:02:22 -080052const int kTargetBitrateBps = 1000000;
53const int kLowTargetBitrateBps = kTargetBitrateBps / 10;
54const int kMaxInitialFramedrop = 4;
asapersson5f7226f2016-11-25 04:37:00 -080055
perkj803d97f2016-11-01 11:45:46 -070056class TestBuffer : public webrtc::I420Buffer {
57 public:
58 TestBuffer(rtc::Event* event, int width, int height)
59 : I420Buffer(width, height), event_(event) {}
60
61 private:
62 friend class rtc::RefCountedObject<TestBuffer>;
63 ~TestBuffer() override {
64 if (event_)
65 event_->Set();
66 }
67 rtc::Event* const event_;
68};
69
70class ViEEncoderUnderTest : public ViEEncoder {
71 public:
kthelgason876222f2016-11-29 01:44:11 -080072 ViEEncoderUnderTest(SendStatisticsProxy* stats_proxy,
73 const VideoSendStream::Config::EncoderSettings& settings)
perkj803d97f2016-11-01 11:45:46 -070074 : ViEEncoder(1 /* number_of_cores */,
75 stats_proxy,
76 settings,
77 nullptr /* pre_encode_callback */,
78 nullptr /* encoder_timing */) {}
79
sprangb1ca0732017-02-01 08:38:12 -080080 void PostTaskAndWait(bool down, AdaptReason reason) {
perkj803d97f2016-11-01 11:45:46 -070081 rtc::Event event(false, false);
kthelgason876222f2016-11-29 01:44:11 -080082 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -080083 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -070084 event.Set();
85 });
perkj070ba852017-02-16 15:46:27 -080086 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -070087 }
88
kthelgason2fc52542017-03-03 00:24:41 -080089 // This is used as a synchronisation mechanism, to make sure that the
90 // encoder queue is not blocked before we start sending it frames.
91 void WaitUntilTaskQueueIsIdle() {
92 rtc::Event event(false, false);
93 encoder_queue()->PostTask([&event] {
94 event.Set();
95 });
96 ASSERT_TRUE(event.Wait(5000));
97 }
98
sprangb1ca0732017-02-01 08:38:12 -080099 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800100
sprangb1ca0732017-02-01 08:38:12 -0800101 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800102
sprangb1ca0732017-02-01 08:38:12 -0800103 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800104
sprangb1ca0732017-02-01 08:38:12 -0800105 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
perkj803d97f2016-11-01 11:45:46 -0700106};
107
asapersson5f7226f2016-11-25 04:37:00 -0800108class VideoStreamFactory
109 : public VideoEncoderConfig::VideoStreamFactoryInterface {
110 public:
111 explicit VideoStreamFactory(size_t num_temporal_layers)
112 : num_temporal_layers_(num_temporal_layers) {
113 EXPECT_GT(num_temporal_layers, 0u);
114 }
115
116 private:
117 std::vector<VideoStream> CreateEncoderStreams(
118 int width,
119 int height,
120 const VideoEncoderConfig& encoder_config) override {
121 std::vector<VideoStream> streams =
122 test::CreateVideoStreams(width, height, encoder_config);
123 for (VideoStream& stream : streams) {
124 stream.temporal_layer_thresholds_bps.resize(num_temporal_layers_ - 1);
125 }
126 return streams;
127 }
128 const size_t num_temporal_layers_;
129};
130
sprangb1ca0732017-02-01 08:38:12 -0800131class AdaptingFrameForwarder : public test::FrameForwarder {
132 public:
133 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
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;
sprangc5d62e22017-04-02 23:53:04 -0700151 if (adaption_enabled()) {
152 if (adapter_.AdaptFrameResolution(
153 video_frame.width(), video_frame.height(),
154 video_frame.timestamp_us() * 1000, &cropped_width,
155 &cropped_height, &out_width, &out_height)) {
156 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
157 nullptr, out_width, out_height),
158 99, 99, kVideoRotation_0);
159 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
160 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
161 }
sprangb1ca0732017-02-01 08:38:12 -0800162 } else {
163 test::FrameForwarder::IncomingCapturedFrame(video_frame);
164 }
165 }
166
167 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
168 const rtc::VideoSinkWants& wants) override {
169 rtc::CritScope cs(&crit_);
sprangc5d62e22017-04-02 23:53:04 -0700170 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
171 wants.max_pixel_count,
172 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800173 test::FrameForwarder::AddOrUpdateSink(sink, wants);
174 }
175
176 cricket::VideoAdapter adapter_;
177 bool adaptation_enabled_ GUARDED_BY(crit_);
178};
sprangc5d62e22017-04-02 23:53:04 -0700179
180class MockableSendStatisticsProxy : public SendStatisticsProxy {
181 public:
182 MockableSendStatisticsProxy(Clock* clock,
183 const VideoSendStream::Config& config,
184 VideoEncoderConfig::ContentType content_type)
185 : SendStatisticsProxy(clock, config, content_type) {}
186
187 VideoSendStream::Stats GetStats() override {
188 rtc::CritScope cs(&lock_);
189 if (mock_stats_)
190 return *mock_stats_;
191 return SendStatisticsProxy::GetStats();
192 }
193
194 void SetMockStats(const VideoSendStream::Stats& stats) {
195 rtc::CritScope cs(&lock_);
196 mock_stats_.emplace(stats);
197 }
198
199 void ResetMockStats() {
200 rtc::CritScope cs(&lock_);
201 mock_stats_.reset();
202 }
203
204 private:
205 rtc::CriticalSection lock_;
206 rtc::Optional<VideoSendStream::Stats> mock_stats_ GUARDED_BY(lock_);
207};
208
perkj803d97f2016-11-01 11:45:46 -0700209} // namespace
210
perkj26091b12016-09-01 01:17:40 -0700211class ViEEncoderTest : public ::testing::Test {
212 public:
213 static const int kDefaultTimeoutMs = 30 * 1000;
214
215 ViEEncoderTest()
216 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700217 codec_width_(320),
218 codec_height_(240),
perkj26091b12016-09-01 01:17:40 -0700219 fake_encoder_(),
sprangc5d62e22017-04-02 23:53:04 -0700220 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700221 Clock::GetRealTimeClock(),
222 video_send_config_,
223 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700224 sink_(&fake_encoder_) {}
225
226 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700227 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700228 video_send_config_ = VideoSendStream::Config(nullptr);
229 video_send_config_.encoder_settings.encoder = &fake_encoder_;
230 video_send_config_.encoder_settings.payload_name = "FAKE";
231 video_send_config_.encoder_settings.payload_type = 125;
232
Per512ecb32016-09-23 15:52:06 +0200233 VideoEncoderConfig video_encoder_config;
perkjfa10b552016-10-02 23:45:26 -0700234 test::FillEncoderConfiguration(1, &video_encoder_config);
Erik Språng08127a92016-11-16 16:41:30 +0100235 video_encoder_config_ = video_encoder_config.Copy();
asapersson5f7226f2016-11-25 04:37:00 -0800236 ConfigureEncoder(std::move(video_encoder_config), true /* nack_enabled */);
237 }
238
239 void ConfigureEncoder(VideoEncoderConfig video_encoder_config,
240 bool nack_enabled) {
241 if (vie_encoder_)
242 vie_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700243 vie_encoder_.reset(new ViEEncoderUnderTest(
244 stats_proxy_.get(), video_send_config_.encoder_settings));
245 vie_encoder_->SetSink(&sink_, false /* rotation_applied */);
sprangc5d62e22017-04-02 23:53:04 -0700246 vie_encoder_->SetSource(
247 &video_source_,
248 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason2bc68642017-02-07 07:02:22 -0800249 vie_encoder_->SetStartBitrate(kTargetBitrateBps);
asapersson5f7226f2016-11-25 04:37:00 -0800250 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
251 kMaxPayloadLength, nack_enabled);
kthelgason2fc52542017-03-03 00:24:41 -0800252 vie_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800253 }
254
255 void ResetEncoder(const std::string& payload_name,
256 size_t num_streams,
257 size_t num_temporal_layers,
258 bool nack_enabled) {
259 video_send_config_.encoder_settings.payload_name = payload_name;
260
261 VideoEncoderConfig video_encoder_config;
262 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800263 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800264 video_encoder_config.video_stream_factory =
265 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers);
266 ConfigureEncoder(std::move(video_encoder_config), nack_enabled);
perkj26091b12016-09-01 01:17:40 -0700267 }
268
sprang57c2fff2017-01-16 06:24:02 -0800269 VideoFrame CreateFrame(int64_t ntp_time_ms,
270 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200271 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
272 destruction_event, codec_width_, codec_height_),
273 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800274 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700275 return frame;
276 }
277
sprang57c2fff2017-01-16 06:24:02 -0800278 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700279 VideoFrame frame(
280 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
281 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800282 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700283 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700284 return frame;
285 }
286
perkj26091b12016-09-01 01:17:40 -0700287 class TestEncoder : public test::FakeEncoder {
288 public:
289 TestEncoder()
290 : FakeEncoder(Clock::GetRealTimeClock()),
291 continue_encode_event_(false, false) {}
292
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) {
sprangc5d62e22017-04-02 23:53:04 -0700406 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
407 CheckLastFrameSizeMathces(expected_width, expected_height);
408 }
409
410 void CheckLastFrameSizeMathces(uint32_t expected_width,
411 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800412 uint32_t width = 0;
413 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800414 {
415 rtc::CritScope lock(&crit_);
416 width = last_width_;
417 height = last_height_;
418 }
419 EXPECT_EQ(expected_height, height);
420 EXPECT_EQ(expected_width, width);
421 }
422
kthelgason2fc52542017-03-03 00:24:41 -0800423 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800424
sprangc5d62e22017-04-02 23:53:04 -0700425 bool WaitForFrame(int64_t timeout_ms) {
426 return encoded_frame_event_.Wait(timeout_ms);
427 }
428
perkj26091b12016-09-01 01:17:40 -0700429 void SetExpectNoFrames() {
430 rtc::CritScope lock(&crit_);
431 expect_frames_ = false;
432 }
433
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_;
sprangc5d62e22017-04-02 23:53:04 -0700481 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700482 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800483 AdaptingFrameForwarder video_source_;
perkj803d97f2016-11-01 11:45:46 -0700484 std::unique_ptr<ViEEncoderUnderTest> vie_encoder_;
perkj26091b12016-09-01 01:17:40 -0700485};
486
487TEST_F(ViEEncoderTest, EncodeOneFrame) {
perkj26091b12016-09-01 01:17:40 -0700488 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
489 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700490 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
perkj26091b12016-09-01 01:17:40 -0700491 sink_.WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700492 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700493 vie_encoder_->Stop();
494}
495
496TEST_F(ViEEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
497 // Dropped since no target bitrate has been set.
498 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700499 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
500 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700501
perkj26091b12016-09-01 01:17:40 -0700502 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
503
perkja49cbd32016-09-16 07:53:41 -0700504 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkj26091b12016-09-01 01:17:40 -0700505 sink_.WaitForEncodedFrame(2);
506 vie_encoder_->Stop();
507}
508
509TEST_F(ViEEncoderTest, DropsFramesWhenRateSetToZero) {
perkj26091b12016-09-01 01:17:40 -0700510 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700511 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700512 sink_.WaitForEncodedFrame(1);
513
514 vie_encoder_->OnBitrateUpdated(0, 0, 0);
515 // Dropped since bitrate is zero.
perkja49cbd32016-09-16 07:53:41 -0700516 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkj26091b12016-09-01 01:17:40 -0700517
518 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700519 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700520 sink_.WaitForEncodedFrame(3);
521 vie_encoder_->Stop();
522}
523
524TEST_F(ViEEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
perkj26091b12016-09-01 01:17:40 -0700525 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700526 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700527 sink_.WaitForEncodedFrame(1);
528
529 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700530 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700531
perkja49cbd32016-09-16 07:53:41 -0700532 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkj26091b12016-09-01 01:17:40 -0700533 sink_.WaitForEncodedFrame(2);
534 vie_encoder_->Stop();
535}
536
537TEST_F(ViEEncoderTest, DropsFrameAfterStop) {
perkj26091b12016-09-01 01:17:40 -0700538 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
539
perkja49cbd32016-09-16 07:53:41 -0700540 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700541 sink_.WaitForEncodedFrame(1);
542
543 vie_encoder_->Stop();
544 sink_.SetExpectNoFrames();
545 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700546 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
547 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700548}
549
550TEST_F(ViEEncoderTest, DropsPendingFramesOnSlowEncode) {
perkj26091b12016-09-01 01:17:40 -0700551 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
552
553 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700554 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700555 sink_.WaitForEncodedFrame(1);
556 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
557 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700558 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
559 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700560 fake_encoder_.ContinueEncode();
561 sink_.WaitForEncodedFrame(3);
562
563 vie_encoder_->Stop();
564}
565
Per512ecb32016-09-23 15:52:06 +0200566TEST_F(ViEEncoderTest, ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
Per512ecb32016-09-23 15:52:06 +0200567 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100568 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200569
570 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200571 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
Per512ecb32016-09-23 15:52:06 +0200572 sink_.WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100573 // The encoder will have been configured once when the first frame is
574 // received.
575 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200576
577 VideoEncoderConfig video_encoder_config;
perkjfa10b552016-10-02 23:45:26 -0700578 test::FillEncoderConfiguration(1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200579 video_encoder_config.min_transmit_bitrate_bps = 9999;
asapersson5f7226f2016-11-25 04:37:00 -0800580 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
581 kMaxPayloadLength, true /* nack_enabled */);
Per512ecb32016-09-23 15:52:06 +0200582
583 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200584 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Per512ecb32016-09-23 15:52:06 +0200585 sink_.WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100586 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700587 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700588
589 vie_encoder_->Stop();
590}
591
perkjfa10b552016-10-02 23:45:26 -0700592TEST_F(ViEEncoderTest, FrameResolutionChangeReconfigureEncoder) {
perkjfa10b552016-10-02 23:45:26 -0700593 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
594
595 // Capture a frame and wait for it to synchronize with the encoder thread.
596 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
597 sink_.WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100598 // The encoder will have been configured once.
599 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700600 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
601 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
602
603 codec_width_ *= 2;
604 codec_height_ *= 2;
605 // Capture a frame with a higher resolution and wait for it to synchronize
606 // with the encoder thread.
607 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
608 sink_.WaitForEncodedFrame(2);
609 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
610 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100611 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700612
613 vie_encoder_->Stop();
614}
615
asapersson5f7226f2016-11-25 04:37:00 -0800616TEST_F(ViEEncoderTest, Vp8ResilienceIsOffFor1S1TLWithNackEnabled) {
617 const bool kNackEnabled = true;
618 const size_t kNumStreams = 1;
619 const size_t kNumTl = 1;
asaperssona90799d2016-12-09 02:35:20 -0800620 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800621 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
622
623 // Capture a frame and wait for it to synchronize with the encoder thread.
624 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
625 sink_.WaitForEncodedFrame(1);
626 // The encoder have been configured once when the first frame is received.
627 EXPECT_EQ(1, sink_.number_of_reconfigurations());
628 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
629 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
630 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
631 // Resilience is off for no temporal layers with nack on.
632 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
633 vie_encoder_->Stop();
634}
635
636TEST_F(ViEEncoderTest, Vp8ResilienceIsOffFor2S1TlWithNackEnabled) {
637 const bool kNackEnabled = true;
638 const size_t kNumStreams = 2;
639 const size_t kNumTl = 1;
asaperssona90799d2016-12-09 02:35:20 -0800640 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800641 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
642
643 // Capture a frame and wait for it to synchronize with the encoder thread.
644 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
645 sink_.WaitForEncodedFrame(1);
646 // The encoder have been configured once when the first frame is received.
647 EXPECT_EQ(1, sink_.number_of_reconfigurations());
648 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
649 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
650 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
651 // Resilience is off for no temporal layers and >1 streams with nack on.
652 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
653 vie_encoder_->Stop();
654}
655
656TEST_F(ViEEncoderTest, Vp8ResilienceIsOnFor1S1TLWithNackDisabled) {
657 const bool kNackEnabled = false;
658 const size_t kNumStreams = 1;
659 const size_t kNumTl = 1;
asaperssona90799d2016-12-09 02:35:20 -0800660 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800661 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
662
663 // Capture a frame and wait for it to synchronize with the encoder thread.
664 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
665 sink_.WaitForEncodedFrame(1);
666 // The encoder have been configured once when the first frame is received.
667 EXPECT_EQ(1, sink_.number_of_reconfigurations());
668 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
669 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
670 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
671 // Resilience is on for no temporal layers with nack off.
672 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
673 vie_encoder_->Stop();
674}
675
676TEST_F(ViEEncoderTest, Vp8ResilienceIsOnFor1S2TlWithNackEnabled) {
677 const bool kNackEnabled = true;
678 const size_t kNumStreams = 1;
679 const size_t kNumTl = 2;
asaperssona90799d2016-12-09 02:35:20 -0800680 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled);
asapersson5f7226f2016-11-25 04:37:00 -0800681 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
682
683 // Capture a frame and wait for it to synchronize with the encoder thread.
684 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
685 sink_.WaitForEncodedFrame(1);
686 // The encoder have been configured once when the first frame is received.
687 EXPECT_EQ(1, sink_.number_of_reconfigurations());
688 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
689 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
690 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
691 // Resilience is on for temporal layers.
692 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
693 vie_encoder_->Stop();
694}
695
perkj803d97f2016-11-01 11:45:46 -0700696TEST_F(ViEEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
697 EXPECT_TRUE(video_source_.has_sinks());
698 test::FrameForwarder new_video_source;
sprangc5d62e22017-04-02 23:53:04 -0700699 vie_encoder_->SetSource(
700 &new_video_source,
701 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -0700702 EXPECT_FALSE(video_source_.has_sinks());
703 EXPECT_TRUE(new_video_source.has_sinks());
704
705 vie_encoder_->Stop();
706}
707
708TEST_F(ViEEncoderTest, SinkWantsRotationApplied) {
709 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
710 vie_encoder_->SetSink(&sink_, true /*rotation_applied*/);
711 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
712 vie_encoder_->Stop();
713}
714
715TEST_F(ViEEncoderTest, SinkWantsFromOveruseDetector) {
perkj803d97f2016-11-01 11:45:46 -0700716 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
717
sprang84a37592017-02-10 07:04:27 -0800718 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700719 EXPECT_EQ(std::numeric_limits<int>::max(),
720 video_source_.sink_wants().max_pixel_count);
perkj803d97f2016-11-01 11:45:46 -0700721
722 int frame_width = 1280;
723 int frame_height = 720;
724
725 // Trigger CPU overuse kMaxCpuDowngrades times. Every time, ViEEncoder should
726 // request lower resolution.
sprangc5d62e22017-04-02 23:53:04 -0700727 for (int i = 1; i <= ViEEncoder::kMaxCpuResolutionDowngrades; ++i) {
perkj803d97f2016-11-01 11:45:46 -0700728 video_source_.IncomingCapturedFrame(
729 CreateFrame(i, frame_width, frame_height));
730 sink_.WaitForEncodedFrame(i);
731
732 vie_encoder_->TriggerCpuOveruse();
733
sprang84a37592017-02-10 07:04:27 -0800734 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700735 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
perkj803d97f2016-11-01 11:45:46 -0700736 frame_width * frame_height);
perkj803d97f2016-11-01 11:45:46 -0700737
738 frame_width /= 2;
739 frame_height /= 2;
740 }
741
kthelgason876222f2016-11-29 01:44:11 -0800742 // Trigger CPU overuse one more time. This should not trigger a request for
perkj803d97f2016-11-01 11:45:46 -0700743 // lower resolution.
744 rtc::VideoSinkWants current_wants = video_source_.sink_wants();
745 video_source_.IncomingCapturedFrame(CreateFrame(
sprangc5d62e22017-04-02 23:53:04 -0700746 ViEEncoder::kMaxCpuResolutionDowngrades + 1, frame_width, frame_height));
747 sink_.WaitForEncodedFrame(ViEEncoder::kMaxCpuResolutionDowngrades + 1);
perkj803d97f2016-11-01 11:45:46 -0700748 vie_encoder_->TriggerCpuOveruse();
sprang84a37592017-02-10 07:04:27 -0800749 EXPECT_EQ(video_source_.sink_wants().target_pixel_count,
750 current_wants.target_pixel_count);
perkj803d97f2016-11-01 11:45:46 -0700751 EXPECT_EQ(video_source_.sink_wants().max_pixel_count,
752 current_wants.max_pixel_count);
perkj803d97f2016-11-01 11:45:46 -0700753
754 // Trigger CPU normal use.
755 vie_encoder_->TriggerCpuNormalUsage();
sprang84a37592017-02-10 07:04:27 -0800756 EXPECT_EQ(frame_width * frame_height * 5 / 3,
757 video_source_.sink_wants().target_pixel_count.value_or(0));
758 EXPECT_EQ(frame_width * frame_height * 4,
sprangc5d62e22017-04-02 23:53:04 -0700759 video_source_.sink_wants().max_pixel_count);
perkj803d97f2016-11-01 11:45:46 -0700760
761 vie_encoder_->Stop();
762}
763
sprangc5d62e22017-04-02 23:53:04 -0700764TEST_F(ViEEncoderTest, SinkWantsStoredByDegradationPreference) {
perkj803d97f2016-11-01 11:45:46 -0700765 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
766
sprang84a37592017-02-10 07:04:27 -0800767 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700768 EXPECT_EQ(std::numeric_limits<int>::max(),
769 video_source_.sink_wants().max_pixel_count);
770 EXPECT_EQ(std::numeric_limits<int>::max(),
771 video_source_.sink_wants().max_framerate_fps);
perkj803d97f2016-11-01 11:45:46 -0700772
sprangc5d62e22017-04-02 23:53:04 -0700773 const int kFrameWidth = 1280;
774 const int kFrameHeight = 720;
775 const int kFrameIntervalMs = 1000 / 30;
776
777 int frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -0700778
kthelgason5e13d412016-12-01 03:59:51 -0800779 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700780 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
781 sink_.WaitForEncodedFrame(frame_timestamp);
782 frame_timestamp += kFrameIntervalMs;
783
perkj803d97f2016-11-01 11:45:46 -0700784 // Trigger CPU overuse.
785 vie_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700786 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700787 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
788 sink_.WaitForEncodedFrame(frame_timestamp);
789 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -0700790
sprangc5d62e22017-04-02 23:53:04 -0700791 // Default degradation preference in maintain-framerate, so will lower max
792 // wanted resolution.
793 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
794 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
795 kFrameWidth * kFrameHeight);
796 EXPECT_EQ(std::numeric_limits<int>::max(),
797 video_source_.sink_wants().max_framerate_fps);
798
799 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -0700800 test::FrameForwarder new_video_source;
801 vie_encoder_->SetSource(
802 &new_video_source,
803 VideoSendStream::DegradationPreference::kMaintainResolution);
804
sprangc5d62e22017-04-02 23:53:04 -0700805 // Initially no degradation registered.
sprang84a37592017-02-10 07:04:27 -0800806 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700807 EXPECT_EQ(std::numeric_limits<int>::max(),
808 new_video_source.sink_wants().max_pixel_count);
809 EXPECT_EQ(std::numeric_limits<int>::max(),
810 new_video_source.sink_wants().max_framerate_fps);
perkj803d97f2016-11-01 11:45:46 -0700811
sprangc5d62e22017-04-02 23:53:04 -0700812 // Force an input frame rate to be available, or the adaptation call won't
813 // know what framerate to adapt form.
814 VideoSendStream::Stats stats = stats_proxy_->GetStats();
815 stats.input_frame_rate = 30;
816 stats_proxy_->SetMockStats(stats);
817
818 vie_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700819 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700820 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
821 sink_.WaitForEncodedFrame(frame_timestamp);
822 frame_timestamp += kFrameIntervalMs;
823
824 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -0800825 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700826 EXPECT_EQ(std::numeric_limits<int>::max(),
827 new_video_source.sink_wants().max_pixel_count);
828 EXPECT_TRUE(new_video_source.sink_wants().max_framerate_fps);
829
830 // Turn of degradation completely.
831 vie_encoder_->SetSource(
832 &new_video_source,
833 VideoSendStream::DegradationPreference::kDegradationDisabled);
834
835 // Initially no degradation registered.
836 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
837 EXPECT_EQ(std::numeric_limits<int>::max(),
838 new_video_source.sink_wants().max_pixel_count);
839 EXPECT_EQ(std::numeric_limits<int>::max(),
840 new_video_source.sink_wants().max_framerate_fps);
841
842 vie_encoder_->TriggerCpuOveruse();
843 new_video_source.IncomingCapturedFrame(
844 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
845 sink_.WaitForEncodedFrame(frame_timestamp);
846 frame_timestamp += kFrameIntervalMs;
847
848 // Still no degradation.
849 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
850 EXPECT_EQ(std::numeric_limits<int>::max(),
851 new_video_source.sink_wants().max_pixel_count);
852 EXPECT_EQ(std::numeric_limits<int>::max(),
853 new_video_source.sink_wants().max_framerate_fps);
perkj803d97f2016-11-01 11:45:46 -0700854
855 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
sprangc5d62e22017-04-02 23:53:04 -0700856 vie_encoder_->SetSource(
857 &new_video_source,
858 VideoSendStream::DegradationPreference::kMaintainFramerate);
859 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
860 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -0800861 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700862 EXPECT_EQ(std::numeric_limits<int>::max(),
863 new_video_source.sink_wants().max_framerate_fps);
864
865 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
866 vie_encoder_->SetSource(
867 &new_video_source,
868 VideoSendStream::DegradationPreference::kMaintainResolution);
869 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
870 EXPECT_EQ(std::numeric_limits<int>::max(),
871 new_video_source.sink_wants().max_pixel_count);
872 EXPECT_TRUE(new_video_source.sink_wants().max_framerate_fps);
perkj803d97f2016-11-01 11:45:46 -0700873
874 vie_encoder_->Stop();
875}
876
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;
sprangc5d62e22017-04-02 23:53:04 -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,
sprangc5d62e22017-04-02 23:53:04 -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.
sprangc5d62e22017-04-02 23:53:04 -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
asapersson36e9eb42017-03-31 05:29:12 -07001045TEST_F(ViEEncoderTest, QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1046 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1047
1048 const int kWidth = 1280;
1049 const int kHeight = 720;
1050 video_source_.set_adaptation_enabled(true);
1051 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1052 sink_.WaitForEncodedFrame(1);
1053 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1054 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1055 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1056
1057 // Trigger adapt down.
1058 vie_encoder_->TriggerQualityLow();
1059 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1060 sink_.WaitForEncodedFrame(2);
1061 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1062 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1063 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1064
1065 // Trigger overuse.
1066 vie_encoder_->TriggerCpuOveruse();
1067 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1068 sink_.WaitForEncodedFrame(3);
1069 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1070 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1071 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1072
1073 // Set source with adaptation still enabled but quality scaler is off.
1074 fake_encoder_.SetQualityScaling(false);
sprangc5d62e22017-04-02 23:53:04 -07001075 vie_encoder_->SetSource(
1076 &video_source_,
1077 VideoSendStream::DegradationPreference::kMaintainFramerate);
asapersson36e9eb42017-03-31 05:29:12 -07001078
1079 video_source_.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
1080 sink_.WaitForEncodedFrame(4);
1081 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1082 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1083 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1084
1085 vie_encoder_->Stop();
1086}
1087
perkj803d97f2016-11-01 11:45:46 -07001088TEST_F(ViEEncoderTest, StatsTracksAdaptationStatsWhenSwitchingSource) {
perkj803d97f2016-11-01 11:45:46 -07001089 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1090
perkj803d97f2016-11-01 11:45:46 -07001091 int frame_width = 1280;
1092 int frame_height = 720;
sprang84a37592017-02-10 07:04:27 -08001093 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001094
1095 video_source_.IncomingCapturedFrame(
sprang84a37592017-02-10 07:04:27 -08001096 CreateFrame(sequence, frame_width, frame_height));
1097 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001098
1099 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001100 EXPECT_FALSE(stats.cpu_limited_resolution);
1101 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1102
1103 // Trigger CPU overuse again, should now adapt down.
1104 vie_encoder_->TriggerCpuOveruse();
1105 video_source_.IncomingCapturedFrame(
1106 CreateFrame(sequence, frame_width, frame_height));
1107 sink_.WaitForEncodedFrame(sequence++);
1108
1109 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001110 EXPECT_TRUE(stats.cpu_limited_resolution);
1111 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1112
1113 // Set new source with adaptation still enabled.
1114 test::FrameForwarder new_video_source;
sprangc5d62e22017-04-02 23:53:04 -07001115 vie_encoder_->SetSource(
1116 &new_video_source,
1117 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001118
1119 new_video_source.IncomingCapturedFrame(
sprang84a37592017-02-10 07:04:27 -08001120 CreateFrame(sequence, frame_width, frame_height));
1121 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001122 stats = stats_proxy_->GetStats();
1123 EXPECT_TRUE(stats.cpu_limited_resolution);
1124 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1125
sprangc5d62e22017-04-02 23:53:04 -07001126 // Set cpu adaptation by frame dropping.
perkj803d97f2016-11-01 11:45:46 -07001127 vie_encoder_->SetSource(
1128 &new_video_source,
1129 VideoSendStream::DegradationPreference::kMaintainResolution);
1130 new_video_source.IncomingCapturedFrame(
sprang84a37592017-02-10 07:04:27 -08001131 CreateFrame(sequence, frame_width, frame_height));
1132 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001133 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001134 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001135 EXPECT_FALSE(stats.cpu_limited_resolution);
1136 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1137
sprangc5d62e22017-04-02 23:53:04 -07001138 // Force an input frame rate to be available, or the adaptation call won't
1139 // know what framerate to adapt form.
1140 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1141 mock_stats.input_frame_rate = 30;
1142 stats_proxy_->SetMockStats(mock_stats);
1143 vie_encoder_->TriggerCpuOveruse();
1144 stats_proxy_->ResetMockStats();
1145
1146 new_video_source.IncomingCapturedFrame(
1147 CreateFrame(sequence, frame_width, frame_height));
1148 sink_.WaitForEncodedFrame(sequence++);
1149
1150 // Framerate now adapted.
1151 stats = stats_proxy_->GetStats();
1152 EXPECT_TRUE(stats.cpu_limited_resolution);
1153 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1154
1155 // Disable CPU adaptation.
1156 vie_encoder_->SetSource(
1157 &new_video_source,
1158 VideoSendStream::DegradationPreference::kDegradationDisabled);
1159 new_video_source.IncomingCapturedFrame(
1160 CreateFrame(sequence, frame_width, frame_height));
1161 sink_.WaitForEncodedFrame(sequence++);
1162
1163 stats = stats_proxy_->GetStats();
1164 EXPECT_FALSE(stats.cpu_limited_resolution);
1165 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1166
1167 // Try to trigger overuse. Should not succeed.
1168 stats_proxy_->SetMockStats(mock_stats);
1169 vie_encoder_->TriggerCpuOveruse();
1170 stats_proxy_->ResetMockStats();
1171
1172 stats = stats_proxy_->GetStats();
1173 EXPECT_FALSE(stats.cpu_limited_resolution);
1174 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1175
1176 // Switch back the source with resolution adaptation enabled.
1177 vie_encoder_->SetSource(
1178 &video_source_,
1179 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001180 video_source_.IncomingCapturedFrame(
sprang84a37592017-02-10 07:04:27 -08001181 CreateFrame(sequence, frame_width, frame_height));
1182 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001183 stats = stats_proxy_->GetStats();
1184 EXPECT_TRUE(stats.cpu_limited_resolution);
sprangc5d62e22017-04-02 23:53:04 -07001185 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001186
1187 // Trigger CPU normal usage.
1188 vie_encoder_->TriggerCpuNormalUsage();
1189 video_source_.IncomingCapturedFrame(
sprang84a37592017-02-10 07:04:27 -08001190 CreateFrame(sequence, frame_width, frame_height));
1191 sink_.WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001192 stats = stats_proxy_->GetStats();
1193 EXPECT_FALSE(stats.cpu_limited_resolution);
sprangc5d62e22017-04-02 23:53:04 -07001194 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1195
1196 // Back to the source with adaptation off, set it back to maintain-resolution.
1197 vie_encoder_->SetSource(
1198 &new_video_source,
1199 VideoSendStream::DegradationPreference::kMaintainResolution);
1200 new_video_source.IncomingCapturedFrame(
1201 CreateFrame(sequence, frame_width, frame_height));
1202 sink_.WaitForEncodedFrame(sequence++);
1203 stats = stats_proxy_->GetStats();
1204 // Disabled, since we previously switched the source too disabled.
1205 EXPECT_FALSE(stats.cpu_limited_resolution);
1206 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1207
1208 // Trigger CPU normal usage.
1209 vie_encoder_->TriggerCpuNormalUsage();
1210 new_video_source.IncomingCapturedFrame(
1211 CreateFrame(sequence, frame_width, frame_height));
1212 sink_.WaitForEncodedFrame(sequence++);
1213 stats = stats_proxy_->GetStats();
1214 EXPECT_FALSE(stats.cpu_limited_resolution);
1215 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001216
1217 vie_encoder_->Stop();
1218}
1219
Erik Språng08127a92016-11-16 16:41:30 +01001220TEST_F(ViEEncoderTest, StatsTracksPreferredBitrate) {
Erik Språng08127a92016-11-16 16:41:30 +01001221 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1222
1223 video_source_.IncomingCapturedFrame(CreateFrame(1, 1280, 720));
1224 sink_.WaitForEncodedFrame(1);
1225
1226 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1227 EXPECT_EQ(video_encoder_config_.max_bitrate_bps,
1228 stats.preferred_media_bitrate_bps);
1229
1230 vie_encoder_->Stop();
1231}
1232
kthelgason876222f2016-11-29 01:44:11 -08001233TEST_F(ViEEncoderTest, ScalingUpAndDownDoesNothingWithMaintainResolution) {
kthelgason876222f2016-11-29 01:44:11 -08001234 int frame_width = 1280;
1235 int frame_height = 720;
1236 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1237
1238 // Expect no scaling to begin with
sprang84a37592017-02-10 07:04:27 -08001239 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001240 EXPECT_EQ(std::numeric_limits<int>::max(),
1241 video_source_.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001242
kthelgason876222f2016-11-29 01:44:11 -08001243 video_source_.IncomingCapturedFrame(
1244 CreateFrame(1, frame_width, frame_height));
1245 sink_.WaitForEncodedFrame(1);
1246
kthelgason5e13d412016-12-01 03:59:51 -08001247 // Trigger scale down
1248 vie_encoder_->TriggerQualityLow();
1249
1250 video_source_.IncomingCapturedFrame(
1251 CreateFrame(2, frame_width, frame_height));
1252 sink_.WaitForEncodedFrame(2);
1253
kthelgason876222f2016-11-29 01:44:11 -08001254 // Expect a scale down.
1255 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001256 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
kthelgason876222f2016-11-29 01:44:11 -08001257 frame_width * frame_height);
1258
1259 // Set adaptation disabled.
1260 test::FrameForwarder new_video_source;
1261 vie_encoder_->SetSource(
1262 &new_video_source,
1263 VideoSendStream::DegradationPreference::kMaintainResolution);
1264
1265 // Trigger scale down
1266 vie_encoder_->TriggerQualityLow();
1267 new_video_source.IncomingCapturedFrame(
kthelgason5e13d412016-12-01 03:59:51 -08001268 CreateFrame(3, frame_width, frame_height));
1269 sink_.WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001270
1271 // Expect no scaling
sprangc5d62e22017-04-02 23:53:04 -07001272 EXPECT_EQ(std::numeric_limits<int>::max(),
1273 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001274
1275 // Trigger scale up
1276 vie_encoder_->TriggerQualityHigh();
1277 new_video_source.IncomingCapturedFrame(
kthelgason5e13d412016-12-01 03:59:51 -08001278 CreateFrame(4, frame_width, frame_height));
1279 sink_.WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001280
1281 // Expect nothing to change, still no scaling
sprangc5d62e22017-04-02 23:53:04 -07001282 EXPECT_EQ(std::numeric_limits<int>::max(),
1283 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001284
1285 vie_encoder_->Stop();
1286}
1287
kthelgason5e13d412016-12-01 03:59:51 -08001288TEST_F(ViEEncoderTest, DoesNotScaleBelowSetLimit) {
kthelgason5e13d412016-12-01 03:59:51 -08001289 int frame_width = 1280;
1290 int frame_height = 720;
kthelgason5e13d412016-12-01 03:59:51 -08001291 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1292
1293 for (size_t i = 1; i <= 10; i++) {
1294 video_source_.IncomingCapturedFrame(
1295 CreateFrame(i, frame_width, frame_height));
1296 sink_.WaitForEncodedFrame(i);
1297 // Trigger scale down
1298 vie_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001299 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
kthelgason5e13d412016-12-01 03:59:51 -08001300 }
1301
1302 vie_encoder_->Stop();
1303}
1304
perkj803d97f2016-11-01 11:45:46 -07001305TEST_F(ViEEncoderTest, UMACpuLimitedResolutionInPercent) {
perkj803d97f2016-11-01 11:45:46 -07001306 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1307
1308 int frame_width = 640;
1309 int frame_height = 360;
1310
1311 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
1312 video_source_.IncomingCapturedFrame(
1313 CreateFrame(i, frame_width, frame_height));
1314 sink_.WaitForEncodedFrame(i);
1315 }
1316
1317 vie_encoder_->TriggerCpuOveruse();
1318 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
1319 video_source_.IncomingCapturedFrame(
1320 CreateFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i,
1321 frame_width, frame_height));
1322 sink_.WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples +
1323 i);
1324 }
1325
1326 vie_encoder_->Stop();
sprangf8ee65e2017-02-28 08:49:33 -08001327 vie_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07001328 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08001329
perkj803d97f2016-11-01 11:45:46 -07001330 EXPECT_EQ(1,
1331 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
1332 EXPECT_EQ(
1333 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
1334}
1335
sprang57c2fff2017-01-16 06:24:02 -08001336TEST_F(ViEEncoderTest, CallsBitrateObserver) {
1337 class MockBitrateObserver : public VideoBitrateAllocationObserver {
1338 public:
1339 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const BitrateAllocation&));
1340 } bitrate_observer;
1341 vie_encoder_->SetBitrateObserver(&bitrate_observer);
1342
1343 const int kDefaultFps = 30;
1344 const BitrateAllocation expected_bitrate =
1345 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08001346 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08001347
1348 // First called on bitrate updated, then again on first frame.
1349 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
1350 .Times(2);
kthelgason2bc68642017-02-07 07:02:22 -08001351 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08001352
1353 const int64_t kStartTimeMs = 1;
1354 video_source_.IncomingCapturedFrame(
1355 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
1356 sink_.WaitForEncodedFrame(kStartTimeMs);
1357
1358 // Not called on second frame.
1359 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
1360 .Times(0);
1361 video_source_.IncomingCapturedFrame(
1362 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
1363 sink_.WaitForEncodedFrame(kStartTimeMs + 1);
1364
1365 // Called after a process interval.
1366 const int64_t kProcessIntervalMs =
1367 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
1368 // TODO(sprang): ViEEncoder should die and/or get injectable clock.
1369 // Sleep for one processing interval plus one frame to avoid flakiness.
1370 SleepMs(kProcessIntervalMs + 1000 / kDefaultFps);
1371 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
1372 .Times(1);
1373 video_source_.IncomingCapturedFrame(CreateFrame(
1374 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
1375 sink_.WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
1376
1377 vie_encoder_->Stop();
1378}
1379
kthelgason2bc68642017-02-07 07:02:22 -08001380TEST_F(ViEEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
1381 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
1382 int frame_width = 640;
1383 int frame_height = 360;
1384
1385 video_source_.IncomingCapturedFrame(
1386 CreateFrame(1, frame_width, frame_height));
1387
1388 // Expect to drop this frame, the wait should time out.
1389 sink_.ExpectDroppedFrame();
1390
1391 // Expect the sink_wants to specify a scaled frame.
sprangc5d62e22017-04-02 23:53:04 -07001392 EXPECT_LT(video_source_.sink_wants().max_pixel_count, 1000 * 1000);
kthelgason2bc68642017-02-07 07:02:22 -08001393
sprangc5d62e22017-04-02 23:53:04 -07001394 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08001395
1396 // Next frame is scaled
1397 video_source_.IncomingCapturedFrame(
1398 CreateFrame(2, frame_width * 3 / 4, frame_height * 3 / 4));
1399
1400 // Expect to drop this frame, the wait should time out.
1401 sink_.ExpectDroppedFrame();
1402
sprangc5d62e22017-04-02 23:53:04 -07001403 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08001404
1405 vie_encoder_->Stop();
1406}
1407
kthelgason2fc52542017-03-03 00:24:41 -08001408TEST_F(ViEEncoderTest, NrOfDroppedFramesLimited) {
kthelgason2bc68642017-02-07 07:02:22 -08001409 // 1kbps. This can never be achieved.
1410 vie_encoder_->OnBitrateUpdated(1000, 0, 0);
1411 int frame_width = 640;
1412 int frame_height = 360;
1413
1414 // We expect the n initial frames to get dropped.
1415 int i;
1416 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
1417 video_source_.IncomingCapturedFrame(
1418 CreateFrame(i, frame_width, frame_height));
1419 sink_.ExpectDroppedFrame();
1420 }
1421 // The n+1th frame should not be dropped, even though it's size is too large.
1422 video_source_.IncomingCapturedFrame(
1423 CreateFrame(i, frame_width, frame_height));
1424 sink_.WaitForEncodedFrame(i);
1425
1426 // Expect the sink_wants to specify a scaled frame.
sprangc5d62e22017-04-02 23:53:04 -07001427 EXPECT_LT(video_source_.sink_wants().max_pixel_count, 1000 * 1000);
kthelgason2bc68642017-02-07 07:02:22 -08001428
1429 vie_encoder_->Stop();
1430}
1431
1432TEST_F(ViEEncoderTest, InitialFrameDropOffWithMaintainResolutionPreference) {
1433 int frame_width = 640;
1434 int frame_height = 360;
1435 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
1436
1437 // Set degradation preference.
1438 vie_encoder_->SetSource(
1439 &video_source_,
1440 VideoSendStream::DegradationPreference::kMaintainResolution);
1441
1442 video_source_.IncomingCapturedFrame(
1443 CreateFrame(1, frame_width, frame_height));
1444 // Frame should not be dropped, even if it's too large.
1445 sink_.WaitForEncodedFrame(1);
1446
1447 vie_encoder_->Stop();
1448}
1449
kthelgason2fc52542017-03-03 00:24:41 -08001450TEST_F(ViEEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
kthelgasonad9010c2017-02-14 00:46:51 -08001451 int frame_width = 640;
1452 int frame_height = 360;
1453 fake_encoder_.SetQualityScaling(false);
1454 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgasonb83797b2017-02-14 11:57:25 -08001455 // Force quality scaler reconfiguration by resetting the source.
1456 vie_encoder_->SetSource(&video_source_,
1457 VideoSendStream::DegradationPreference::kBalanced);
kthelgasonad9010c2017-02-14 00:46:51 -08001458
1459 video_source_.IncomingCapturedFrame(
1460 CreateFrame(1, frame_width, frame_height));
1461 // Frame should not be dropped, even if it's too large.
1462 sink_.WaitForEncodedFrame(1);
1463
1464 vie_encoder_->Stop();
1465 fake_encoder_.SetQualityScaling(true);
1466}
1467
sprangb1ca0732017-02-01 08:38:12 -08001468// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
1469TEST_F(ViEEncoderTest, AdaptsResolutionOnOveruse) {
1470 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1471
1472 const int kFrameWidth = 1280;
1473 const int kFrameHeight = 720;
1474 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
1475 // requested by ViEEncoder::VideoSourceProxy::RequestResolutionLowerThan().
1476 video_source_.set_adaptation_enabled(true);
1477
1478 video_source_.IncomingCapturedFrame(
1479 CreateFrame(1, kFrameWidth, kFrameHeight));
1480 sink_.WaitForEncodedFrame(kFrameWidth, kFrameHeight);
1481
1482 // Trigger CPU overuse, downscale by 3/4.
1483 vie_encoder_->TriggerCpuOveruse();
1484 video_source_.IncomingCapturedFrame(
1485 CreateFrame(2, kFrameWidth, kFrameHeight));
1486 sink_.WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
1487
sprangc5d62e22017-04-02 23:53:04 -07001488 // Trigger CPU normal use, return to original resolution;
sprangb1ca0732017-02-01 08:38:12 -08001489 vie_encoder_->TriggerCpuNormalUsage();
1490 video_source_.IncomingCapturedFrame(
1491 CreateFrame(3, kFrameWidth, kFrameHeight));
1492 sink_.WaitForEncodedFrame(kFrameWidth, kFrameHeight);
1493
1494 vie_encoder_->Stop();
1495}
sprangfe627f32017-03-29 08:24:59 -07001496
1497TEST_F(ViEEncoderTest, FailingInitEncodeDoesntCauseCrash) {
1498 fake_encoder_.ForceInitEncodeFailure(true);
1499 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1500 ResetEncoder("VP8", 2, 1, true);
1501 const int kFrameWidth = 1280;
1502 const int kFrameHeight = 720;
1503 video_source_.IncomingCapturedFrame(
1504 CreateFrame(1, kFrameWidth, kFrameHeight));
1505 sink_.ExpectDroppedFrame();
1506 vie_encoder_->Stop();
1507}
sprangc5d62e22017-04-02 23:53:04 -07001508
1509TEST_F(ViEEncoderTest, AdaptsFrameOnOveruseWithMaintainResolution) {
1510 const int kDefaultFramerateFps = 30;
1511 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kDefaultFramerateFps;
1512 const int kFrameWidth = 1280;
1513 const int kFrameHeight = 720;
1514 rtc::ScopedFakeClock fake_clock;
1515
1516 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1517 vie_encoder_->SetSource(
1518 &video_source_,
1519 VideoSendStream::DegradationPreference::kMaintainResolution);
1520 video_source_.set_adaptation_enabled(true);
1521
1522 fake_clock.SetTimeMicros(kFrameIntervalMs * 1000);
1523 int64_t timestamp_ms = kFrameIntervalMs;
1524
1525 video_source_.IncomingCapturedFrame(
1526 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1527 sink_.WaitForEncodedFrame(timestamp_ms);
1528
1529 // Try to trigger overuse. No fps estimate available => no effect.
1530 vie_encoder_->TriggerCpuOveruse();
1531
1532 // Insert frames for one second to get a stable estimate.
1533 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1534 timestamp_ms += kFrameIntervalMs;
1535 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1536 video_source_.IncomingCapturedFrame(
1537 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1538 sink_.WaitForEncodedFrame(timestamp_ms);
1539 }
1540
1541 // Trigger CPU overuse, reduce framerate by 2/3.
1542 vie_encoder_->TriggerCpuOveruse();
1543 int num_frames_dropped = 0;
1544 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1545 timestamp_ms += kFrameIntervalMs;
1546 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1547 video_source_.IncomingCapturedFrame(
1548 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1549 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
1550 ++num_frames_dropped;
1551 } else {
1552 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
1553 }
1554 }
1555
1556 // TODO(sprang): Find where there's rounding errors or stuff causing the
1557 // margin here to be a little larger than we'd like (input fps estimate is
1558 // off) and the frame dropping is a little too aggressive.
1559 const int kErrorMargin = 5;
1560 EXPECT_NEAR(num_frames_dropped,
1561 kDefaultFramerateFps - (kDefaultFramerateFps * 2 / 3),
1562 kErrorMargin);
1563
1564 // Trigger CPU overuse, reduce framerate by 2/3 again.
1565 vie_encoder_->TriggerCpuOveruse();
1566 num_frames_dropped = 0;
1567 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1568 timestamp_ms += kFrameIntervalMs;
1569 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1570 video_source_.IncomingCapturedFrame(
1571 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1572 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
1573 ++num_frames_dropped;
1574 } else {
1575 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
1576 }
1577 }
1578 EXPECT_NEAR(num_frames_dropped,
1579 kDefaultFramerateFps - (kDefaultFramerateFps * 4 / 9),
1580 kErrorMargin);
1581
1582 // Go back up one step.
1583 vie_encoder_->TriggerCpuNormalUsage();
1584 num_frames_dropped = 0;
1585 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1586 timestamp_ms += kFrameIntervalMs;
1587 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1588 video_source_.IncomingCapturedFrame(
1589 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1590 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
1591 ++num_frames_dropped;
1592 } else {
1593 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
1594 }
1595 }
1596 EXPECT_NEAR(num_frames_dropped,
1597 kDefaultFramerateFps - (kDefaultFramerateFps * 2 / 3),
1598 kErrorMargin);
1599
1600 // Go back up to original mode.
1601 vie_encoder_->TriggerCpuNormalUsage();
1602 num_frames_dropped = 0;
1603 for (int i = 0; i < kDefaultFramerateFps; ++i) {
1604 timestamp_ms += kFrameIntervalMs;
1605 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1606 video_source_.IncomingCapturedFrame(
1607 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1608 if (!sink_.WaitForFrame(kFrameTimeoutMs)) {
1609 ++num_frames_dropped;
1610 } else {
1611 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
1612 }
1613 }
1614 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
1615
1616 vie_encoder_->Stop();
1617}
1618
1619TEST_F(ViEEncoderTest, DoesntAdaptDownPastMinFramerate) {
1620 const int kFramerateFps = 5;
1621 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
1622 const int kMinFpsFrameInterval = rtc::kNumMillisecsPerSec / kMinFramerateFps;
1623 const int kFrameWidth = 1280;
1624 const int kFrameHeight = 720;
1625
1626 rtc::ScopedFakeClock fake_clock;
1627 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1628 vie_encoder_->SetSource(
1629 &video_source_,
1630 VideoSendStream::DegradationPreference::kMaintainResolution);
1631 video_source_.set_adaptation_enabled(true);
1632
1633 fake_clock.SetTimeMicros(kFrameIntervalMs * 1000);
1634 int64_t timestamp_ms = kFrameIntervalMs;
1635
1636 // Trigger overuse as much as we can.
1637 for (int i = 0; i < ViEEncoder::kMaxCpuResolutionDowngrades; ++i) {
1638 // Insert frames to get a new fps estimate...
1639 for (int j = 0; j < kFramerateFps; ++j) {
1640 video_source_.IncomingCapturedFrame(
1641 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1642 timestamp_ms += kFrameIntervalMs;
1643 fake_clock.AdvanceTimeMicros(kFrameIntervalMs * 1000);
1644 }
1645 // ...and then try to adapt again.
1646 vie_encoder_->TriggerCpuOveruse();
1647 }
1648
1649 // Drain any frame in the pipeline.
1650 sink_.WaitForFrame(kDefaultTimeoutMs);
1651
1652 // Insert frames at min fps, all should go through.
1653 for (int i = 0; i < 10; ++i) {
1654 timestamp_ms += kMinFpsFrameInterval;
1655 fake_clock.AdvanceTimeMicros(kMinFpsFrameInterval * 1000);
1656 video_source_.IncomingCapturedFrame(
1657 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
1658 sink_.WaitForEncodedFrame(timestamp_ms);
1659 }
1660 vie_encoder_->Stop();
1661}
perkj26091b12016-09-01 01:17:40 -07001662} // namespace webrtc