blob: 4d72a826f2241b22ff4d919877c2ef28bcbc0797 [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 {
kthelgason33ce8892016-12-09 03:53:59 -080032// TODO(kthelgason): Lower this limit when better testing
33// on MediaCodec and fallback implementations are in place.
34const int kMinPixelsPerFrame = 320 * 180;
sprangc5d62e22017-04-02 23:53:04 -070035const int kMinFramerateFps = 2;
36const int64_t kFrameTimeoutMs = 100;
37} // namespace
kthelgason33ce8892016-12-09 03:53:59 -080038
perkj26091b12016-09-01 01:17:40 -070039namespace webrtc {
40
kthelgason876222f2016-11-29 01:44:11 -080041using DegredationPreference = VideoSendStream::DegradationPreference;
sprangb1ca0732017-02-01 08:38:12 -080042using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080043using ::testing::_;
44using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080045
perkj803d97f2016-11-01 11:45:46 -070046namespace {
asapersson5f7226f2016-11-25 04:37:00 -080047const size_t kMaxPayloadLength = 1440;
kthelgason2bc68642017-02-07 07:02:22 -080048const int kTargetBitrateBps = 1000000;
49const int kLowTargetBitrateBps = kTargetBitrateBps / 10;
50const int kMaxInitialFramedrop = 4;
asapersson5f7226f2016-11-25 04:37:00 -080051
perkj803d97f2016-11-01 11:45:46 -070052class TestBuffer : public webrtc::I420Buffer {
53 public:
54 TestBuffer(rtc::Event* event, int width, int height)
55 : I420Buffer(width, height), event_(event) {}
56
57 private:
58 friend class rtc::RefCountedObject<TestBuffer>;
59 ~TestBuffer() override {
60 if (event_)
61 event_->Set();
62 }
63 rtc::Event* const event_;
64};
65
66class ViEEncoderUnderTest : public ViEEncoder {
67 public:
kthelgason876222f2016-11-29 01:44:11 -080068 ViEEncoderUnderTest(SendStatisticsProxy* stats_proxy,
69 const VideoSendStream::Config::EncoderSettings& settings)
perkj803d97f2016-11-01 11:45:46 -070070 : ViEEncoder(1 /* number_of_cores */,
71 stats_proxy,
72 settings,
73 nullptr /* pre_encode_callback */,
74 nullptr /* encoder_timing */) {}
75
sprangb1ca0732017-02-01 08:38:12 -080076 void PostTaskAndWait(bool down, AdaptReason reason) {
perkj803d97f2016-11-01 11:45:46 -070077 rtc::Event event(false, false);
kthelgason876222f2016-11-29 01:44:11 -080078 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -080079 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -070080 event.Set();
81 });
perkj070ba852017-02-16 15:46:27 -080082 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -070083 }
84
kthelgason2fc52542017-03-03 00:24:41 -080085 // This is used as a synchronisation mechanism, to make sure that the
86 // encoder queue is not blocked before we start sending it frames.
87 void WaitUntilTaskQueueIsIdle() {
88 rtc::Event event(false, false);
89 encoder_queue()->PostTask([&event] {
90 event.Set();
91 });
92 ASSERT_TRUE(event.Wait(5000));
93 }
94
sprangb1ca0732017-02-01 08:38:12 -080095 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -080096
sprangb1ca0732017-02-01 08:38:12 -080097 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -080098
sprangb1ca0732017-02-01 08:38:12 -080099 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800100
sprangb1ca0732017-02-01 08:38:12 -0800101 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
perkj803d97f2016-11-01 11:45:46 -0700102};
103
asapersson5f7226f2016-11-25 04:37:00 -0800104class VideoStreamFactory
105 : public VideoEncoderConfig::VideoStreamFactoryInterface {
106 public:
107 explicit VideoStreamFactory(size_t num_temporal_layers)
108 : num_temporal_layers_(num_temporal_layers) {
109 EXPECT_GT(num_temporal_layers, 0u);
110 }
111
112 private:
113 std::vector<VideoStream> CreateEncoderStreams(
114 int width,
115 int height,
116 const VideoEncoderConfig& encoder_config) override {
117 std::vector<VideoStream> streams =
118 test::CreateVideoStreams(width, height, encoder_config);
119 for (VideoStream& stream : streams) {
120 stream.temporal_layer_thresholds_bps.resize(num_temporal_layers_ - 1);
121 }
122 return streams;
123 }
124 const size_t num_temporal_layers_;
125};
126
sprangb1ca0732017-02-01 08:38:12 -0800127class AdaptingFrameForwarder : public test::FrameForwarder {
128 public:
129 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700130 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800131
132 void set_adaptation_enabled(bool enabled) {
133 rtc::CritScope cs(&crit_);
134 adaptation_enabled_ = enabled;
135 }
136
asaperssonfab67072017-04-04 05:51:49 -0700137 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800138 rtc::CritScope cs(&crit_);
139 return adaptation_enabled_;
140 }
141
asapersson09f05612017-05-15 23:40:18 -0700142 rtc::VideoSinkWants last_wants() const {
143 rtc::CritScope cs(&crit_);
144 return last_wants_;
145 }
146
sprangb1ca0732017-02-01 08:38:12 -0800147 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
148 int cropped_width = 0;
149 int cropped_height = 0;
150 int out_width = 0;
151 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700152 if (adaption_enabled()) {
153 if (adapter_.AdaptFrameResolution(
154 video_frame.width(), video_frame.height(),
155 video_frame.timestamp_us() * 1000, &cropped_width,
156 &cropped_height, &out_width, &out_height)) {
157 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
158 nullptr, out_width, out_height),
159 99, 99, kVideoRotation_0);
160 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
161 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
162 }
sprangb1ca0732017-02-01 08:38:12 -0800163 } else {
164 test::FrameForwarder::IncomingCapturedFrame(video_frame);
165 }
166 }
167
168 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
169 const rtc::VideoSinkWants& wants) override {
170 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700171 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700172 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
173 wants.max_pixel_count,
174 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800175 test::FrameForwarder::AddOrUpdateSink(sink, wants);
176 }
sprangb1ca0732017-02-01 08:38:12 -0800177 cricket::VideoAdapter adapter_;
178 bool adaptation_enabled_ GUARDED_BY(crit_);
asapersson09f05612017-05-15 23:40:18 -0700179 rtc::VideoSinkWants last_wants_ GUARDED_BY(crit_);
sprangb1ca0732017-02-01 08:38:12 -0800180};
sprangc5d62e22017-04-02 23:53:04 -0700181
182class MockableSendStatisticsProxy : public SendStatisticsProxy {
183 public:
184 MockableSendStatisticsProxy(Clock* clock,
185 const VideoSendStream::Config& config,
186 VideoEncoderConfig::ContentType content_type)
187 : SendStatisticsProxy(clock, config, content_type) {}
188
189 VideoSendStream::Stats GetStats() override {
190 rtc::CritScope cs(&lock_);
191 if (mock_stats_)
192 return *mock_stats_;
193 return SendStatisticsProxy::GetStats();
194 }
195
196 void SetMockStats(const VideoSendStream::Stats& stats) {
197 rtc::CritScope cs(&lock_);
198 mock_stats_.emplace(stats);
199 }
200
201 void ResetMockStats() {
202 rtc::CritScope cs(&lock_);
203 mock_stats_.reset();
204 }
205
206 private:
207 rtc::CriticalSection lock_;
208 rtc::Optional<VideoSendStream::Stats> mock_stats_ GUARDED_BY(lock_);
209};
210
perkj803d97f2016-11-01 11:45:46 -0700211} // namespace
212
perkj26091b12016-09-01 01:17:40 -0700213class ViEEncoderTest : public ::testing::Test {
214 public:
215 static const int kDefaultTimeoutMs = 30 * 1000;
216
217 ViEEncoderTest()
218 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700219 codec_width_(320),
220 codec_height_(240),
sprangcdafeda2017-06-08 06:12:05 -0700221 max_framerate_(30),
perkj26091b12016-09-01 01:17:40 -0700222 fake_encoder_(),
sprangc5d62e22017-04-02 23:53:04 -0700223 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700224 Clock::GetRealTimeClock(),
225 video_send_config_,
226 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700227 sink_(&fake_encoder_) {}
228
229 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700230 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700231 video_send_config_ = VideoSendStream::Config(nullptr);
232 video_send_config_.encoder_settings.encoder = &fake_encoder_;
233 video_send_config_.encoder_settings.payload_name = "FAKE";
234 video_send_config_.encoder_settings.payload_type = 125;
235
Per512ecb32016-09-23 15:52:06 +0200236 VideoEncoderConfig video_encoder_config;
perkjfa10b552016-10-02 23:45:26 -0700237 test::FillEncoderConfiguration(1, &video_encoder_config);
sprangcdafeda2017-06-08 06:12:05 -0700238 video_encoder_config.video_stream_factory =
239 new rtc::RefCountedObject<VideoStreamFactory>(1);
Erik Språng08127a92016-11-16 16:41:30 +0100240 video_encoder_config_ = video_encoder_config.Copy();
sprangcdafeda2017-06-08 06:12:05 -0700241
242 // Framerate limit is specified by the VideoStreamFactory.
243 std::vector<VideoStream> streams =
244 video_encoder_config.video_stream_factory->CreateEncoderStreams(
245 codec_width_, codec_height_, video_encoder_config);
246 max_framerate_ = streams[0].max_framerate;
247 fake_clock_.SetTimeMicros(1234);
248
asapersson5f7226f2016-11-25 04:37:00 -0800249 ConfigureEncoder(std::move(video_encoder_config), true /* nack_enabled */);
250 }
251
252 void ConfigureEncoder(VideoEncoderConfig video_encoder_config,
253 bool nack_enabled) {
254 if (vie_encoder_)
255 vie_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700256 vie_encoder_.reset(new ViEEncoderUnderTest(
257 stats_proxy_.get(), video_send_config_.encoder_settings));
258 vie_encoder_->SetSink(&sink_, false /* rotation_applied */);
sprangc5d62e22017-04-02 23:53:04 -0700259 vie_encoder_->SetSource(
260 &video_source_,
261 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason2bc68642017-02-07 07:02:22 -0800262 vie_encoder_->SetStartBitrate(kTargetBitrateBps);
asapersson5f7226f2016-11-25 04:37:00 -0800263 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
264 kMaxPayloadLength, nack_enabled);
kthelgason2fc52542017-03-03 00:24:41 -0800265 vie_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800266 }
267
268 void ResetEncoder(const std::string& payload_name,
269 size_t num_streams,
270 size_t num_temporal_layers,
sprangcdafeda2017-06-08 06:12:05 -0700271 bool nack_enabled,
272 bool screenshare) {
asapersson5f7226f2016-11-25 04:37:00 -0800273 video_send_config_.encoder_settings.payload_name = payload_name;
274
275 VideoEncoderConfig video_encoder_config;
276 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800277 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800278 video_encoder_config.video_stream_factory =
279 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers);
sprangcdafeda2017-06-08 06:12:05 -0700280 video_encoder_config.content_type =
281 screenshare ? VideoEncoderConfig::ContentType::kScreen
282 : VideoEncoderConfig::ContentType::kRealtimeVideo;
asapersson5f7226f2016-11-25 04:37:00 -0800283 ConfigureEncoder(std::move(video_encoder_config), nack_enabled);
perkj26091b12016-09-01 01:17:40 -0700284 }
285
sprang57c2fff2017-01-16 06:24:02 -0800286 VideoFrame CreateFrame(int64_t ntp_time_ms,
287 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200288 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
289 destruction_event, codec_width_, codec_height_),
290 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800291 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700292 return frame;
293 }
294
sprang57c2fff2017-01-16 06:24:02 -0800295 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700296 VideoFrame frame(
297 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
298 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800299 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700300 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700301 return frame;
302 }
303
asapersson02465b82017-04-10 01:12:52 -0700304 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700305 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700306 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
307 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700308 }
309
asapersson09f05612017-05-15 23:40:18 -0700310 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
311 const rtc::VideoSinkWants& wants2) {
312 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
313 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
314 }
315
316 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
317 const rtc::VideoSinkWants& wants2) {
318 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
319 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
320 EXPECT_GT(wants1.max_pixel_count, 0);
321 }
322
323 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
324 const rtc::VideoSinkWants& wants2) {
325 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
326 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
327 }
328
329 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
330 int pixel_count) {
331 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700332 EXPECT_LT(wants.max_pixel_count, pixel_count);
333 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700334 }
335
336 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
337 EXPECT_LT(wants.max_framerate_fps, fps);
338 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
339 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700340 }
341
sprangcdafeda2017-06-08 06:12:05 -0700342 void WaitForEncodedFrame(int64_t expected_ntp_time) {
343 sink_.WaitForEncodedFrame(expected_ntp_time);
344 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
345 }
346
347 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
348 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
349 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
350 return ok;
351 }
352
353 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
354 sink_.WaitForEncodedFrame(expected_width, expected_height);
355 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
356 }
357
358 void ExpectDroppedFrame() {
359 sink_.ExpectDroppedFrame();
360 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
361 }
362
363 bool WaitForFrame(int64_t timeout_ms) {
364 bool ok = sink_.WaitForFrame(timeout_ms);
365 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
366 return ok;
367 }
368
perkj26091b12016-09-01 01:17:40 -0700369 class TestEncoder : public test::FakeEncoder {
370 public:
371 TestEncoder()
372 : FakeEncoder(Clock::GetRealTimeClock()),
373 continue_encode_event_(false, false) {}
374
asaperssonfab67072017-04-04 05:51:49 -0700375 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800376 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700377 return config_;
378 }
379
380 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800381 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700382 block_next_encode_ = true;
383 }
384
kthelgason876222f2016-11-29 01:44:11 -0800385 VideoEncoder::ScalingSettings GetScalingSettings() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800386 rtc::CritScope lock(&local_crit_sect_);
kthelgasonad9010c2017-02-14 00:46:51 -0800387 if (quality_scaling_)
388 return VideoEncoder::ScalingSettings(true, 1, 2);
389 return VideoEncoder::ScalingSettings(false);
kthelgason876222f2016-11-29 01:44:11 -0800390 }
391
perkjfa10b552016-10-02 23:45:26 -0700392 void ContinueEncode() { continue_encode_event_.Set(); }
393
394 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
395 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800396 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700397 EXPECT_EQ(timestamp_, timestamp);
398 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
399 }
400
kthelgason2fc52542017-03-03 00:24:41 -0800401 void SetQualityScaling(bool b) {
402 rtc::CritScope lock(&local_crit_sect_);
403 quality_scaling_ = b;
404 }
kthelgasonad9010c2017-02-14 00:46:51 -0800405
sprangfe627f32017-03-29 08:24:59 -0700406 void ForceInitEncodeFailure(bool force_failure) {
407 rtc::CritScope lock(&local_crit_sect_);
408 force_init_encode_failed_ = force_failure;
409 }
410
perkjfa10b552016-10-02 23:45:26 -0700411 private:
perkj26091b12016-09-01 01:17:40 -0700412 int32_t Encode(const VideoFrame& input_image,
413 const CodecSpecificInfo* codec_specific_info,
414 const std::vector<FrameType>* frame_types) override {
415 bool block_encode;
416 {
brandtre78d2662017-01-16 05:57:16 -0800417 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700418 EXPECT_GT(input_image.timestamp(), timestamp_);
419 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
420 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
421
422 timestamp_ = input_image.timestamp();
423 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700424 last_input_width_ = input_image.width();
425 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700426 block_encode = block_next_encode_;
427 block_next_encode_ = false;
428 }
429 int32_t result =
430 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
431 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700432 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700433 return result;
434 }
435
sprangfe627f32017-03-29 08:24:59 -0700436 int32_t InitEncode(const VideoCodec* config,
437 int32_t number_of_cores,
438 size_t max_payload_size) override {
439 int res =
440 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
441 rtc::CritScope lock(&local_crit_sect_);
442 if (config->codecType == kVideoCodecVP8 && config->VP8().tl_factory) {
443 // Simulate setting up temporal layers, in order to validate the life
444 // cycle of these objects.
445 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
446 int num_temporal_layers =
447 std::max<int>(1, config->VP8().numberOfTemporalLayers);
448 for (int i = 0; i < num_streams; ++i) {
449 allocated_temporal_layers_.emplace_back(
450 config->VP8().tl_factory->Create(i, num_temporal_layers, 42));
451 }
452 }
453 if (force_init_encode_failed_)
454 return -1;
455 return res;
456 }
457
brandtre78d2662017-01-16 05:57:16 -0800458 rtc::CriticalSection local_crit_sect_;
sprangfe627f32017-03-29 08:24:59 -0700459 bool block_next_encode_ GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700460 rtc::Event continue_encode_event_;
sprangfe627f32017-03-29 08:24:59 -0700461 uint32_t timestamp_ GUARDED_BY(local_crit_sect_) = 0;
462 int64_t ntp_time_ms_ GUARDED_BY(local_crit_sect_) = 0;
463 int last_input_width_ GUARDED_BY(local_crit_sect_) = 0;
464 int last_input_height_ GUARDED_BY(local_crit_sect_) = 0;
465 bool quality_scaling_ GUARDED_BY(local_crit_sect_) = true;
466 std::vector<std::unique_ptr<TemporalLayers>> allocated_temporal_layers_
467 GUARDED_BY(local_crit_sect_);
468 bool force_init_encode_failed_ GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700469 };
470
Per512ecb32016-09-23 15:52:06 +0200471 class TestSink : public ViEEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700472 public:
473 explicit TestSink(TestEncoder* test_encoder)
474 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
475
perkj26091b12016-09-01 01:17:40 -0700476 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprangcdafeda2017-06-08 06:12:05 -0700477 EXPECT_TRUE(
478 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
479 }
480
481 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
482 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700483 uint32_t timestamp = 0;
sprangcdafeda2017-06-08 06:12:05 -0700484 if (!encoded_frame_event_.Wait(timeout_ms))
485 return false;
perkj26091b12016-09-01 01:17:40 -0700486 {
487 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800488 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700489 }
490 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprangcdafeda2017-06-08 06:12:05 -0700491 return true;
perkj26091b12016-09-01 01:17:40 -0700492 }
493
sprangb1ca0732017-02-01 08:38:12 -0800494 void WaitForEncodedFrame(uint32_t expected_width,
495 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700496 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
497 CheckLastFrameSizeMathces(expected_width, expected_height);
498 }
499
500 void CheckLastFrameSizeMathces(uint32_t expected_width,
501 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800502 uint32_t width = 0;
503 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800504 {
505 rtc::CritScope lock(&crit_);
506 width = last_width_;
507 height = last_height_;
508 }
509 EXPECT_EQ(expected_height, height);
510 EXPECT_EQ(expected_width, width);
511 }
512
kthelgason2fc52542017-03-03 00:24:41 -0800513 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800514
sprangc5d62e22017-04-02 23:53:04 -0700515 bool WaitForFrame(int64_t timeout_ms) {
516 return encoded_frame_event_.Wait(timeout_ms);
517 }
518
perkj26091b12016-09-01 01:17:40 -0700519 void SetExpectNoFrames() {
520 rtc::CritScope lock(&crit_);
521 expect_frames_ = false;
522 }
523
asaperssonfab67072017-04-04 05:51:49 -0700524 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200525 rtc::CritScope lock(&crit_);
526 return number_of_reconfigurations_;
527 }
528
asaperssonfab67072017-04-04 05:51:49 -0700529 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200530 rtc::CritScope lock(&crit_);
531 return min_transmit_bitrate_bps_;
532 }
533
perkj26091b12016-09-01 01:17:40 -0700534 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700535 Result OnEncodedImage(
536 const EncodedImage& encoded_image,
537 const CodecSpecificInfo* codec_specific_info,
538 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200539 rtc::CritScope lock(&crit_);
540 EXPECT_TRUE(expect_frames_);
sprangb1ca0732017-02-01 08:38:12 -0800541 last_timestamp_ = encoded_image._timeStamp;
542 last_width_ = encoded_image._encodedWidth;
543 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200544 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800545 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200546 }
547
548 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
549 int min_transmit_bitrate_bps) override {
550 rtc::CriticalSection crit_;
551 ++number_of_reconfigurations_;
552 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
553 }
554
perkj26091b12016-09-01 01:17:40 -0700555 rtc::CriticalSection crit_;
556 TestEncoder* test_encoder_;
557 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800558 uint32_t last_timestamp_ = 0;
559 uint32_t last_height_ = 0;
560 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700561 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200562 int number_of_reconfigurations_ = 0;
563 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700564 };
565
566 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100567 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200568 int codec_width_;
569 int codec_height_;
sprangcdafeda2017-06-08 06:12:05 -0700570 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700571 TestEncoder fake_encoder_;
sprangc5d62e22017-04-02 23:53:04 -0700572 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700573 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800574 AdaptingFrameForwarder video_source_;
perkj803d97f2016-11-01 11:45:46 -0700575 std::unique_ptr<ViEEncoderUnderTest> vie_encoder_;
sprangcdafeda2017-06-08 06:12:05 -0700576 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700577};
578
579TEST_F(ViEEncoderTest, EncodeOneFrame) {
perkj26091b12016-09-01 01:17:40 -0700580 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
581 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700582 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprangcdafeda2017-06-08 06:12:05 -0700583 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700584 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700585 vie_encoder_->Stop();
586}
587
588TEST_F(ViEEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
589 // Dropped since no target bitrate has been set.
590 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700591 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
592 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700593
perkj26091b12016-09-01 01:17:40 -0700594 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
595
perkja49cbd32016-09-16 07:53:41 -0700596 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprangcdafeda2017-06-08 06:12:05 -0700597 WaitForEncodedFrame(2);
perkj26091b12016-09-01 01:17:40 -0700598 vie_encoder_->Stop();
599}
600
601TEST_F(ViEEncoderTest, DropsFramesWhenRateSetToZero) {
perkj26091b12016-09-01 01:17:40 -0700602 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700603 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprangcdafeda2017-06-08 06:12:05 -0700604 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700605
606 vie_encoder_->OnBitrateUpdated(0, 0, 0);
607 // Dropped since bitrate is zero.
perkja49cbd32016-09-16 07:53:41 -0700608 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkj26091b12016-09-01 01:17:40 -0700609
610 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700611 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
sprangcdafeda2017-06-08 06:12:05 -0700612 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700613 vie_encoder_->Stop();
614}
615
616TEST_F(ViEEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
perkj26091b12016-09-01 01:17:40 -0700617 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700618 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprangcdafeda2017-06-08 06:12:05 -0700619 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700620
621 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700622 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700623
perkja49cbd32016-09-16 07:53:41 -0700624 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprangcdafeda2017-06-08 06:12:05 -0700625 WaitForEncodedFrame(2);
perkj26091b12016-09-01 01:17:40 -0700626 vie_encoder_->Stop();
627}
628
629TEST_F(ViEEncoderTest, DropsFrameAfterStop) {
perkj26091b12016-09-01 01:17:40 -0700630 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
631
perkja49cbd32016-09-16 07:53:41 -0700632 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprangcdafeda2017-06-08 06:12:05 -0700633 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700634
635 vie_encoder_->Stop();
636 sink_.SetExpectNoFrames();
637 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700638 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
639 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700640}
641
642TEST_F(ViEEncoderTest, DropsPendingFramesOnSlowEncode) {
perkj26091b12016-09-01 01:17:40 -0700643 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
644
645 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700646 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprangcdafeda2017-06-08 06:12:05 -0700647 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700648 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
649 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700650 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
651 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700652 fake_encoder_.ContinueEncode();
sprangcdafeda2017-06-08 06:12:05 -0700653 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700654
655 vie_encoder_->Stop();
656}
657
Per512ecb32016-09-23 15:52:06 +0200658TEST_F(ViEEncoderTest, ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
Per512ecb32016-09-23 15:52:06 +0200659 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100660 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200661
662 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200663 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprangcdafeda2017-06-08 06:12:05 -0700664 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100665 // The encoder will have been configured once when the first frame is
666 // received.
667 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200668
669 VideoEncoderConfig video_encoder_config;
perkjfa10b552016-10-02 23:45:26 -0700670 test::FillEncoderConfiguration(1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200671 video_encoder_config.min_transmit_bitrate_bps = 9999;
asapersson5f7226f2016-11-25 04:37:00 -0800672 vie_encoder_->ConfigureEncoder(std::move(video_encoder_config),
673 kMaxPayloadLength, true /* nack_enabled */);
Per512ecb32016-09-23 15:52:06 +0200674
675 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200676 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprangcdafeda2017-06-08 06:12:05 -0700677 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100678 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700679 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700680
681 vie_encoder_->Stop();
682}
683
perkjfa10b552016-10-02 23:45:26 -0700684TEST_F(ViEEncoderTest, FrameResolutionChangeReconfigureEncoder) {
perkjfa10b552016-10-02 23:45:26 -0700685 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
686
687 // Capture a frame and wait for it to synchronize with the encoder thread.
688 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprangcdafeda2017-06-08 06:12:05 -0700689 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100690 // The encoder will have been configured once.
691 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700692 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
693 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
694
695 codec_width_ *= 2;
696 codec_height_ *= 2;
697 // Capture a frame with a higher resolution and wait for it to synchronize
698 // with the encoder thread.
699 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprangcdafeda2017-06-08 06:12:05 -0700700 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700701 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
702 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100703 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700704
705 vie_encoder_->Stop();
706}
707
asapersson5f7226f2016-11-25 04:37:00 -0800708TEST_F(ViEEncoderTest, Vp8ResilienceIsOffFor1S1TLWithNackEnabled) {
709 const bool kNackEnabled = true;
710 const size_t kNumStreams = 1;
711 const size_t kNumTl = 1;
sprangcdafeda2017-06-08 06:12:05 -0700712 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled, false);
asapersson5f7226f2016-11-25 04:37:00 -0800713 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
714
715 // Capture a frame and wait for it to synchronize with the encoder thread.
716 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprangcdafeda2017-06-08 06:12:05 -0700717 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800718 // The encoder have been configured once when the first frame is received.
719 EXPECT_EQ(1, sink_.number_of_reconfigurations());
720 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
721 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
722 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
723 // Resilience is off for no temporal layers with nack on.
724 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
725 vie_encoder_->Stop();
726}
727
728TEST_F(ViEEncoderTest, Vp8ResilienceIsOffFor2S1TlWithNackEnabled) {
729 const bool kNackEnabled = true;
730 const size_t kNumStreams = 2;
731 const size_t kNumTl = 1;
sprangcdafeda2017-06-08 06:12:05 -0700732 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled, false);
asapersson5f7226f2016-11-25 04:37:00 -0800733 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
734
735 // Capture a frame and wait for it to synchronize with the encoder thread.
736 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprangcdafeda2017-06-08 06:12:05 -0700737 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800738 // The encoder have been configured once when the first frame is received.
739 EXPECT_EQ(1, sink_.number_of_reconfigurations());
740 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
741 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
742 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
743 // Resilience is off for no temporal layers and >1 streams with nack on.
744 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
745 vie_encoder_->Stop();
746}
747
748TEST_F(ViEEncoderTest, Vp8ResilienceIsOnFor1S1TLWithNackDisabled) {
749 const bool kNackEnabled = false;
750 const size_t kNumStreams = 1;
751 const size_t kNumTl = 1;
sprangcdafeda2017-06-08 06:12:05 -0700752 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled, false);
asapersson5f7226f2016-11-25 04:37:00 -0800753 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
754
755 // Capture a frame and wait for it to synchronize with the encoder thread.
756 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprangcdafeda2017-06-08 06:12:05 -0700757 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800758 // The encoder have been configured once when the first frame is received.
759 EXPECT_EQ(1, sink_.number_of_reconfigurations());
760 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
761 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
762 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
763 // Resilience is on for no temporal layers with nack off.
764 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
765 vie_encoder_->Stop();
766}
767
768TEST_F(ViEEncoderTest, Vp8ResilienceIsOnFor1S2TlWithNackEnabled) {
769 const bool kNackEnabled = true;
770 const size_t kNumStreams = 1;
771 const size_t kNumTl = 2;
sprangcdafeda2017-06-08 06:12:05 -0700772 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled, false);
asapersson5f7226f2016-11-25 04:37:00 -0800773 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
774
775 // Capture a frame and wait for it to synchronize with the encoder thread.
776 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprangcdafeda2017-06-08 06:12:05 -0700777 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800778 // The encoder have been configured once when the first frame is received.
779 EXPECT_EQ(1, sink_.number_of_reconfigurations());
780 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
781 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
782 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
783 // Resilience is on for temporal layers.
784 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
785 vie_encoder_->Stop();
786}
787
perkj803d97f2016-11-01 11:45:46 -0700788TEST_F(ViEEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
789 EXPECT_TRUE(video_source_.has_sinks());
790 test::FrameForwarder new_video_source;
sprangc5d62e22017-04-02 23:53:04 -0700791 vie_encoder_->SetSource(
792 &new_video_source,
793 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -0700794 EXPECT_FALSE(video_source_.has_sinks());
795 EXPECT_TRUE(new_video_source.has_sinks());
796
797 vie_encoder_->Stop();
798}
799
800TEST_F(ViEEncoderTest, SinkWantsRotationApplied) {
801 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
802 vie_encoder_->SetSink(&sink_, true /*rotation_applied*/);
803 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
804 vie_encoder_->Stop();
805}
806
807TEST_F(ViEEncoderTest, SinkWantsFromOveruseDetector) {
asaperssond0de2952017-04-21 01:47:31 -0700808 const int kMaxDowngrades = ViEEncoder::kMaxCpuResolutionDowngrades;
perkj803d97f2016-11-01 11:45:46 -0700809 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
810
asapersson02465b82017-04-10 01:12:52 -0700811 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700812
813 int frame_width = 1280;
814 int frame_height = 720;
815
816 // Trigger CPU overuse kMaxCpuDowngrades times. Every time, ViEEncoder should
817 // request lower resolution.
asaperssond0de2952017-04-21 01:47:31 -0700818 for (int i = 1; i <= kMaxDowngrades; ++i) {
perkj803d97f2016-11-01 11:45:46 -0700819 video_source_.IncomingCapturedFrame(
820 CreateFrame(i, frame_width, frame_height));
sprangcdafeda2017-06-08 06:12:05 -0700821 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -0700822
823 vie_encoder_->TriggerCpuOveruse();
824
sprang84a37592017-02-10 07:04:27 -0800825 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700826 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
perkj803d97f2016-11-01 11:45:46 -0700827 frame_width * frame_height);
asaperssond0de2952017-04-21 01:47:31 -0700828 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
829 EXPECT_EQ(i, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -0700830
831 frame_width /= 2;
832 frame_height /= 2;
833 }
834
kthelgason876222f2016-11-29 01:44:11 -0800835 // Trigger CPU overuse one more time. This should not trigger a request for
perkj803d97f2016-11-01 11:45:46 -0700836 // lower resolution.
837 rtc::VideoSinkWants current_wants = video_source_.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -0700838 video_source_.IncomingCapturedFrame(
839 CreateFrame(kMaxDowngrades + 1, frame_width, frame_height));
sprangcdafeda2017-06-08 06:12:05 -0700840 WaitForEncodedFrame(kMaxDowngrades + 1);
perkj803d97f2016-11-01 11:45:46 -0700841 vie_encoder_->TriggerCpuOveruse();
sprang84a37592017-02-10 07:04:27 -0800842 EXPECT_EQ(video_source_.sink_wants().target_pixel_count,
843 current_wants.target_pixel_count);
perkj803d97f2016-11-01 11:45:46 -0700844 EXPECT_EQ(video_source_.sink_wants().max_pixel_count,
845 current_wants.max_pixel_count);
asaperssond0de2952017-04-21 01:47:31 -0700846 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
847 EXPECT_EQ(kMaxDowngrades,
848 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -0700849
850 // Trigger CPU normal use.
851 vie_encoder_->TriggerCpuNormalUsage();
sprang84a37592017-02-10 07:04:27 -0800852 EXPECT_EQ(frame_width * frame_height * 5 / 3,
853 video_source_.sink_wants().target_pixel_count.value_or(0));
854 EXPECT_EQ(frame_width * frame_height * 4,
sprangc5d62e22017-04-02 23:53:04 -0700855 video_source_.sink_wants().max_pixel_count);
asaperssond0de2952017-04-21 01:47:31 -0700856 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
857 EXPECT_EQ(kMaxDowngrades + 1,
858 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -0700859
860 vie_encoder_->Stop();
861}
862
sprangc5d62e22017-04-02 23:53:04 -0700863TEST_F(ViEEncoderTest, SinkWantsStoredByDegradationPreference) {
perkj803d97f2016-11-01 11:45:46 -0700864 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -0700865 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700866
sprangc5d62e22017-04-02 23:53:04 -0700867 const int kFrameWidth = 1280;
868 const int kFrameHeight = 720;
869 const int kFrameIntervalMs = 1000 / 30;
870
871 int frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -0700872
kthelgason5e13d412016-12-01 03:59:51 -0800873 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700874 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprangcdafeda2017-06-08 06:12:05 -0700875 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700876 frame_timestamp += kFrameIntervalMs;
877
perkj803d97f2016-11-01 11:45:46 -0700878 // Trigger CPU overuse.
879 vie_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700880 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700881 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprangcdafeda2017-06-08 06:12:05 -0700882 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700883 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -0700884
asapersson0944a802017-04-07 00:57:58 -0700885 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -0700886 // wanted resolution.
887 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
888 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
889 kFrameWidth * kFrameHeight);
890 EXPECT_EQ(std::numeric_limits<int>::max(),
891 video_source_.sink_wants().max_framerate_fps);
892
893 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -0700894 test::FrameForwarder new_video_source;
895 vie_encoder_->SetSource(
896 &new_video_source,
897 VideoSendStream::DegradationPreference::kMaintainResolution);
898
sprangc5d62e22017-04-02 23:53:04 -0700899 // Initially no degradation registered.
asapersson02465b82017-04-10 01:12:52 -0700900 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700901
sprangc5d62e22017-04-02 23:53:04 -0700902 // Force an input frame rate to be available, or the adaptation call won't
903 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -0700904 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -0700905 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -0700906 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -0700907 stats_proxy_->SetMockStats(stats);
908
909 vie_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700910 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -0700911 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprangcdafeda2017-06-08 06:12:05 -0700912 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700913 frame_timestamp += kFrameIntervalMs;
914
915 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -0800916 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700917 EXPECT_EQ(std::numeric_limits<int>::max(),
918 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700919 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -0700920
asapersson02465b82017-04-10 01:12:52 -0700921 // Turn off degradation completely.
sprangc5d62e22017-04-02 23:53:04 -0700922 vie_encoder_->SetSource(
923 &new_video_source,
924 VideoSendStream::DegradationPreference::kDegradationDisabled);
asapersson02465b82017-04-10 01:12:52 -0700925 VerifyNoLimitation(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -0700926
927 vie_encoder_->TriggerCpuOveruse();
928 new_video_source.IncomingCapturedFrame(
929 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprangcdafeda2017-06-08 06:12:05 -0700930 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -0700931 frame_timestamp += kFrameIntervalMs;
932
933 // Still no degradation.
asapersson02465b82017-04-10 01:12:52 -0700934 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700935
936 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
sprangc5d62e22017-04-02 23:53:04 -0700937 vie_encoder_->SetSource(
938 &new_video_source,
939 VideoSendStream::DegradationPreference::kMaintainFramerate);
940 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
941 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -0800942 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700943 EXPECT_EQ(std::numeric_limits<int>::max(),
944 new_video_source.sink_wants().max_framerate_fps);
945
946 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
947 vie_encoder_->SetSource(
948 &new_video_source,
949 VideoSendStream::DegradationPreference::kMaintainResolution);
950 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
951 EXPECT_EQ(std::numeric_limits<int>::max(),
952 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700953 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -0700954
955 vie_encoder_->Stop();
956}
957
asaperssonfab67072017-04-04 05:51:49 -0700958TEST_F(ViEEncoderTest, StatsTracksQualityAdaptationStats) {
perkj803d97f2016-11-01 11:45:46 -0700959 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
960
asaperssonfab67072017-04-04 05:51:49 -0700961 const int kWidth = 1280;
962 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -0700963 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -0700964 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -0700965 VideoSendStream::Stats stats = stats_proxy_->GetStats();
966 EXPECT_FALSE(stats.bw_limited_resolution);
967 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
968
969 // Trigger adapt down.
970 vie_encoder_->TriggerQualityLow();
971 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -0700972 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -0700973
974 stats = stats_proxy_->GetStats();
975 EXPECT_TRUE(stats.bw_limited_resolution);
976 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
977
978 // Trigger adapt up.
979 vie_encoder_->TriggerQualityHigh();
980 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -0700981 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -0700982
983 stats = stats_proxy_->GetStats();
984 EXPECT_FALSE(stats.bw_limited_resolution);
985 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
986 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
987
988 vie_encoder_->Stop();
989}
990
991TEST_F(ViEEncoderTest, StatsTracksCpuAdaptationStats) {
992 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
993
994 const int kWidth = 1280;
995 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -0700996 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -0700997 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -0700998 VideoSendStream::Stats stats = stats_proxy_->GetStats();
999 EXPECT_FALSE(stats.cpu_limited_resolution);
1000 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1001
1002 // Trigger CPU overuse.
1003 vie_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001004 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001005 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001006
1007 stats = stats_proxy_->GetStats();
1008 EXPECT_TRUE(stats.cpu_limited_resolution);
1009 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1010
1011 // Trigger CPU normal use.
1012 vie_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001013 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001014 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001015
1016 stats = stats_proxy_->GetStats();
1017 EXPECT_FALSE(stats.cpu_limited_resolution);
1018 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001019 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001020
1021 vie_encoder_->Stop();
1022}
1023
kthelgason876222f2016-11-29 01:44:11 -08001024TEST_F(ViEEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
kthelgason876222f2016-11-29 01:44:11 -08001025 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1026
asaperssonfab67072017-04-04 05:51:49 -07001027 const int kWidth = 1280;
1028 const int kHeight = 720;
1029 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001030 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001031 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001032 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001033 EXPECT_FALSE(stats.cpu_limited_resolution);
1034 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1035
asaperssonfab67072017-04-04 05:51:49 -07001036 // Trigger CPU overuse.
kthelgason876222f2016-11-29 01:44:11 -08001037 vie_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001038 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001039 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001040 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001041 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001042 EXPECT_TRUE(stats.cpu_limited_resolution);
1043 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1044
1045 // Set new source with adaptation still enabled.
1046 test::FrameForwarder new_video_source;
sprangc5d62e22017-04-02 23:53:04 -07001047 vie_encoder_->SetSource(
1048 &new_video_source,
1049 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001050
asaperssonfab67072017-04-04 05:51:49 -07001051 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001052 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001053 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001054 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001055 EXPECT_TRUE(stats.cpu_limited_resolution);
1056 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1057
1058 // Set adaptation disabled.
1059 vie_encoder_->SetSource(
1060 &new_video_source,
sprangc5d62e22017-04-02 23:53:04 -07001061 VideoSendStream::DegradationPreference::kDegradationDisabled);
kthelgason876222f2016-11-29 01:44:11 -08001062
asaperssonfab67072017-04-04 05:51:49 -07001063 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001064 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001065 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001066 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001067 EXPECT_FALSE(stats.cpu_limited_resolution);
1068 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1069
1070 // Set adaptation back to enabled.
sprangc5d62e22017-04-02 23:53:04 -07001071 vie_encoder_->SetSource(
1072 &new_video_source,
1073 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001074
asaperssonfab67072017-04-04 05:51:49 -07001075 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001076 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001077 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001078 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001079 EXPECT_TRUE(stats.cpu_limited_resolution);
1080 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1081
asaperssonfab67072017-04-04 05:51:49 -07001082 // Trigger CPU normal use.
kthelgason876222f2016-11-29 01:44:11 -08001083 vie_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001084 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001085 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001086 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001087 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001088 EXPECT_FALSE(stats.cpu_limited_resolution);
1089 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001090 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001091
1092 vie_encoder_->Stop();
1093}
1094
1095TEST_F(ViEEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
kthelgason876222f2016-11-29 01:44:11 -08001096 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1097
asaperssonfab67072017-04-04 05:51:49 -07001098 const int kWidth = 1280;
1099 const int kHeight = 720;
1100 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001101 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001102 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001103 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001104 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001105 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001106
1107 // Set new source with adaptation still enabled.
1108 test::FrameForwarder new_video_source;
1109 vie_encoder_->SetSource(&new_video_source,
1110 VideoSendStream::DegradationPreference::kBalanced);
1111
asaperssonfab67072017-04-04 05:51:49 -07001112 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001113 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001114 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001115 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001116 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001117 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001118
asaperssonfab67072017-04-04 05:51:49 -07001119 // Trigger adapt down.
kthelgason876222f2016-11-29 01:44:11 -08001120 vie_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001121 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001122 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001123 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001124 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001125 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001126 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001127
asaperssonfab67072017-04-04 05:51:49 -07001128 // Set new source with adaptation still enabled.
kthelgason876222f2016-11-29 01:44:11 -08001129 vie_encoder_->SetSource(&new_video_source,
1130 VideoSendStream::DegradationPreference::kBalanced);
1131
asaperssonfab67072017-04-04 05:51:49 -07001132 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001133 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001134 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001135 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001136 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001137 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001138
asapersson02465b82017-04-10 01:12:52 -07001139 // Disable resolution scaling.
kthelgason876222f2016-11-29 01:44:11 -08001140 vie_encoder_->SetSource(
1141 &new_video_source,
1142 VideoSendStream::DegradationPreference::kMaintainResolution);
1143
asaperssonfab67072017-04-04 05:51:49 -07001144 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001145 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001146 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001147 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001148 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001149 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1150 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001151
1152 vie_encoder_->Stop();
1153}
1154
asapersson36e9eb42017-03-31 05:29:12 -07001155TEST_F(ViEEncoderTest, QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1156 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1157
1158 const int kWidth = 1280;
1159 const int kHeight = 720;
1160 video_source_.set_adaptation_enabled(true);
1161 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001162 WaitForEncodedFrame(1);
asapersson36e9eb42017-03-31 05:29:12 -07001163 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1164 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1165 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1166
1167 // Trigger adapt down.
1168 vie_encoder_->TriggerQualityLow();
1169 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001170 WaitForEncodedFrame(2);
asapersson36e9eb42017-03-31 05:29:12 -07001171 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1172 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1173 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1174
1175 // Trigger overuse.
1176 vie_encoder_->TriggerCpuOveruse();
1177 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001178 WaitForEncodedFrame(3);
asapersson36e9eb42017-03-31 05:29:12 -07001179 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1180 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1181 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1182
1183 // Set source with adaptation still enabled but quality scaler is off.
1184 fake_encoder_.SetQualityScaling(false);
sprangc5d62e22017-04-02 23:53:04 -07001185 vie_encoder_->SetSource(
1186 &video_source_,
1187 VideoSendStream::DegradationPreference::kMaintainFramerate);
asapersson36e9eb42017-03-31 05:29:12 -07001188
1189 video_source_.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001190 WaitForEncodedFrame(4);
asapersson36e9eb42017-03-31 05:29:12 -07001191 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1192 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1193 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1194
1195 vie_encoder_->Stop();
1196}
1197
asapersson02465b82017-04-10 01:12:52 -07001198TEST_F(ViEEncoderTest, StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
perkj803d97f2016-11-01 11:45:46 -07001199 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1200
asapersson0944a802017-04-07 00:57:58 -07001201 const int kWidth = 1280;
1202 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001203 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001204
asaperssonfab67072017-04-04 05:51:49 -07001205 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001206 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001207 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001208 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001209 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001210 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1211
asapersson02465b82017-04-10 01:12:52 -07001212 // Trigger CPU overuse, should now adapt down.
sprang84a37592017-02-10 07:04:27 -08001213 vie_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001214 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001215 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001216 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001217 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001218 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001219 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1220
1221 // Set new source with adaptation still enabled.
1222 test::FrameForwarder new_video_source;
sprangc5d62e22017-04-02 23:53:04 -07001223 vie_encoder_->SetSource(
1224 &new_video_source,
1225 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001226
1227 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001228 CreateFrame(sequence, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001229 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001230 stats = stats_proxy_->GetStats();
1231 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001232 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001233 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1234
sprangc5d62e22017-04-02 23:53:04 -07001235 // Set cpu adaptation by frame dropping.
perkj803d97f2016-11-01 11:45:46 -07001236 vie_encoder_->SetSource(
1237 &new_video_source,
1238 VideoSendStream::DegradationPreference::kMaintainResolution);
1239 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001240 CreateFrame(sequence, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001241 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001242 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001243 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001244 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001245 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001246 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1247
sprangc5d62e22017-04-02 23:53:04 -07001248 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001249 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001250 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1251 mock_stats.input_frame_rate = 30;
1252 stats_proxy_->SetMockStats(mock_stats);
1253 vie_encoder_->TriggerCpuOveruse();
1254 stats_proxy_->ResetMockStats();
1255
1256 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001257 CreateFrame(sequence, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001258 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001259
1260 // Framerate now adapted.
1261 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001262 EXPECT_FALSE(stats.cpu_limited_resolution);
1263 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001264 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1265
1266 // Disable CPU adaptation.
1267 vie_encoder_->SetSource(
1268 &new_video_source,
1269 VideoSendStream::DegradationPreference::kDegradationDisabled);
1270 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001271 CreateFrame(sequence, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001272 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001273
1274 stats = stats_proxy_->GetStats();
1275 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001276 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001277 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1278
1279 // Try to trigger overuse. Should not succeed.
1280 stats_proxy_->SetMockStats(mock_stats);
1281 vie_encoder_->TriggerCpuOveruse();
1282 stats_proxy_->ResetMockStats();
1283
1284 stats = stats_proxy_->GetStats();
1285 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001286 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001287 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1288
1289 // Switch back the source with resolution adaptation enabled.
1290 vie_encoder_->SetSource(
1291 &video_source_,
1292 VideoSendStream::DegradationPreference::kMaintainFramerate);
asaperssonfab67072017-04-04 05:51:49 -07001293 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001294 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001295 stats = stats_proxy_->GetStats();
1296 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001297 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001298 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001299
1300 // Trigger CPU normal usage.
1301 vie_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001302 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001303 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001304 stats = stats_proxy_->GetStats();
1305 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001306 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001307 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1308
1309 // Back to the source with adaptation off, set it back to maintain-resolution.
1310 vie_encoder_->SetSource(
1311 &new_video_source,
1312 VideoSendStream::DegradationPreference::kMaintainResolution);
1313 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001314 CreateFrame(sequence, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001315 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001316 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001317 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001318 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001319 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001320 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1321
1322 // Trigger CPU normal usage.
1323 vie_encoder_->TriggerCpuNormalUsage();
1324 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001325 CreateFrame(sequence, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001326 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001327 stats = stats_proxy_->GetStats();
1328 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001329 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001330 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001331 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001332
1333 vie_encoder_->Stop();
1334}
1335
Erik Språng08127a92016-11-16 16:41:30 +01001336TEST_F(ViEEncoderTest, StatsTracksPreferredBitrate) {
Erik Språng08127a92016-11-16 16:41:30 +01001337 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1338
asaperssonfab67072017-04-04 05:51:49 -07001339 const int kWidth = 1280;
1340 const int kHeight = 720;
1341 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001342 WaitForEncodedFrame(1);
Erik Språng08127a92016-11-16 16:41:30 +01001343
1344 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1345 EXPECT_EQ(video_encoder_config_.max_bitrate_bps,
1346 stats.preferred_media_bitrate_bps);
1347
1348 vie_encoder_->Stop();
1349}
1350
kthelgason876222f2016-11-29 01:44:11 -08001351TEST_F(ViEEncoderTest, ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001352 const int kWidth = 1280;
1353 const int kHeight = 720;
kthelgason876222f2016-11-29 01:44:11 -08001354 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1355
asaperssonfab67072017-04-04 05:51:49 -07001356 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001357 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001358
asaperssonfab67072017-04-04 05:51:49 -07001359 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001360 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001361
asaperssonfab67072017-04-04 05:51:49 -07001362 // Trigger scale down.
kthelgason5e13d412016-12-01 03:59:51 -08001363 vie_encoder_->TriggerQualityLow();
1364
asaperssonfab67072017-04-04 05:51:49 -07001365 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001366 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001367
kthelgason876222f2016-11-29 01:44:11 -08001368 // Expect a scale down.
1369 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001370 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001371
asapersson02465b82017-04-10 01:12:52 -07001372 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001373 test::FrameForwarder new_video_source;
1374 vie_encoder_->SetSource(
1375 &new_video_source,
1376 VideoSendStream::DegradationPreference::kMaintainResolution);
1377
asaperssonfab67072017-04-04 05:51:49 -07001378 // Trigger scale down.
kthelgason876222f2016-11-29 01:44:11 -08001379 vie_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001380 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001381 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001382
asaperssonfab67072017-04-04 05:51:49 -07001383 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001384 EXPECT_EQ(std::numeric_limits<int>::max(),
1385 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001386
asaperssonfab67072017-04-04 05:51:49 -07001387 // Trigger scale up.
kthelgason876222f2016-11-29 01:44:11 -08001388 vie_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001389 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001390 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001391
asapersson02465b82017-04-10 01:12:52 -07001392 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001393 EXPECT_EQ(std::numeric_limits<int>::max(),
1394 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001395
1396 vie_encoder_->Stop();
1397}
1398
asapersson02465b82017-04-10 01:12:52 -07001399TEST_F(ViEEncoderTest, SkipsSameAdaptDownRequest_MaintainFramerateMode) {
1400 const int kWidth = 1280;
1401 const int kHeight = 720;
1402 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1403
1404 // Enable kMaintainFramerate preference, no initial limitation.
1405 test::FrameForwarder source;
1406 vie_encoder_->SetSource(
1407 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1408
1409 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001410 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001411 VerifyNoLimitation(source.sink_wants());
1412 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1413 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1414
1415 // Trigger adapt down, expect scaled down resolution.
1416 vie_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001417 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001418 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1419 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1420 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1421
1422 // Trigger adapt down for same input resolution, expect no change.
1423 vie_encoder_->TriggerCpuOveruse();
1424 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1425 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1426 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1427
1428 vie_encoder_->Stop();
1429}
1430
1431TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_MaintainFramerateMode) {
1432 const int kWidth = 1280;
1433 const int kHeight = 720;
1434 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1435
1436 // Enable kMaintainFramerate preference, no initial limitation.
1437 test::FrameForwarder source;
1438 vie_encoder_->SetSource(
1439 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1440
1441 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001442 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001443 VerifyNoLimitation(source.sink_wants());
1444 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1445 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1446
1447 // Trigger adapt up, expect no change.
1448 vie_encoder_->TriggerCpuNormalUsage();
1449 VerifyNoLimitation(source.sink_wants());
1450 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1451 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1452
1453 vie_encoder_->Stop();
1454}
1455
1456TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_MaintainResolutionMode) {
1457 const int kWidth = 1280;
1458 const int kHeight = 720;
1459 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1460
1461 // Enable kMaintainResolution preference, no initial limitation.
1462 test::FrameForwarder source;
1463 vie_encoder_->SetSource(
1464 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
1465
1466 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001467 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001468 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001469 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001470 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1471
1472 // Trigger adapt up, expect no change.
1473 vie_encoder_->TriggerCpuNormalUsage();
1474 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001475 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001476 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1477
1478 vie_encoder_->Stop();
1479}
1480
asapersson09f05612017-05-15 23:40:18 -07001481TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
1482 const int kWidth = 1280;
1483 const int kHeight = 720;
1484 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1485
1486 // Enable kDegradationDisabled preference, no initial limitation.
1487 test::FrameForwarder source;
1488 vie_encoder_->SetSource(
1489 &source, VideoSendStream::DegradationPreference::kDegradationDisabled);
1490
1491 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1492 sink_.WaitForEncodedFrame(kWidth, kHeight);
1493 VerifyNoLimitation(source.sink_wants());
1494 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1495 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1496 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1497
1498 // Trigger adapt up, expect no change.
1499 vie_encoder_->TriggerQualityHigh();
1500 VerifyNoLimitation(source.sink_wants());
1501 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1502 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1503 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1504
1505 vie_encoder_->Stop();
1506}
1507
asapersson02465b82017-04-10 01:12:52 -07001508TEST_F(ViEEncoderTest, AdaptsResolutionForLowQuality_MaintainFramerateMode) {
1509 const int kWidth = 1280;
1510 const int kHeight = 720;
1511 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1512
1513 // Enable kMaintainFramerate preference, no initial limitation.
1514 AdaptingFrameForwarder source;
1515 source.set_adaptation_enabled(true);
1516 vie_encoder_->SetSource(
1517 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1518
1519 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001520 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001521 VerifyNoLimitation(source.sink_wants());
1522 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1523 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1524
1525 // Trigger adapt down, expect scaled down resolution.
1526 vie_encoder_->TriggerQualityLow();
1527 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001528 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001529 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001530 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1531 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1532
1533 // Trigger adapt up, expect no restriction.
1534 vie_encoder_->TriggerQualityHigh();
1535 VerifyNoLimitation(source.sink_wants());
1536 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1537 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1538 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1539
1540 vie_encoder_->Stop();
1541}
1542
asapersson09f05612017-05-15 23:40:18 -07001543TEST_F(ViEEncoderTest, AdaptsFramerateForLowQuality_MaintainResolutionMode) {
1544 const int kWidth = 1280;
1545 const int kHeight = 720;
1546 const int kInputFps = 30;
1547 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1548
1549 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1550 stats.input_frame_rate = kInputFps;
1551 stats_proxy_->SetMockStats(stats);
1552
1553 // Expect no scaling to begin with (preference: kMaintainFramerate).
1554 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1555 sink_.WaitForEncodedFrame(1);
1556 VerifyNoLimitation(video_source_.sink_wants());
1557
1558 // Trigger adapt down, expect scaled down resolution.
1559 vie_encoder_->TriggerQualityLow();
1560 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1561 sink_.WaitForEncodedFrame(2);
1562 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1563
1564 // Enable kMaintainResolution preference.
1565 test::FrameForwarder new_video_source;
1566 vie_encoder_->SetSource(
1567 &new_video_source,
1568 VideoSendStream::DegradationPreference::kMaintainResolution);
1569 VerifyNoLimitation(new_video_source.sink_wants());
1570
1571 // Trigger adapt down, expect reduced framerate.
1572 vie_encoder_->TriggerQualityLow();
1573 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1574 sink_.WaitForEncodedFrame(3);
1575 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1576
1577 // Trigger adapt up, expect no restriction.
1578 vie_encoder_->TriggerQualityHigh();
1579 VerifyNoLimitation(new_video_source.sink_wants());
1580
1581 vie_encoder_->Stop();
1582}
1583
asaperssond0de2952017-04-21 01:47:31 -07001584TEST_F(ViEEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
1585 const int kWidth = 1280;
1586 const int kHeight = 720;
1587 const size_t kNumFrames = 10;
1588
kthelgason5e13d412016-12-01 03:59:51 -08001589 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1590
asaperssond0de2952017-04-21 01:47:31 -07001591 // Enable adapter, expected input resolutions when downscaling:
1592 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (min resolution limit)
1593 video_source_.set_adaptation_enabled(true);
1594
1595 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1596 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1597
1598 int downscales = 0;
1599 for (size_t i = 1; i <= kNumFrames; i++) {
1600 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001601 WaitForEncodedFrame(i);
asaperssond0de2952017-04-21 01:47:31 -07001602
asaperssonfab67072017-04-04 05:51:49 -07001603 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001604 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
kthelgason5e13d412016-12-01 03:59:51 -08001605 vie_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001606 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001607
1608 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1609 ++downscales;
1610
1611 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1612 EXPECT_EQ(downscales,
1613 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1614 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001615 }
asaperssond0de2952017-04-21 01:47:31 -07001616 vie_encoder_->Stop();
1617}
1618
1619TEST_F(ViEEncoderTest,
1620 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1621 const int kWidth = 1280;
1622 const int kHeight = 720;
1623 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1624
1625 // Enable kMaintainFramerate preference, no initial limitation.
1626 AdaptingFrameForwarder source;
1627 source.set_adaptation_enabled(true);
1628 vie_encoder_->SetSource(
1629 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1630
1631 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001632 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001633 VerifyNoLimitation(source.sink_wants());
1634 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1635 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1636
1637 // Trigger adapt down, expect scaled down resolution.
1638 vie_encoder_->TriggerCpuOveruse();
1639 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001640 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001641 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001642 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1643 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1644
1645 // Trigger adapt up, expect no restriction.
1646 vie_encoder_->TriggerCpuNormalUsage();
1647 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001648 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001649 VerifyNoLimitation(source.sink_wants());
1650 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1651 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1652
1653 // Trigger adapt down, expect scaled down resolution.
1654 vie_encoder_->TriggerCpuOveruse();
1655 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001656 WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07001657 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001658 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1659 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1660
1661 // Trigger adapt up, expect no restriction.
1662 vie_encoder_->TriggerCpuNormalUsage();
asapersson09f05612017-05-15 23:40:18 -07001663 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1664 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001665 VerifyNoLimitation(source.sink_wants());
1666 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1667 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1668
1669 vie_encoder_->Stop();
1670}
1671
1672TEST_F(ViEEncoderTest,
1673 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
1674 const int kWidth = 1280;
1675 const int kHeight = 720;
1676 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1677
1678 // Enable kMaintainFramerate preference, no initial limitation.
1679 AdaptingFrameForwarder source;
1680 source.set_adaptation_enabled(true);
1681 vie_encoder_->SetSource(
1682 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1683
1684 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001685 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001686 VerifyNoLimitation(source.sink_wants());
1687 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1688 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1689 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1690 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1691
1692 // Trigger cpu adapt down, expect scaled down resolution (960x540).
1693 vie_encoder_->TriggerCpuOveruse();
1694 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001695 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001696 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001697 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1698 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1699 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1700 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1701
1702 // Trigger cpu adapt down, expect scaled down resolution (640x360).
1703 vie_encoder_->TriggerCpuOveruse();
1704 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001705 WaitForEncodedFrame(3);
asapersson09f05612017-05-15 23:40:18 -07001706 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
1707 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07001708 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1709 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1710 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1711 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1712
1713 // Trigger cpu adapt down, max cpu downgrades reached, expect no change.
1714 vie_encoder_->TriggerCpuOveruse();
1715 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001716 WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07001717 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07001718 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1719 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1720 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1721 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1722
1723 // Trigger quality adapt down, expect scaled down resolution (480x270).
1724 vie_encoder_->TriggerQualityLow();
1725 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001726 WaitForEncodedFrame(5);
asapersson09f05612017-05-15 23:40:18 -07001727 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001728 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1729 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1730 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1731 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1732
1733 // Trigger cpu adapt up, expect upscaled resolution (640x360).
1734 vie_encoder_->TriggerCpuNormalUsage();
1735 source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001736 WaitForEncodedFrame(6);
asapersson09f05612017-05-15 23:40:18 -07001737 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001738 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1739 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1740 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1741 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1742
1743 // Trigger cpu adapt up, expect upscaled resolution (960x540).
1744 vie_encoder_->TriggerCpuNormalUsage();
1745 source.IncomingCapturedFrame(CreateFrame(7, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001746 WaitForEncodedFrame(7);
asapersson09f05612017-05-15 23:40:18 -07001747 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001748 last_wants = source.sink_wants();
1749 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1750 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1751 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1752 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1753
1754 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
1755 vie_encoder_->TriggerCpuNormalUsage();
1756 source.IncomingCapturedFrame(CreateFrame(8, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001757 WaitForEncodedFrame(8);
asapersson09f05612017-05-15 23:40:18 -07001758 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07001759 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1760 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1761 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1762 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1763
1764 // Trigger quality adapt up, expect no restriction (1280x720).
1765 vie_encoder_->TriggerQualityHigh();
1766 source.IncomingCapturedFrame(CreateFrame(9, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001767 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07001768 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001769 VerifyNoLimitation(source.sink_wants());
1770 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1771 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1772 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1773 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08001774
1775 vie_encoder_->Stop();
1776}
1777
asaperssonf4e44af2017-04-19 02:01:06 -07001778TEST_F(ViEEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07001779 const int kWidth = 640;
1780 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07001781
sprangcdafeda2017-06-08 06:12:05 -07001782 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1783
perkj803d97f2016-11-01 11:45:46 -07001784 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07001785 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001786 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07001787 }
1788
1789 vie_encoder_->TriggerCpuOveruse();
1790 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07001791 video_source_.IncomingCapturedFrame(CreateFrame(
1792 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001793 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07001794 }
1795
1796 vie_encoder_->Stop();
sprangf8ee65e2017-02-28 08:49:33 -08001797 vie_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07001798 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08001799
perkj803d97f2016-11-01 11:45:46 -07001800 EXPECT_EQ(1,
1801 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
1802 EXPECT_EQ(
1803 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
1804}
1805
asaperssonf4e44af2017-04-19 02:01:06 -07001806TEST_F(ViEEncoderTest, CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
1807 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1808 const int kWidth = 640;
1809 const int kHeight = 360;
1810
1811 vie_encoder_->SetSource(
1812 &video_source_,
1813 VideoSendStream::DegradationPreference::kDegradationDisabled);
1814
1815 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
1816 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001817 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07001818 }
1819
1820 vie_encoder_->Stop();
1821 vie_encoder_.reset();
1822 stats_proxy_.reset();
1823
1824 EXPECT_EQ(0,
1825 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
1826}
1827
sprang57c2fff2017-01-16 06:24:02 -08001828TEST_F(ViEEncoderTest, CallsBitrateObserver) {
1829 class MockBitrateObserver : public VideoBitrateAllocationObserver {
1830 public:
1831 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const BitrateAllocation&));
1832 } bitrate_observer;
1833 vie_encoder_->SetBitrateObserver(&bitrate_observer);
1834
1835 const int kDefaultFps = 30;
1836 const BitrateAllocation expected_bitrate =
1837 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08001838 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08001839
1840 // First called on bitrate updated, then again on first frame.
1841 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
1842 .Times(2);
kthelgason2bc68642017-02-07 07:02:22 -08001843 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08001844
1845 const int64_t kStartTimeMs = 1;
1846 video_source_.IncomingCapturedFrame(
1847 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprangcdafeda2017-06-08 06:12:05 -07001848 WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08001849
1850 // Not called on second frame.
1851 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
1852 .Times(0);
1853 video_source_.IncomingCapturedFrame(
1854 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprangcdafeda2017-06-08 06:12:05 -07001855 WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08001856
1857 // Called after a process interval.
1858 const int64_t kProcessIntervalMs =
1859 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprangcdafeda2017-06-08 06:12:05 -07001860 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec *
1861 (kProcessIntervalMs + (1000 / kDefaultFps)));
sprang57c2fff2017-01-16 06:24:02 -08001862 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
1863 .Times(1);
1864 video_source_.IncomingCapturedFrame(CreateFrame(
1865 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprangcdafeda2017-06-08 06:12:05 -07001866 WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08001867
1868 vie_encoder_->Stop();
1869}
1870
kthelgason2bc68642017-02-07 07:02:22 -08001871TEST_F(ViEEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07001872 const int kTooLowBitrateForFrameSizeBps = 10000;
1873 vie_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
1874 const int kWidth = 640;
1875 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08001876
asaperssonfab67072017-04-04 05:51:49 -07001877 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08001878
1879 // Expect to drop this frame, the wait should time out.
sprangcdafeda2017-06-08 06:12:05 -07001880 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08001881
1882 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07001883 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08001884
sprangc5d62e22017-04-02 23:53:04 -07001885 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08001886
asaperssonfab67072017-04-04 05:51:49 -07001887 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08001888 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001889 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08001890
1891 // Expect to drop this frame, the wait should time out.
sprangcdafeda2017-06-08 06:12:05 -07001892 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08001893
sprangc5d62e22017-04-02 23:53:04 -07001894 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08001895
1896 vie_encoder_->Stop();
1897}
1898
asapersson09f05612017-05-15 23:40:18 -07001899TEST_F(ViEEncoderTest, NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07001900 const int kTooLowBitrateForFrameSizeBps = 10000;
1901 vie_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
1902 const int kWidth = 640;
1903 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08001904
1905 // We expect the n initial frames to get dropped.
1906 int i;
1907 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07001908 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001909 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08001910 }
1911 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07001912 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprangcdafeda2017-06-08 06:12:05 -07001913 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08001914
1915 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07001916 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08001917
1918 vie_encoder_->Stop();
1919}
1920
1921TEST_F(ViEEncoderTest, InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07001922 const int kWidth = 640;
1923 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08001924 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
1925
1926 // Set degradation preference.
1927 vie_encoder_->SetSource(
1928 &video_source_,
1929 VideoSendStream::DegradationPreference::kMaintainResolution);
1930
asaperssonfab67072017-04-04 05:51:49 -07001931 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08001932 // Frame should not be dropped, even if it's too large.
sprangcdafeda2017-06-08 06:12:05 -07001933 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08001934
1935 vie_encoder_->Stop();
1936}
1937
kthelgason2fc52542017-03-03 00:24:41 -08001938TEST_F(ViEEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07001939 const int kWidth = 640;
1940 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08001941 fake_encoder_.SetQualityScaling(false);
1942 vie_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001943
kthelgasonb83797b2017-02-14 11:57:25 -08001944 // Force quality scaler reconfiguration by resetting the source.
1945 vie_encoder_->SetSource(&video_source_,
1946 VideoSendStream::DegradationPreference::kBalanced);
kthelgasonad9010c2017-02-14 00:46:51 -08001947
asaperssonfab67072017-04-04 05:51:49 -07001948 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08001949 // Frame should not be dropped, even if it's too large.
sprangcdafeda2017-06-08 06:12:05 -07001950 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08001951
1952 vie_encoder_->Stop();
1953 fake_encoder_.SetQualityScaling(true);
1954}
1955
asaperssond0de2952017-04-21 01:47:31 -07001956TEST_F(ViEEncoderTest,
1957 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
1958 const int kTooSmallWidth = 10;
1959 const int kTooSmallHeight = 10;
1960 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1961
1962 // Enable kMaintainFramerate preference, no initial limitation.
1963 test::FrameForwarder source;
1964 vie_encoder_->SetSource(
1965 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1966 VerifyNoLimitation(source.sink_wants());
1967 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1968
1969 // Trigger adapt down, too small frame, expect no change.
1970 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprangcdafeda2017-06-08 06:12:05 -07001971 WaitForEncodedFrame(1);
asaperssond0de2952017-04-21 01:47:31 -07001972 vie_encoder_->TriggerCpuOveruse();
1973 VerifyNoLimitation(source.sink_wants());
1974 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1975 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1976
1977 vie_encoder_->Stop();
1978}
1979
asapersson02465b82017-04-10 01:12:52 -07001980TEST_F(ViEEncoderTest, FailingInitEncodeDoesntCauseCrash) {
1981 fake_encoder_.ForceInitEncodeFailure(true);
1982 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangcdafeda2017-06-08 06:12:05 -07001983 ResetEncoder("VP8", 2, 1, true, false);
asapersson02465b82017-04-10 01:12:52 -07001984 const int kFrameWidth = 1280;
1985 const int kFrameHeight = 720;
1986 video_source_.IncomingCapturedFrame(
1987 CreateFrame(1, kFrameWidth, kFrameHeight));
sprangcdafeda2017-06-08 06:12:05 -07001988 ExpectDroppedFrame();
asapersson02465b82017-04-10 01:12:52 -07001989 vie_encoder_->Stop();
1990}
1991
sprangb1ca0732017-02-01 08:38:12 -08001992// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
asaperssond0de2952017-04-21 01:47:31 -07001993TEST_F(ViEEncoderTest, AdaptsResolutionOnOveruse_MaintainFramerateMode) {
sprangb1ca0732017-02-01 08:38:12 -08001994 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
1995
1996 const int kFrameWidth = 1280;
1997 const int kFrameHeight = 720;
1998 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
1999 // requested by ViEEncoder::VideoSourceProxy::RequestResolutionLowerThan().
2000 video_source_.set_adaptation_enabled(true);
2001
2002 video_source_.IncomingCapturedFrame(
2003 CreateFrame(1, kFrameWidth, kFrameHeight));
sprangcdafeda2017-06-08 06:12:05 -07002004 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002005
2006 // Trigger CPU overuse, downscale by 3/4.
2007 vie_encoder_->TriggerCpuOveruse();
2008 video_source_.IncomingCapturedFrame(
2009 CreateFrame(2, kFrameWidth, kFrameHeight));
sprangcdafeda2017-06-08 06:12:05 -07002010 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002011
asaperssonfab67072017-04-04 05:51:49 -07002012 // Trigger CPU normal use, return to original resolution.
sprangb1ca0732017-02-01 08:38:12 -08002013 vie_encoder_->TriggerCpuNormalUsage();
2014 video_source_.IncomingCapturedFrame(
2015 CreateFrame(3, kFrameWidth, kFrameHeight));
sprangcdafeda2017-06-08 06:12:05 -07002016 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002017
2018 vie_encoder_->Stop();
2019}
sprangfe627f32017-03-29 08:24:59 -07002020
asapersson02465b82017-04-10 01:12:52 -07002021TEST_F(ViEEncoderTest, AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangcdafeda2017-06-08 06:12:05 -07002022 // const int kDefaultFramerateFps = 30;
sprangc5d62e22017-04-02 23:53:04 -07002023 const int kFrameWidth = 1280;
2024 const int kFrameHeight = 720;
sprangcdafeda2017-06-08 06:12:05 -07002025 int kFrameIntervalMs = rtc::kNumMillisecsPerSec / max_framerate_;
sprangc5d62e22017-04-02 23:53:04 -07002026
2027 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2028 vie_encoder_->SetSource(
2029 &video_source_,
2030 VideoSendStream::DegradationPreference::kMaintainResolution);
2031 video_source_.set_adaptation_enabled(true);
2032
sprangcdafeda2017-06-08 06:12:05 -07002033 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002034
2035 video_source_.IncomingCapturedFrame(
2036 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprangcdafeda2017-06-08 06:12:05 -07002037 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002038
2039 // Try to trigger overuse. No fps estimate available => no effect.
2040 vie_encoder_->TriggerCpuOveruse();
2041
2042 // Insert frames for one second to get a stable estimate.
sprangcdafeda2017-06-08 06:12:05 -07002043 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002044 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002045 video_source_.IncomingCapturedFrame(
2046 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprangcdafeda2017-06-08 06:12:05 -07002047 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002048 }
2049
2050 // Trigger CPU overuse, reduce framerate by 2/3.
2051 vie_encoder_->TriggerCpuOveruse();
2052 int num_frames_dropped = 0;
sprangcdafeda2017-06-08 06:12:05 -07002053 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002054 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002055 video_source_.IncomingCapturedFrame(
2056 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprangcdafeda2017-06-08 06:12:05 -07002057 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002058 ++num_frames_dropped;
2059 } else {
2060 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2061 }
2062 }
2063
sprangcdafeda2017-06-08 06:12:05 -07002064 // Add some slack to account for frames dropped by the frame dropper.
2065 const int kErrorMargin = 1;
2066 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002067 kErrorMargin);
2068
2069 // Trigger CPU overuse, reduce framerate by 2/3 again.
2070 vie_encoder_->TriggerCpuOveruse();
2071 num_frames_dropped = 0;
sprangcdafeda2017-06-08 06:12:05 -07002072 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002073 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002074 video_source_.IncomingCapturedFrame(
2075 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprangcdafeda2017-06-08 06:12:05 -07002076 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002077 ++num_frames_dropped;
2078 } else {
2079 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2080 }
2081 }
sprangcdafeda2017-06-08 06:12:05 -07002082 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002083 kErrorMargin);
2084
2085 // Go back up one step.
2086 vie_encoder_->TriggerCpuNormalUsage();
2087 num_frames_dropped = 0;
sprangcdafeda2017-06-08 06:12:05 -07002088 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002089 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002090 video_source_.IncomingCapturedFrame(
2091 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprangcdafeda2017-06-08 06:12:05 -07002092 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002093 ++num_frames_dropped;
2094 } else {
2095 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2096 }
2097 }
sprangcdafeda2017-06-08 06:12:05 -07002098 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002099 kErrorMargin);
2100
2101 // Go back up to original mode.
2102 vie_encoder_->TriggerCpuNormalUsage();
2103 num_frames_dropped = 0;
sprangcdafeda2017-06-08 06:12:05 -07002104 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002105 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002106 video_source_.IncomingCapturedFrame(
2107 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprangcdafeda2017-06-08 06:12:05 -07002108 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002109 ++num_frames_dropped;
2110 } else {
2111 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2112 }
2113 }
2114 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2115
2116 vie_encoder_->Stop();
2117}
2118
2119TEST_F(ViEEncoderTest, DoesntAdaptDownPastMinFramerate) {
2120 const int kFramerateFps = 5;
2121 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
2122 const int kMinFpsFrameInterval = rtc::kNumMillisecsPerSec / kMinFramerateFps;
2123 const int kFrameWidth = 1280;
2124 const int kFrameHeight = 720;
2125
sprangcdafeda2017-06-08 06:12:05 -07002126 // Reconfigure encoder with two temporal layers and screensharing, which will
2127 // disable frame dropping and make testing easier.
2128 ResetEncoder("VP8", 1, 2, true, true);
2129
sprangc5d62e22017-04-02 23:53:04 -07002130 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2131 vie_encoder_->SetSource(
2132 &video_source_,
2133 VideoSendStream::DegradationPreference::kMaintainResolution);
2134 video_source_.set_adaptation_enabled(true);
2135
sprangcdafeda2017-06-08 06:12:05 -07002136 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002137
2138 // Trigger overuse as much as we can.
2139 for (int i = 0; i < ViEEncoder::kMaxCpuResolutionDowngrades; ++i) {
2140 // Insert frames to get a new fps estimate...
2141 for (int j = 0; j < kFramerateFps; ++j) {
2142 video_source_.IncomingCapturedFrame(
2143 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
2144 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002145 }
2146 // ...and then try to adapt again.
2147 vie_encoder_->TriggerCpuOveruse();
2148 }
2149
2150 // Drain any frame in the pipeline.
sprangcdafeda2017-06-08 06:12:05 -07002151 WaitForFrame(kDefaultTimeoutMs);
sprangc5d62e22017-04-02 23:53:04 -07002152
2153 // Insert frames at min fps, all should go through.
2154 for (int i = 0; i < 10; ++i) {
2155 timestamp_ms += kMinFpsFrameInterval;
sprangc5d62e22017-04-02 23:53:04 -07002156 video_source_.IncomingCapturedFrame(
2157 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprangcdafeda2017-06-08 06:12:05 -07002158 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002159 }
2160 vie_encoder_->Stop();
2161}
sprangcdafeda2017-06-08 06:12:05 -07002162
2163TEST_F(ViEEncoderTest, PriodicallyUpdatesChannelParameters) {
2164 const int kFrameWidth = 1280;
2165 const int kFrameHeight = 720;
2166 const int kLowFps = 2;
2167 const int kHighFps = 30;
2168
2169 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2170
2171 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
2172 max_framerate_ = kLowFps;
2173
2174 // Insert 2 seconds of 2fps video.
2175 for (int i = 0; i < kLowFps * 2; ++i) {
2176 video_source_.IncomingCapturedFrame(
2177 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
2178 WaitForEncodedFrame(timestamp_ms);
2179 timestamp_ms += 1000 / kLowFps;
2180 }
2181
2182 // Make sure encoder is updated with new target.
2183 vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2184 video_source_.IncomingCapturedFrame(
2185 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
2186 WaitForEncodedFrame(timestamp_ms);
2187 timestamp_ms += 1000 / kLowFps;
2188
2189 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
2190
2191 // Insert 30fps frames for just a little more than the forced update period.
2192 const int kVcmTimerIntervalFrames =
2193 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
2194 const int kFrameIntervalMs = 1000 / kHighFps;
2195 max_framerate_ = kHighFps;
2196 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
2197 video_source_.IncomingCapturedFrame(
2198 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
2199 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
2200 // be dropped if the encoder hans't been updated with the new higher target
2201 // framerate yet, causing it to overshoot the target bitrate and then
2202 // suffering the wrath of the media optimizer.
2203 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
2204 timestamp_ms += kFrameIntervalMs;
2205 }
2206
2207 // Don expect correct measurement just yet, but it should be higher than
2208 // before.
2209 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
2210
2211 vie_encoder_->Stop();
2212}
perkj26091b12016-09-01 01:17:40 -07002213} // namespace webrtc