blob: 69b911942ec560f2f9bf0d7e763667c02fa3b76f [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"
sprangb1ca0732017-02-01 08:38:12 -080016#include "webrtc/media/base/videoadapter.h"
sprangfe627f32017-03-29 08:24:59 -070017#include "webrtc/modules/video_coding/codecs/vp8/temporal_layers.h"
sprang57c2fff2017-01-16 06:24:02 -080018#include "webrtc/modules/video_coding/utility/default_video_bitrate_allocator.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020019#include "webrtc/rtc_base/fakeclock.h"
20#include "webrtc/rtc_base/logging.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"
mflodmancc3d4422017-08-03 08:27:51 -070029#include "webrtc/video/video_stream_encoder.h"
perkj26091b12016-09-01 01:17:40 -070030
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;
asapersson6b463fa2017-08-17 07:28:10 -070037const unsigned char kNumSlDummy = 0;
sprangc5d62e22017-04-02 23:53:04 -070038} // namespace
kthelgason33ce8892016-12-09 03:53:59 -080039
perkj26091b12016-09-01 01:17:40 -070040namespace webrtc {
41
kthelgason876222f2016-11-29 01:44:11 -080042using DegredationPreference = VideoSendStream::DegradationPreference;
sprangb1ca0732017-02-01 08:38:12 -080043using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080044using ::testing::_;
45using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080046
perkj803d97f2016-11-01 11:45:46 -070047namespace {
asapersson5f7226f2016-11-25 04:37:00 -080048const size_t kMaxPayloadLength = 1440;
kthelgason2bc68642017-02-07 07:02:22 -080049const int kTargetBitrateBps = 1000000;
50const int kLowTargetBitrateBps = kTargetBitrateBps / 10;
51const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070052const int kDefaultFramerate = 30;
asapersson5f7226f2016-11-25 04:37:00 -080053
perkj803d97f2016-11-01 11:45:46 -070054class TestBuffer : public webrtc::I420Buffer {
55 public:
56 TestBuffer(rtc::Event* event, int width, int height)
57 : I420Buffer(width, height), event_(event) {}
58
59 private:
60 friend class rtc::RefCountedObject<TestBuffer>;
61 ~TestBuffer() override {
62 if (event_)
63 event_->Set();
64 }
65 rtc::Event* const event_;
66};
67
sprangfda496a2017-06-15 04:21:07 -070068class CpuOveruseDetectorProxy : public OveruseFrameDetector {
69 public:
70 CpuOveruseDetectorProxy(const CpuOveruseOptions& options,
71 AdaptationObserverInterface* overuse_observer,
72 EncodedFrameObserver* encoder_timing_,
73 CpuOveruseMetricsObserver* metrics_observer)
74 : OveruseFrameDetector(options,
75 overuse_observer,
76 encoder_timing_,
77 metrics_observer),
78 last_target_framerate_fps_(-1) {}
79 virtual ~CpuOveruseDetectorProxy() {}
80
81 void OnTargetFramerateUpdated(int framerate_fps) override {
82 rtc::CritScope cs(&lock_);
83 last_target_framerate_fps_ = framerate_fps;
84 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
85 }
86
87 int GetLastTargetFramerate() {
88 rtc::CritScope cs(&lock_);
89 return last_target_framerate_fps_;
90 }
91
92 private:
93 rtc::CriticalSection lock_;
94 int last_target_framerate_fps_ GUARDED_BY(lock_);
95};
96
mflodmancc3d4422017-08-03 08:27:51 -070097class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -070098 public:
mflodmancc3d4422017-08-03 08:27:51 -070099 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
kthelgason876222f2016-11-29 01:44:11 -0800100 const VideoSendStream::Config::EncoderSettings& settings)
mflodmancc3d4422017-08-03 08:27:51 -0700101 : VideoStreamEncoder(
102 1 /* number_of_cores */,
103 stats_proxy,
104 settings,
105 nullptr /* pre_encode_callback */,
106 nullptr /* encoder_timing */,
107 std::unique_ptr<OveruseFrameDetector>(
108 overuse_detector_proxy_ = new CpuOveruseDetectorProxy(
109 GetCpuOveruseOptions(settings.full_overuse_time),
110 this,
111 nullptr,
112 stats_proxy))) {}
perkj803d97f2016-11-01 11:45:46 -0700113
sprangb1ca0732017-02-01 08:38:12 -0800114 void PostTaskAndWait(bool down, AdaptReason reason) {
perkj803d97f2016-11-01 11:45:46 -0700115 rtc::Event event(false, false);
kthelgason876222f2016-11-29 01:44:11 -0800116 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800117 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700118 event.Set();
119 });
perkj070ba852017-02-16 15:46:27 -0800120 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700121 }
122
kthelgason2fc52542017-03-03 00:24:41 -0800123 // This is used as a synchronisation mechanism, to make sure that the
124 // encoder queue is not blocked before we start sending it frames.
125 void WaitUntilTaskQueueIsIdle() {
126 rtc::Event event(false, false);
127 encoder_queue()->PostTask([&event] {
128 event.Set();
129 });
130 ASSERT_TRUE(event.Wait(5000));
131 }
132
sprangb1ca0732017-02-01 08:38:12 -0800133 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800134
sprangb1ca0732017-02-01 08:38:12 -0800135 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800136
sprangb1ca0732017-02-01 08:38:12 -0800137 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800138
sprangb1ca0732017-02-01 08:38:12 -0800139 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700140
141 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700142};
143
asapersson5f7226f2016-11-25 04:37:00 -0800144class VideoStreamFactory
145 : public VideoEncoderConfig::VideoStreamFactoryInterface {
146 public:
sprangfda496a2017-06-15 04:21:07 -0700147 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
148 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800149 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700150 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800151 }
152
153 private:
154 std::vector<VideoStream> CreateEncoderStreams(
155 int width,
156 int height,
157 const VideoEncoderConfig& encoder_config) override {
158 std::vector<VideoStream> streams =
159 test::CreateVideoStreams(width, height, encoder_config);
160 for (VideoStream& stream : streams) {
161 stream.temporal_layer_thresholds_bps.resize(num_temporal_layers_ - 1);
sprangfda496a2017-06-15 04:21:07 -0700162 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800163 }
164 return streams;
165 }
sprangfda496a2017-06-15 04:21:07 -0700166
asapersson5f7226f2016-11-25 04:37:00 -0800167 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700168 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800169};
170
ilnik6b826ef2017-06-16 06:53:48 -0700171
sprangb1ca0732017-02-01 08:38:12 -0800172class AdaptingFrameForwarder : public test::FrameForwarder {
173 public:
174 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700175 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800176
177 void set_adaptation_enabled(bool enabled) {
178 rtc::CritScope cs(&crit_);
179 adaptation_enabled_ = enabled;
180 }
181
asaperssonfab67072017-04-04 05:51:49 -0700182 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800183 rtc::CritScope cs(&crit_);
184 return adaptation_enabled_;
185 }
186
asapersson09f05612017-05-15 23:40:18 -0700187 rtc::VideoSinkWants last_wants() const {
188 rtc::CritScope cs(&crit_);
189 return last_wants_;
190 }
191
sprangb1ca0732017-02-01 08:38:12 -0800192 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
193 int cropped_width = 0;
194 int cropped_height = 0;
195 int out_width = 0;
196 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700197 if (adaption_enabled()) {
198 if (adapter_.AdaptFrameResolution(
199 video_frame.width(), video_frame.height(),
200 video_frame.timestamp_us() * 1000, &cropped_width,
201 &cropped_height, &out_width, &out_height)) {
202 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
203 nullptr, out_width, out_height),
204 99, 99, kVideoRotation_0);
205 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
206 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
207 }
sprangb1ca0732017-02-01 08:38:12 -0800208 } else {
209 test::FrameForwarder::IncomingCapturedFrame(video_frame);
210 }
211 }
212
213 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
214 const rtc::VideoSinkWants& wants) override {
215 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700216 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700217 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
218 wants.max_pixel_count,
219 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800220 test::FrameForwarder::AddOrUpdateSink(sink, wants);
221 }
sprangb1ca0732017-02-01 08:38:12 -0800222 cricket::VideoAdapter adapter_;
223 bool adaptation_enabled_ GUARDED_BY(crit_);
asapersson09f05612017-05-15 23:40:18 -0700224 rtc::VideoSinkWants last_wants_ GUARDED_BY(crit_);
sprangb1ca0732017-02-01 08:38:12 -0800225};
sprangc5d62e22017-04-02 23:53:04 -0700226
227class MockableSendStatisticsProxy : public SendStatisticsProxy {
228 public:
229 MockableSendStatisticsProxy(Clock* clock,
230 const VideoSendStream::Config& config,
231 VideoEncoderConfig::ContentType content_type)
232 : SendStatisticsProxy(clock, config, content_type) {}
233
234 VideoSendStream::Stats GetStats() override {
235 rtc::CritScope cs(&lock_);
236 if (mock_stats_)
237 return *mock_stats_;
238 return SendStatisticsProxy::GetStats();
239 }
240
241 void SetMockStats(const VideoSendStream::Stats& stats) {
242 rtc::CritScope cs(&lock_);
243 mock_stats_.emplace(stats);
244 }
245
246 void ResetMockStats() {
247 rtc::CritScope cs(&lock_);
248 mock_stats_.reset();
249 }
250
251 private:
252 rtc::CriticalSection lock_;
253 rtc::Optional<VideoSendStream::Stats> mock_stats_ GUARDED_BY(lock_);
254};
255
sprang4847ae62017-06-27 07:06:52 -0700256class MockBitrateObserver : public VideoBitrateAllocationObserver {
257 public:
258 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const BitrateAllocation&));
259};
260
perkj803d97f2016-11-01 11:45:46 -0700261} // namespace
262
mflodmancc3d4422017-08-03 08:27:51 -0700263class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700264 public:
265 static const int kDefaultTimeoutMs = 30 * 1000;
266
mflodmancc3d4422017-08-03 08:27:51 -0700267 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700268 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700269 codec_width_(320),
270 codec_height_(240),
sprang4847ae62017-06-27 07:06:52 -0700271 max_framerate_(30),
perkj26091b12016-09-01 01:17:40 -0700272 fake_encoder_(),
sprangc5d62e22017-04-02 23:53:04 -0700273 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700274 Clock::GetRealTimeClock(),
275 video_send_config_,
276 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700277 sink_(&fake_encoder_) {}
278
279 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700280 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700281 video_send_config_ = VideoSendStream::Config(nullptr);
282 video_send_config_.encoder_settings.encoder = &fake_encoder_;
283 video_send_config_.encoder_settings.payload_name = "FAKE";
284 video_send_config_.encoder_settings.payload_type = 125;
285
Per512ecb32016-09-23 15:52:06 +0200286 VideoEncoderConfig video_encoder_config;
perkjfa10b552016-10-02 23:45:26 -0700287 test::FillEncoderConfiguration(1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700288 video_encoder_config.video_stream_factory =
289 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100290 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700291
292 // Framerate limit is specified by the VideoStreamFactory.
293 std::vector<VideoStream> streams =
294 video_encoder_config.video_stream_factory->CreateEncoderStreams(
295 codec_width_, codec_height_, video_encoder_config);
296 max_framerate_ = streams[0].max_framerate;
297 fake_clock_.SetTimeMicros(1234);
298
asapersson5f7226f2016-11-25 04:37:00 -0800299 ConfigureEncoder(std::move(video_encoder_config), true /* nack_enabled */);
300 }
301
302 void ConfigureEncoder(VideoEncoderConfig video_encoder_config,
303 bool nack_enabled) {
mflodmancc3d4422017-08-03 08:27:51 -0700304 if (video_stream_encoder_)
305 video_stream_encoder_->Stop();
306 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700307 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700308 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
309 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -0700310 &video_source_,
311 VideoSendStream::DegradationPreference::kMaintainFramerate);
mflodmancc3d4422017-08-03 08:27:51 -0700312 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
313 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
314 kMaxPayloadLength, nack_enabled);
315 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800316 }
317
318 void ResetEncoder(const std::string& payload_name,
319 size_t num_streams,
320 size_t num_temporal_layers,
asapersson6b463fa2017-08-17 07:28:10 -0700321 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700322 bool nack_enabled,
323 bool screenshare) {
asapersson5f7226f2016-11-25 04:37:00 -0800324 video_send_config_.encoder_settings.payload_name = payload_name;
325
326 VideoEncoderConfig video_encoder_config;
327 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800328 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800329 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700330 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
331 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700332 video_encoder_config.content_type =
333 screenshare ? VideoEncoderConfig::ContentType::kScreen
334 : VideoEncoderConfig::ContentType::kRealtimeVideo;
asapersson6b463fa2017-08-17 07:28:10 -0700335 if (payload_name == "VP9") {
336 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
337 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
338 video_encoder_config.encoder_specific_settings =
339 new rtc::RefCountedObject<
340 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
341 }
asapersson5f7226f2016-11-25 04:37:00 -0800342 ConfigureEncoder(std::move(video_encoder_config), nack_enabled);
perkj26091b12016-09-01 01:17:40 -0700343 }
344
sprang57c2fff2017-01-16 06:24:02 -0800345 VideoFrame CreateFrame(int64_t ntp_time_ms,
346 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200347 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
348 destruction_event, codec_width_, codec_height_),
349 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800350 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700351 return frame;
352 }
353
sprang57c2fff2017-01-16 06:24:02 -0800354 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700355 VideoFrame frame(
356 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
357 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800358 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700359 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700360 return frame;
361 }
362
asapersson02465b82017-04-10 01:12:52 -0700363 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700364 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700365 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
366 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700367 }
368
asapersson09f05612017-05-15 23:40:18 -0700369 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
370 const rtc::VideoSinkWants& wants2) {
371 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
372 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
373 }
374
375 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
376 const rtc::VideoSinkWants& wants2) {
377 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
378 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
379 EXPECT_GT(wants1.max_pixel_count, 0);
380 }
381
382 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
383 const rtc::VideoSinkWants& wants2) {
384 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
385 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
386 }
387
asaperssonf7e294d2017-06-13 23:25:22 -0700388 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
389 const rtc::VideoSinkWants& wants2) {
390 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
391 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
392 }
393
394 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
395 const rtc::VideoSinkWants& wants2) {
396 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
397 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
398 }
399
400 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
401 const rtc::VideoSinkWants& wants2) {
402 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
403 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
404 }
405
406 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
407 const rtc::VideoSinkWants& wants2) {
408 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
409 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
410 EXPECT_GT(wants1.max_pixel_count, 0);
411 }
412
413 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
414 const rtc::VideoSinkWants& wants2) {
415 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
416 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
417 }
418
asapersson09f05612017-05-15 23:40:18 -0700419 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
420 int pixel_count) {
421 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700422 EXPECT_LT(wants.max_pixel_count, pixel_count);
423 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700424 }
425
426 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
427 EXPECT_LT(wants.max_framerate_fps, fps);
428 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
429 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700430 }
431
asaperssonf7e294d2017-06-13 23:25:22 -0700432 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
433 int expected_fps) {
434 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
435 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
436 EXPECT_FALSE(wants.target_pixel_count);
437 }
438
sprang4847ae62017-06-27 07:06:52 -0700439 void WaitForEncodedFrame(int64_t expected_ntp_time) {
440 sink_.WaitForEncodedFrame(expected_ntp_time);
441 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
442 }
443
444 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
445 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
446 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
447 return ok;
448 }
449
450 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
451 sink_.WaitForEncodedFrame(expected_width, expected_height);
452 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
453 }
454
455 void ExpectDroppedFrame() {
456 sink_.ExpectDroppedFrame();
457 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
458 }
459
460 bool WaitForFrame(int64_t timeout_ms) {
461 bool ok = sink_.WaitForFrame(timeout_ms);
462 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
463 return ok;
464 }
465
perkj26091b12016-09-01 01:17:40 -0700466 class TestEncoder : public test::FakeEncoder {
467 public:
468 TestEncoder()
469 : FakeEncoder(Clock::GetRealTimeClock()),
470 continue_encode_event_(false, false) {}
471
asaperssonfab67072017-04-04 05:51:49 -0700472 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800473 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700474 return config_;
475 }
476
477 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800478 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700479 block_next_encode_ = true;
480 }
481
kthelgason876222f2016-11-29 01:44:11 -0800482 VideoEncoder::ScalingSettings GetScalingSettings() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800483 rtc::CritScope lock(&local_crit_sect_);
kthelgasonad9010c2017-02-14 00:46:51 -0800484 if (quality_scaling_)
485 return VideoEncoder::ScalingSettings(true, 1, 2);
486 return VideoEncoder::ScalingSettings(false);
kthelgason876222f2016-11-29 01:44:11 -0800487 }
488
perkjfa10b552016-10-02 23:45:26 -0700489 void ContinueEncode() { continue_encode_event_.Set(); }
490
491 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
492 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800493 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700494 EXPECT_EQ(timestamp_, timestamp);
495 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
496 }
497
kthelgason2fc52542017-03-03 00:24:41 -0800498 void SetQualityScaling(bool b) {
499 rtc::CritScope lock(&local_crit_sect_);
500 quality_scaling_ = b;
501 }
kthelgasonad9010c2017-02-14 00:46:51 -0800502
sprangfe627f32017-03-29 08:24:59 -0700503 void ForceInitEncodeFailure(bool force_failure) {
504 rtc::CritScope lock(&local_crit_sect_);
505 force_init_encode_failed_ = force_failure;
506 }
507
perkjfa10b552016-10-02 23:45:26 -0700508 private:
perkj26091b12016-09-01 01:17:40 -0700509 int32_t Encode(const VideoFrame& input_image,
510 const CodecSpecificInfo* codec_specific_info,
511 const std::vector<FrameType>* frame_types) override {
512 bool block_encode;
513 {
brandtre78d2662017-01-16 05:57:16 -0800514 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700515 EXPECT_GT(input_image.timestamp(), timestamp_);
516 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
517 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
518
519 timestamp_ = input_image.timestamp();
520 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700521 last_input_width_ = input_image.width();
522 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700523 block_encode = block_next_encode_;
524 block_next_encode_ = false;
525 }
526 int32_t result =
527 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
528 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700529 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700530 return result;
531 }
532
sprangfe627f32017-03-29 08:24:59 -0700533 int32_t InitEncode(const VideoCodec* config,
534 int32_t number_of_cores,
535 size_t max_payload_size) override {
536 int res =
537 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
538 rtc::CritScope lock(&local_crit_sect_);
539 if (config->codecType == kVideoCodecVP8 && config->VP8().tl_factory) {
540 // Simulate setting up temporal layers, in order to validate the life
541 // cycle of these objects.
542 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
543 int num_temporal_layers =
544 std::max<int>(1, config->VP8().numberOfTemporalLayers);
545 for (int i = 0; i < num_streams; ++i) {
546 allocated_temporal_layers_.emplace_back(
547 config->VP8().tl_factory->Create(i, num_temporal_layers, 42));
548 }
549 }
550 if (force_init_encode_failed_)
551 return -1;
552 return res;
553 }
554
brandtre78d2662017-01-16 05:57:16 -0800555 rtc::CriticalSection local_crit_sect_;
sprangfe627f32017-03-29 08:24:59 -0700556 bool block_next_encode_ GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700557 rtc::Event continue_encode_event_;
sprangfe627f32017-03-29 08:24:59 -0700558 uint32_t timestamp_ GUARDED_BY(local_crit_sect_) = 0;
559 int64_t ntp_time_ms_ GUARDED_BY(local_crit_sect_) = 0;
560 int last_input_width_ GUARDED_BY(local_crit_sect_) = 0;
561 int last_input_height_ GUARDED_BY(local_crit_sect_) = 0;
562 bool quality_scaling_ GUARDED_BY(local_crit_sect_) = true;
563 std::vector<std::unique_ptr<TemporalLayers>> allocated_temporal_layers_
564 GUARDED_BY(local_crit_sect_);
565 bool force_init_encode_failed_ GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700566 };
567
mflodmancc3d4422017-08-03 08:27:51 -0700568 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700569 public:
570 explicit TestSink(TestEncoder* test_encoder)
571 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
572
perkj26091b12016-09-01 01:17:40 -0700573 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700574 EXPECT_TRUE(
575 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
576 }
577
578 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
579 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700580 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700581 if (!encoded_frame_event_.Wait(timeout_ms))
582 return false;
perkj26091b12016-09-01 01:17:40 -0700583 {
584 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800585 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700586 }
587 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700588 return true;
perkj26091b12016-09-01 01:17:40 -0700589 }
590
sprangb1ca0732017-02-01 08:38:12 -0800591 void WaitForEncodedFrame(uint32_t expected_width,
592 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700593 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
594 CheckLastFrameSizeMathces(expected_width, expected_height);
595 }
596
597 void CheckLastFrameSizeMathces(uint32_t expected_width,
598 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800599 uint32_t width = 0;
600 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800601 {
602 rtc::CritScope lock(&crit_);
603 width = last_width_;
604 height = last_height_;
605 }
606 EXPECT_EQ(expected_height, height);
607 EXPECT_EQ(expected_width, width);
608 }
609
kthelgason2fc52542017-03-03 00:24:41 -0800610 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800611
sprangc5d62e22017-04-02 23:53:04 -0700612 bool WaitForFrame(int64_t timeout_ms) {
613 return encoded_frame_event_.Wait(timeout_ms);
614 }
615
perkj26091b12016-09-01 01:17:40 -0700616 void SetExpectNoFrames() {
617 rtc::CritScope lock(&crit_);
618 expect_frames_ = false;
619 }
620
asaperssonfab67072017-04-04 05:51:49 -0700621 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200622 rtc::CritScope lock(&crit_);
623 return number_of_reconfigurations_;
624 }
625
asaperssonfab67072017-04-04 05:51:49 -0700626 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200627 rtc::CritScope lock(&crit_);
628 return min_transmit_bitrate_bps_;
629 }
630
perkj26091b12016-09-01 01:17:40 -0700631 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700632 Result OnEncodedImage(
633 const EncodedImage& encoded_image,
634 const CodecSpecificInfo* codec_specific_info,
635 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200636 rtc::CritScope lock(&crit_);
637 EXPECT_TRUE(expect_frames_);
sprangb1ca0732017-02-01 08:38:12 -0800638 last_timestamp_ = encoded_image._timeStamp;
639 last_width_ = encoded_image._encodedWidth;
640 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200641 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800642 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200643 }
644
645 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
646 int min_transmit_bitrate_bps) override {
647 rtc::CriticalSection crit_;
648 ++number_of_reconfigurations_;
649 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
650 }
651
perkj26091b12016-09-01 01:17:40 -0700652 rtc::CriticalSection crit_;
653 TestEncoder* test_encoder_;
654 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800655 uint32_t last_timestamp_ = 0;
656 uint32_t last_height_ = 0;
657 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700658 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200659 int number_of_reconfigurations_ = 0;
660 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700661 };
662
663 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100664 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200665 int codec_width_;
666 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700667 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700668 TestEncoder fake_encoder_;
sprangc5d62e22017-04-02 23:53:04 -0700669 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700670 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800671 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700672 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700673 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700674};
675
mflodmancc3d4422017-08-03 08:27:51 -0700676TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
677 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700678 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700679 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700680 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700681 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700682 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700683}
684
mflodmancc3d4422017-08-03 08:27:51 -0700685TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700686 // Dropped since no target bitrate has been set.
687 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700688 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
689 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700690
mflodmancc3d4422017-08-03 08:27:51 -0700691 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700692
perkja49cbd32016-09-16 07:53:41 -0700693 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700694 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700695 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700696}
697
mflodmancc3d4422017-08-03 08:27:51 -0700698TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
699 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700700 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700701 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700702
mflodmancc3d4422017-08-03 08:27:51 -0700703 video_stream_encoder_->OnBitrateUpdated(0, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700704 // Dropped since bitrate is zero.
perkja49cbd32016-09-16 07:53:41 -0700705 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkj26091b12016-09-01 01:17:40 -0700706
mflodmancc3d4422017-08-03 08:27:51 -0700707 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700708 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700709 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700710 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700711}
712
mflodmancc3d4422017-08-03 08:27:51 -0700713TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
714 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700715 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700716 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700717
718 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700719 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700720
perkja49cbd32016-09-16 07:53:41 -0700721 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700722 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700723 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700724}
725
mflodmancc3d4422017-08-03 08:27:51 -0700726TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
727 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700728
perkja49cbd32016-09-16 07:53:41 -0700729 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700730 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700731
mflodmancc3d4422017-08-03 08:27:51 -0700732 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700733 sink_.SetExpectNoFrames();
734 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700735 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
736 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700737}
738
mflodmancc3d4422017-08-03 08:27:51 -0700739TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
740 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700741
742 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700743 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700744 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700745 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
746 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700747 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
748 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700749 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700750 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700751
mflodmancc3d4422017-08-03 08:27:51 -0700752 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700753}
754
mflodmancc3d4422017-08-03 08:27:51 -0700755TEST_F(VideoStreamEncoderTest,
756 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
757 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100758 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200759
760 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200761 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700762 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100763 // The encoder will have been configured once when the first frame is
764 // received.
765 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200766
767 VideoEncoderConfig video_encoder_config;
perkjfa10b552016-10-02 23:45:26 -0700768 test::FillEncoderConfiguration(1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200769 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -0700770 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
771 kMaxPayloadLength,
772 true /* nack_enabled */);
Per512ecb32016-09-23 15:52:06 +0200773
774 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200775 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700776 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100777 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700778 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700779
mflodmancc3d4422017-08-03 08:27:51 -0700780 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -0700781}
782
mflodmancc3d4422017-08-03 08:27:51 -0700783TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
784 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkjfa10b552016-10-02 23:45:26 -0700785
786 // Capture a frame and wait for it to synchronize with the encoder thread.
787 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700788 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100789 // The encoder will have been configured once.
790 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700791 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
792 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
793
794 codec_width_ *= 2;
795 codec_height_ *= 2;
796 // Capture a frame with a higher resolution and wait for it to synchronize
797 // with the encoder thread.
798 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700799 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700800 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
801 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100802 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700803
mflodmancc3d4422017-08-03 08:27:51 -0700804 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -0700805}
806
mflodmancc3d4422017-08-03 08:27:51 -0700807TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOffFor1S1TLWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800808 const bool kNackEnabled = true;
809 const size_t kNumStreams = 1;
810 const size_t kNumTl = 1;
asapersson6b463fa2017-08-17 07:28:10 -0700811 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700812 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800813
814 // Capture a frame and wait for it to synchronize with the encoder thread.
815 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700816 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800817 // The encoder have been configured once when the first frame is received.
818 EXPECT_EQ(1, sink_.number_of_reconfigurations());
819 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
820 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
821 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
822 // Resilience is off for no temporal layers with nack on.
823 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700824 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800825}
826
mflodmancc3d4422017-08-03 08:27:51 -0700827TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOffFor2S1TlWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800828 const bool kNackEnabled = true;
829 const size_t kNumStreams = 2;
830 const size_t kNumTl = 1;
asapersson6b463fa2017-08-17 07:28:10 -0700831 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700832 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800833
834 // Capture a frame and wait for it to synchronize with the encoder thread.
835 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700836 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800837 // The encoder have been configured once when the first frame is received.
838 EXPECT_EQ(1, sink_.number_of_reconfigurations());
839 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
840 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
841 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
842 // Resilience is off for no temporal layers and >1 streams with nack on.
843 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700844 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800845}
846
mflodmancc3d4422017-08-03 08:27:51 -0700847TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOnFor1S1TLWithNackDisabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800848 const bool kNackEnabled = false;
849 const size_t kNumStreams = 1;
850 const size_t kNumTl = 1;
asapersson6b463fa2017-08-17 07:28:10 -0700851 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700852 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800853
854 // Capture a frame and wait for it to synchronize with the encoder thread.
855 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700856 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800857 // The encoder have been configured once when the first frame is received.
858 EXPECT_EQ(1, sink_.number_of_reconfigurations());
859 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
860 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
861 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
862 // Resilience is on for no temporal layers with nack off.
863 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700864 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800865}
866
mflodmancc3d4422017-08-03 08:27:51 -0700867TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOnFor1S2TlWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800868 const bool kNackEnabled = true;
869 const size_t kNumStreams = 1;
870 const size_t kNumTl = 2;
asapersson6b463fa2017-08-17 07:28:10 -0700871 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700872 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800873
874 // Capture a frame and wait for it to synchronize with the encoder thread.
875 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700876 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800877 // The encoder have been configured once when the first frame is received.
878 EXPECT_EQ(1, sink_.number_of_reconfigurations());
879 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
880 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
881 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
882 // Resilience is on for temporal layers.
883 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700884 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800885}
886
asapersson6b463fa2017-08-17 07:28:10 -0700887TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOffFor1SL1TLWithNackEnabled) {
888 const bool kNackEnabled = true;
889 const size_t kNumStreams = 1;
890 const size_t kNumTl = 1;
891 const unsigned char kNumSl = 1;
892 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
893 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
894
895 // Capture a frame and wait for it to synchronize with the encoder thread.
896 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
897 sink_.WaitForEncodedFrame(1);
898 // The encoder have been configured once when the first frame is received.
899 EXPECT_EQ(1, sink_.number_of_reconfigurations());
900 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
901 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
902 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
903 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
904 // Resilience is off for no spatial and temporal layers with nack on.
905 EXPECT_FALSE(fake_encoder_.codec_config().VP9()->resilienceOn);
906 video_stream_encoder_->Stop();
907}
908
909TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOnFor1SL1TLWithNackDisabled) {
910 const bool kNackEnabled = false;
911 const size_t kNumStreams = 1;
912 const size_t kNumTl = 1;
913 const unsigned char kNumSl = 1;
914 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
915 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
916
917 // Capture a frame and wait for it to synchronize with the encoder thread.
918 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
919 sink_.WaitForEncodedFrame(1);
920 // The encoder have been configured once when the first frame is received.
921 EXPECT_EQ(1, sink_.number_of_reconfigurations());
922 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
923 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
924 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
925 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
926 // Resilience is on if nack is off.
927 EXPECT_TRUE(fake_encoder_.codec_config().VP9()->resilienceOn);
928 video_stream_encoder_->Stop();
929}
930
931TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOnFor2SL1TLWithNackEnabled) {
932 const bool kNackEnabled = true;
933 const size_t kNumStreams = 1;
934 const size_t kNumTl = 1;
935 const unsigned char kNumSl = 2;
936 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
937 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
938
939 // Capture a frame and wait for it to synchronize with the encoder thread.
940 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
941 sink_.WaitForEncodedFrame(1);
942 // The encoder have been configured once when the first frame is received.
943 EXPECT_EQ(1, sink_.number_of_reconfigurations());
944 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
945 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
946 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
947 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
948 // Resilience is on for spatial layers.
949 EXPECT_TRUE(fake_encoder_.codec_config().VP9()->resilienceOn);
950 video_stream_encoder_->Stop();
951}
952
953TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOnFor1SL2TLWithNackEnabled) {
954 const bool kNackEnabled = true;
955 const size_t kNumStreams = 1;
956 const size_t kNumTl = 2;
957 const unsigned char kNumSl = 1;
958 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
959 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
960
961 // Capture a frame and wait for it to synchronize with the encoder thread.
962 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
963 sink_.WaitForEncodedFrame(1);
964 // The encoder have been configured once when the first frame is received.
965 EXPECT_EQ(1, sink_.number_of_reconfigurations());
966 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
967 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
968 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
969 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
970 // Resilience is on for temporal layers.
971 EXPECT_TRUE(fake_encoder_.codec_config().VP9()->resilienceOn);
972 video_stream_encoder_->Stop();
973}
974
mflodmancc3d4422017-08-03 08:27:51 -0700975TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -0700976 EXPECT_TRUE(video_source_.has_sinks());
977 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700978 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -0700979 &new_video_source,
980 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -0700981 EXPECT_FALSE(video_source_.has_sinks());
982 EXPECT_TRUE(new_video_source.has_sinks());
983
mflodmancc3d4422017-08-03 08:27:51 -0700984 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700985}
986
mflodmancc3d4422017-08-03 08:27:51 -0700987TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -0700988 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700989 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -0700990 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700991 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700992}
993
mflodmancc3d4422017-08-03 08:27:51 -0700994TEST_F(VideoStreamEncoderTest, SinkWantsFromOveruseDetector) {
995 const int kMaxDowngrades = VideoStreamEncoder::kMaxCpuResolutionDowngrades;
996 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -0700997
asapersson02465b82017-04-10 01:12:52 -0700998 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700999
1000 int frame_width = 1280;
1001 int frame_height = 720;
1002
mflodmancc3d4422017-08-03 08:27:51 -07001003 // Trigger CPU overuse kMaxCpuDowngrades times. Every time, VideoStreamEncoder
1004 // should request lower resolution.
asaperssond0de2952017-04-21 01:47:31 -07001005 for (int i = 1; i <= kMaxDowngrades; ++i) {
perkj803d97f2016-11-01 11:45:46 -07001006 video_source_.IncomingCapturedFrame(
1007 CreateFrame(i, frame_width, frame_height));
sprang4847ae62017-06-27 07:06:52 -07001008 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07001009
mflodmancc3d4422017-08-03 08:27:51 -07001010 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001011
sprang84a37592017-02-10 07:04:27 -08001012 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001013 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
perkj803d97f2016-11-01 11:45:46 -07001014 frame_width * frame_height);
asaperssond0de2952017-04-21 01:47:31 -07001015 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1016 EXPECT_EQ(i, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001017
1018 frame_width /= 2;
1019 frame_height /= 2;
1020 }
1021
kthelgason876222f2016-11-29 01:44:11 -08001022 // Trigger CPU overuse one more time. This should not trigger a request for
perkj803d97f2016-11-01 11:45:46 -07001023 // lower resolution.
1024 rtc::VideoSinkWants current_wants = video_source_.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07001025 video_source_.IncomingCapturedFrame(
1026 CreateFrame(kMaxDowngrades + 1, frame_width, frame_height));
sprang4847ae62017-06-27 07:06:52 -07001027 WaitForEncodedFrame(kMaxDowngrades + 1);
mflodmancc3d4422017-08-03 08:27:51 -07001028 video_stream_encoder_->TriggerCpuOveruse();
sprang84a37592017-02-10 07:04:27 -08001029 EXPECT_EQ(video_source_.sink_wants().target_pixel_count,
1030 current_wants.target_pixel_count);
perkj803d97f2016-11-01 11:45:46 -07001031 EXPECT_EQ(video_source_.sink_wants().max_pixel_count,
1032 current_wants.max_pixel_count);
asaperssond0de2952017-04-21 01:47:31 -07001033 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1034 EXPECT_EQ(kMaxDowngrades,
1035 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001036
1037 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001038 video_stream_encoder_->TriggerCpuNormalUsage();
sprang84a37592017-02-10 07:04:27 -08001039 EXPECT_EQ(frame_width * frame_height * 5 / 3,
1040 video_source_.sink_wants().target_pixel_count.value_or(0));
1041 EXPECT_EQ(frame_width * frame_height * 4,
sprangc5d62e22017-04-02 23:53:04 -07001042 video_source_.sink_wants().max_pixel_count);
asaperssond0de2952017-04-21 01:47:31 -07001043 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1044 EXPECT_EQ(kMaxDowngrades + 1,
1045 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001046
mflodmancc3d4422017-08-03 08:27:51 -07001047 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001048}
1049
mflodmancc3d4422017-08-03 08:27:51 -07001050TEST_F(VideoStreamEncoderTest,
1051 TestMaxCpuResolutionDowngrades_BalancedMode_NoFpsLimit) {
1052 const int kMaxDowngrades = VideoStreamEncoder::kMaxCpuResolutionDowngrades;
asaperssonf7e294d2017-06-13 23:25:22 -07001053 const int kWidth = 1280;
1054 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001055 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001056
1057 // Enable kBalanced preference, no initial limitation.
1058 AdaptingFrameForwarder source;
1059 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001060 video_stream_encoder_->SetSource(
1061 &source,
1062 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001063 VerifyNoLimitation(source.sink_wants());
1064 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1065 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1066
1067 // Trigger adapt down kMaxCpuDowngrades times.
1068 int t = 1;
1069 for (int i = 1; i <= kMaxDowngrades; ++i) {
1070 source.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1071 sink_.WaitForEncodedFrame(t++);
mflodmancc3d4422017-08-03 08:27:51 -07001072 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07001073 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
1074 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1075 EXPECT_EQ(i, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1076 }
1077
1078 // Trigger adapt down, max cpu downgrades reach, expect no change.
1079 rtc::VideoSinkWants last_wants = source.sink_wants();
1080 source.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1081 sink_.WaitForEncodedFrame(t++);
mflodmancc3d4422017-08-03 08:27:51 -07001082 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07001083 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
1084 EXPECT_EQ(last_wants.max_pixel_count, source.sink_wants().max_pixel_count);
1085 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1086 EXPECT_EQ(kMaxDowngrades,
1087 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1088
1089 // Trigger adapt up kMaxCpuDowngrades times.
1090 for (int i = 1; i <= kMaxDowngrades; ++i) {
1091 source.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1092 sink_.WaitForEncodedFrame(t++);
mflodmancc3d4422017-08-03 08:27:51 -07001093 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07001094 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
1095 EXPECT_GT(source.sink_wants().max_pixel_count, last_wants.max_pixel_count);
1096 EXPECT_EQ(kMaxDowngrades + i,
1097 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1098 }
1099
1100 VerifyNoLimitation(source.sink_wants());
1101 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1102
mflodmancc3d4422017-08-03 08:27:51 -07001103 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001104}
mflodmancc3d4422017-08-03 08:27:51 -07001105TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
1106 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001107 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001108
sprangc5d62e22017-04-02 23:53:04 -07001109 const int kFrameWidth = 1280;
1110 const int kFrameHeight = 720;
1111 const int kFrameIntervalMs = 1000 / 30;
1112
1113 int frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -07001114
kthelgason5e13d412016-12-01 03:59:51 -08001115 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001116 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001117 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001118 frame_timestamp += kFrameIntervalMs;
1119
perkj803d97f2016-11-01 11:45:46 -07001120 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001121 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001122 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001123 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001124 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001125 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -07001126
asapersson0944a802017-04-07 00:57:58 -07001127 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -07001128 // wanted resolution.
1129 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
1130 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
1131 kFrameWidth * kFrameHeight);
1132 EXPECT_EQ(std::numeric_limits<int>::max(),
1133 video_source_.sink_wants().max_framerate_fps);
1134
1135 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -07001136 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001137 video_stream_encoder_->SetSource(
perkj803d97f2016-11-01 11:45:46 -07001138 &new_video_source,
1139 VideoSendStream::DegradationPreference::kMaintainResolution);
1140
sprangc5d62e22017-04-02 23:53:04 -07001141 // Initially no degradation registered.
asapersson02465b82017-04-10 01:12:52 -07001142 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001143
sprangc5d62e22017-04-02 23:53:04 -07001144 // Force an input frame rate to be available, or the adaptation call won't
1145 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -07001146 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -07001147 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -07001148 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -07001149 stats_proxy_->SetMockStats(stats);
1150
mflodmancc3d4422017-08-03 08:27:51 -07001151 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001152 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001153 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001154 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001155 frame_timestamp += kFrameIntervalMs;
1156
1157 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001158 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001159 EXPECT_EQ(std::numeric_limits<int>::max(),
1160 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001161 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001162
asapersson02465b82017-04-10 01:12:52 -07001163 // Turn off degradation completely.
mflodmancc3d4422017-08-03 08:27:51 -07001164 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001165 &new_video_source,
1166 VideoSendStream::DegradationPreference::kDegradationDisabled);
asapersson02465b82017-04-10 01:12:52 -07001167 VerifyNoLimitation(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001168
mflodmancc3d4422017-08-03 08:27:51 -07001169 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001170 new_video_source.IncomingCapturedFrame(
1171 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001172 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001173 frame_timestamp += kFrameIntervalMs;
1174
1175 // Still no degradation.
asapersson02465b82017-04-10 01:12:52 -07001176 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001177
1178 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001179 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001180 &new_video_source,
1181 VideoSendStream::DegradationPreference::kMaintainFramerate);
1182 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1183 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001184 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001185 EXPECT_EQ(std::numeric_limits<int>::max(),
1186 new_video_source.sink_wants().max_framerate_fps);
1187
1188 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001189 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001190 &new_video_source,
1191 VideoSendStream::DegradationPreference::kMaintainResolution);
1192 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1193 EXPECT_EQ(std::numeric_limits<int>::max(),
1194 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001195 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001196
mflodmancc3d4422017-08-03 08:27:51 -07001197 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001198}
1199
mflodmancc3d4422017-08-03 08:27:51 -07001200TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
1201 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001202
asaperssonfab67072017-04-04 05:51:49 -07001203 const int kWidth = 1280;
1204 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001205 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001206 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001207 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1208 EXPECT_FALSE(stats.bw_limited_resolution);
1209 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1210
1211 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001212 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001213 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001214 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001215
1216 stats = stats_proxy_->GetStats();
1217 EXPECT_TRUE(stats.bw_limited_resolution);
1218 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1219
1220 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001221 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001222 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001223 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001224
1225 stats = stats_proxy_->GetStats();
1226 EXPECT_FALSE(stats.bw_limited_resolution);
1227 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1228 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1229
mflodmancc3d4422017-08-03 08:27:51 -07001230 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001231}
1232
mflodmancc3d4422017-08-03 08:27:51 -07001233TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
1234 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001235
1236 const int kWidth = 1280;
1237 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001238 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001239 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001240 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1241 EXPECT_FALSE(stats.cpu_limited_resolution);
1242 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1243
1244 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001245 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001246 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001247 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001248
1249 stats = stats_proxy_->GetStats();
1250 EXPECT_TRUE(stats.cpu_limited_resolution);
1251 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1252
1253 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001254 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001255 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001256 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001257
1258 stats = stats_proxy_->GetStats();
1259 EXPECT_FALSE(stats.cpu_limited_resolution);
1260 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001261 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001262
mflodmancc3d4422017-08-03 08:27:51 -07001263 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001264}
1265
mflodmancc3d4422017-08-03 08:27:51 -07001266TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
1267 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001268
asaperssonfab67072017-04-04 05:51:49 -07001269 const int kWidth = 1280;
1270 const int kHeight = 720;
1271 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001272 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001273 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001274 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001275 EXPECT_FALSE(stats.cpu_limited_resolution);
1276 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1277
asaperssonfab67072017-04-04 05:51:49 -07001278 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001279 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001280 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001281 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001282 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001283 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001284 EXPECT_TRUE(stats.cpu_limited_resolution);
1285 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1286
1287 // Set new source with adaptation still enabled.
1288 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001289 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001290 &new_video_source,
1291 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001292
asaperssonfab67072017-04-04 05:51:49 -07001293 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001294 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001295 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001296 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001297 EXPECT_TRUE(stats.cpu_limited_resolution);
1298 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1299
1300 // Set adaptation disabled.
mflodmancc3d4422017-08-03 08:27:51 -07001301 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001302 &new_video_source,
sprangc5d62e22017-04-02 23:53:04 -07001303 VideoSendStream::DegradationPreference::kDegradationDisabled);
kthelgason876222f2016-11-29 01:44:11 -08001304
asaperssonfab67072017-04-04 05:51:49 -07001305 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001306 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001307 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001308 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001309 EXPECT_FALSE(stats.cpu_limited_resolution);
1310 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1311
1312 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001313 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001314 &new_video_source,
1315 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001316
asaperssonfab67072017-04-04 05:51:49 -07001317 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001318 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001319 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001320 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001321 EXPECT_TRUE(stats.cpu_limited_resolution);
1322 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1323
asaperssonfab67072017-04-04 05:51:49 -07001324 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001325 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001326 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001327 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001328 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001329 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001330 EXPECT_FALSE(stats.cpu_limited_resolution);
1331 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001332 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001333
mflodmancc3d4422017-08-03 08:27:51 -07001334 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001335}
1336
mflodmancc3d4422017-08-03 08:27:51 -07001337TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
1338 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001339
asaperssonfab67072017-04-04 05:51:49 -07001340 const int kWidth = 1280;
1341 const int kHeight = 720;
1342 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001343 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001344 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001345 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001346 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001347 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001348
1349 // Set new source with adaptation still enabled.
1350 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001351 video_stream_encoder_->SetSource(
1352 &new_video_source,
1353 VideoSendStream::DegradationPreference::kBalanced);
kthelgason876222f2016-11-29 01:44:11 -08001354
asaperssonfab67072017-04-04 05:51:49 -07001355 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001356 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001357 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001358 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001359 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001360 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001361
asaperssonfab67072017-04-04 05:51:49 -07001362 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001363 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001364 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001365 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001366 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001367 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001368 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001369 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001370
asaperssonfab67072017-04-04 05:51:49 -07001371 // Set new source with adaptation still enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001372 video_stream_encoder_->SetSource(
1373 &new_video_source,
1374 VideoSendStream::DegradationPreference::kBalanced);
kthelgason876222f2016-11-29 01:44:11 -08001375
asaperssonfab67072017-04-04 05:51:49 -07001376 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001377 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001378 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001379 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001380 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001381 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001382
asapersson02465b82017-04-10 01:12:52 -07001383 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001384 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001385 &new_video_source,
1386 VideoSendStream::DegradationPreference::kMaintainResolution);
1387
asaperssonfab67072017-04-04 05:51:49 -07001388 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001389 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001390 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001391 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001392 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001393 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1394 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001395
mflodmancc3d4422017-08-03 08:27:51 -07001396 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001397}
1398
mflodmancc3d4422017-08-03 08:27:51 -07001399TEST_F(VideoStreamEncoderTest,
1400 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1401 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001402
1403 const int kWidth = 1280;
1404 const int kHeight = 720;
1405 video_source_.set_adaptation_enabled(true);
1406 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001407 WaitForEncodedFrame(1);
asapersson36e9eb42017-03-31 05:29:12 -07001408 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1409 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1410 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1411
1412 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001413 video_stream_encoder_->TriggerQualityLow();
asapersson36e9eb42017-03-31 05:29:12 -07001414 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001415 WaitForEncodedFrame(2);
asapersson36e9eb42017-03-31 05:29:12 -07001416 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1417 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1418 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1419
1420 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001421 video_stream_encoder_->TriggerCpuOveruse();
asapersson36e9eb42017-03-31 05:29:12 -07001422 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001423 WaitForEncodedFrame(3);
asapersson36e9eb42017-03-31 05:29:12 -07001424 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1425 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1426 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1427
1428 // Set source with adaptation still enabled but quality scaler is off.
1429 fake_encoder_.SetQualityScaling(false);
mflodmancc3d4422017-08-03 08:27:51 -07001430 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001431 &video_source_,
1432 VideoSendStream::DegradationPreference::kMaintainFramerate);
asapersson36e9eb42017-03-31 05:29:12 -07001433
1434 video_source_.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001435 WaitForEncodedFrame(4);
asapersson36e9eb42017-03-31 05:29:12 -07001436 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1437 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1438 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1439
mflodmancc3d4422017-08-03 08:27:51 -07001440 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001441}
1442
mflodmancc3d4422017-08-03 08:27:51 -07001443TEST_F(VideoStreamEncoderTest,
1444 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
1445 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001446
asapersson0944a802017-04-07 00:57:58 -07001447 const int kWidth = 1280;
1448 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001449 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001450
asaperssonfab67072017-04-04 05:51:49 -07001451 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001452 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001453 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001454 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001455 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001456 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1457
asapersson02465b82017-04-10 01:12:52 -07001458 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001459 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001460 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001461 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001462 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001463 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001464 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001465 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1466
1467 // Set new source with adaptation still enabled.
1468 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001469 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001470 &new_video_source,
1471 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001472
1473 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001474 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001475 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001476 stats = stats_proxy_->GetStats();
1477 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001478 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001479 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1480
sprangc5d62e22017-04-02 23:53:04 -07001481 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001482 video_stream_encoder_->SetSource(
perkj803d97f2016-11-01 11:45:46 -07001483 &new_video_source,
1484 VideoSendStream::DegradationPreference::kMaintainResolution);
1485 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001486 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001487 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001488 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001489 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001490 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001491 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001492 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1493
sprangc5d62e22017-04-02 23:53:04 -07001494 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001495 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001496 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1497 mock_stats.input_frame_rate = 30;
1498 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001499 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001500 stats_proxy_->ResetMockStats();
1501
1502 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001503 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001504 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001505
1506 // Framerate now adapted.
1507 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001508 EXPECT_FALSE(stats.cpu_limited_resolution);
1509 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001510 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1511
1512 // Disable CPU adaptation.
mflodmancc3d4422017-08-03 08:27:51 -07001513 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001514 &new_video_source,
1515 VideoSendStream::DegradationPreference::kDegradationDisabled);
1516 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001517 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001518 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001519
1520 stats = stats_proxy_->GetStats();
1521 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001522 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001523 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1524
1525 // Try to trigger overuse. Should not succeed.
1526 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001527 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001528 stats_proxy_->ResetMockStats();
1529
1530 stats = stats_proxy_->GetStats();
1531 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001532 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001533 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1534
1535 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001536 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001537 &video_source_,
1538 VideoSendStream::DegradationPreference::kMaintainFramerate);
asaperssonfab67072017-04-04 05:51:49 -07001539 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001540 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001541 stats = stats_proxy_->GetStats();
1542 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001543 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001544 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001545
1546 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001547 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001548 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001549 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001550 stats = stats_proxy_->GetStats();
1551 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001552 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001553 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1554
1555 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001556 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001557 &new_video_source,
1558 VideoSendStream::DegradationPreference::kMaintainResolution);
1559 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001560 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001561 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001562 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001563 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001564 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001565 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001566 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1567
1568 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001569 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001570 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001571 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001572 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001573 stats = stats_proxy_->GetStats();
1574 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001575 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001576 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001577 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001578
mflodmancc3d4422017-08-03 08:27:51 -07001579 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001580}
1581
mflodmancc3d4422017-08-03 08:27:51 -07001582TEST_F(VideoStreamEncoderTest, StatsTracksPreferredBitrate) {
1583 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Erik Språng08127a92016-11-16 16:41:30 +01001584
asaperssonfab67072017-04-04 05:51:49 -07001585 const int kWidth = 1280;
1586 const int kHeight = 720;
1587 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001588 WaitForEncodedFrame(1);
Erik Språng08127a92016-11-16 16:41:30 +01001589
1590 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1591 EXPECT_EQ(video_encoder_config_.max_bitrate_bps,
1592 stats.preferred_media_bitrate_bps);
1593
mflodmancc3d4422017-08-03 08:27:51 -07001594 video_stream_encoder_->Stop();
Erik Språng08127a92016-11-16 16:41:30 +01001595}
1596
mflodmancc3d4422017-08-03 08:27:51 -07001597TEST_F(VideoStreamEncoderTest,
1598 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001599 const int kWidth = 1280;
1600 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001601 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001602
asaperssonfab67072017-04-04 05:51:49 -07001603 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001604 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001605
asaperssonfab67072017-04-04 05:51:49 -07001606 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001607 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001608
asaperssonfab67072017-04-04 05:51:49 -07001609 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001610 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001611
asaperssonfab67072017-04-04 05:51:49 -07001612 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001613 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001614
kthelgason876222f2016-11-29 01:44:11 -08001615 // Expect a scale down.
1616 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001617 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001618
asapersson02465b82017-04-10 01:12:52 -07001619 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001620 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001621 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001622 &new_video_source,
1623 VideoSendStream::DegradationPreference::kMaintainResolution);
1624
asaperssonfab67072017-04-04 05:51:49 -07001625 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001626 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001627 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001628 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001629
asaperssonfab67072017-04-04 05:51:49 -07001630 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001631 EXPECT_EQ(std::numeric_limits<int>::max(),
1632 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001633
asaperssonfab67072017-04-04 05:51:49 -07001634 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001635 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001636 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001637 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001638
asapersson02465b82017-04-10 01:12:52 -07001639 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001640 EXPECT_EQ(std::numeric_limits<int>::max(),
1641 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001642
mflodmancc3d4422017-08-03 08:27:51 -07001643 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001644}
1645
mflodmancc3d4422017-08-03 08:27:51 -07001646TEST_F(VideoStreamEncoderTest,
1647 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001648 const int kWidth = 1280;
1649 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001650 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001651
1652 // Enable kMaintainFramerate preference, no initial limitation.
1653 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001654 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001655 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1656
1657 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001658 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001659 VerifyNoLimitation(source.sink_wants());
1660 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1661 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1662
1663 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001664 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001665 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001666 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1667 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1668 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1669
1670 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001671 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001672 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1673 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1674 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1675
mflodmancc3d4422017-08-03 08:27:51 -07001676 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001677}
1678
mflodmancc3d4422017-08-03 08:27:51 -07001679TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001680 const int kWidth = 1280;
1681 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001682 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001683
1684 // Enable kBalanced preference, no initial limitation.
1685 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001686 video_stream_encoder_->SetSource(
1687 &source,
1688 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001689 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1690 sink_.WaitForEncodedFrame(1);
1691 VerifyNoLimitation(source.sink_wants());
1692
1693 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001694 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001695 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1696 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1697 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1698 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1699
1700 // Trigger adapt down for same input resolution, expect no change.
1701 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1702 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001703 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001704 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1705 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1706 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1707
1708 // Trigger adapt down for larger input resolution, expect no change.
1709 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1710 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001711 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001712 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1713 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1714 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1715
mflodmancc3d4422017-08-03 08:27:51 -07001716 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001717}
1718
mflodmancc3d4422017-08-03 08:27:51 -07001719TEST_F(VideoStreamEncoderTest,
1720 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001721 const int kWidth = 1280;
1722 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001723 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001724
1725 // Enable kMaintainFramerate preference, no initial limitation.
1726 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001727 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001728 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1729
1730 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001731 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001732 VerifyNoLimitation(source.sink_wants());
1733 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1734 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1735
1736 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001737 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001738 VerifyNoLimitation(source.sink_wants());
1739 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1740 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1741
mflodmancc3d4422017-08-03 08:27:51 -07001742 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001743}
1744
mflodmancc3d4422017-08-03 08:27:51 -07001745TEST_F(VideoStreamEncoderTest,
1746 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001747 const int kWidth = 1280;
1748 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001749 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001750
1751 // Enable kMaintainResolution preference, no initial limitation.
1752 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001753 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001754 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
1755
1756 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001757 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001758 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001759 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001760 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1761
1762 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001763 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001764 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001765 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001766 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1767
mflodmancc3d4422017-08-03 08:27:51 -07001768 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001769}
1770
mflodmancc3d4422017-08-03 08:27:51 -07001771TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001772 const int kWidth = 1280;
1773 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001774 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001775
1776 // Enable kBalanced preference, no initial limitation.
1777 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001778 video_stream_encoder_->SetSource(
1779 &source,
1780 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001781
1782 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1783 sink_.WaitForEncodedFrame(kWidth, kHeight);
1784 VerifyNoLimitation(source.sink_wants());
1785 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1786 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1787 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1788
1789 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001790 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001791 VerifyNoLimitation(source.sink_wants());
1792 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1793 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1794 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1795
mflodmancc3d4422017-08-03 08:27:51 -07001796 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001797}
1798
mflodmancc3d4422017-08-03 08:27:51 -07001799TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001800 const int kWidth = 1280;
1801 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001802 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001803
1804 // Enable kDegradationDisabled preference, no initial limitation.
1805 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001806 video_stream_encoder_->SetSource(
asapersson09f05612017-05-15 23:40:18 -07001807 &source, VideoSendStream::DegradationPreference::kDegradationDisabled);
1808
1809 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1810 sink_.WaitForEncodedFrame(kWidth, kHeight);
1811 VerifyNoLimitation(source.sink_wants());
1812 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1813 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1814 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1815
1816 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001817 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001818 VerifyNoLimitation(source.sink_wants());
1819 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1820 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1821 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1822
mflodmancc3d4422017-08-03 08:27:51 -07001823 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001824}
1825
mflodmancc3d4422017-08-03 08:27:51 -07001826TEST_F(VideoStreamEncoderTest,
1827 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001828 const int kWidth = 1280;
1829 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001830 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001831
1832 // Enable kMaintainFramerate preference, no initial limitation.
1833 AdaptingFrameForwarder source;
1834 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001835 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001836 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1837
1838 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001839 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001840 VerifyNoLimitation(source.sink_wants());
1841 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1842 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1843
1844 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001845 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001846 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001847 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001848 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001849 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1850 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1851
1852 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001853 video_stream_encoder_->TriggerQualityHigh();
asapersson02465b82017-04-10 01:12:52 -07001854 VerifyNoLimitation(source.sink_wants());
1855 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1856 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1857 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1858
mflodmancc3d4422017-08-03 08:27:51 -07001859 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001860}
1861
mflodmancc3d4422017-08-03 08:27:51 -07001862TEST_F(VideoStreamEncoderTest,
1863 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001864 const int kWidth = 1280;
1865 const int kHeight = 720;
1866 const int kInputFps = 30;
mflodmancc3d4422017-08-03 08:27:51 -07001867 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001868
1869 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1870 stats.input_frame_rate = kInputFps;
1871 stats_proxy_->SetMockStats(stats);
1872
1873 // Expect no scaling to begin with (preference: kMaintainFramerate).
1874 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1875 sink_.WaitForEncodedFrame(1);
1876 VerifyNoLimitation(video_source_.sink_wants());
1877
1878 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001879 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001880 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1881 sink_.WaitForEncodedFrame(2);
1882 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1883
1884 // Enable kMaintainResolution preference.
1885 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001886 video_stream_encoder_->SetSource(
asapersson09f05612017-05-15 23:40:18 -07001887 &new_video_source,
1888 VideoSendStream::DegradationPreference::kMaintainResolution);
1889 VerifyNoLimitation(new_video_source.sink_wants());
1890
1891 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001892 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001893 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1894 sink_.WaitForEncodedFrame(3);
1895 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1896
1897 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001898 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001899 VerifyNoLimitation(new_video_source.sink_wants());
1900
mflodmancc3d4422017-08-03 08:27:51 -07001901 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001902}
1903
mflodmancc3d4422017-08-03 08:27:51 -07001904TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001905 const int kWidth = 1280;
1906 const int kHeight = 720;
1907 const size_t kNumFrames = 10;
1908
mflodmancc3d4422017-08-03 08:27:51 -07001909 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001910
asaperssond0de2952017-04-21 01:47:31 -07001911 // Enable adapter, expected input resolutions when downscaling:
1912 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (min resolution limit)
1913 video_source_.set_adaptation_enabled(true);
1914
1915 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1916 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1917
1918 int downscales = 0;
1919 for (size_t i = 1; i <= kNumFrames; i++) {
1920 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001921 WaitForEncodedFrame(i);
asaperssond0de2952017-04-21 01:47:31 -07001922
asaperssonfab67072017-04-04 05:51:49 -07001923 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001924 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001925 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001926 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001927
1928 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1929 ++downscales;
1930
1931 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1932 EXPECT_EQ(downscales,
1933 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1934 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001935 }
mflodmancc3d4422017-08-03 08:27:51 -07001936 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001937}
1938
mflodmancc3d4422017-08-03 08:27:51 -07001939TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001940 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1941 const int kWidth = 1280;
1942 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001943 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001944
1945 // Enable kMaintainFramerate preference, no initial limitation.
1946 AdaptingFrameForwarder source;
1947 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001948 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07001949 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1950
1951 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001952 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001953 VerifyNoLimitation(source.sink_wants());
1954 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1955 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1956
1957 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001958 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001959 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001960 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001961 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001962 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1963 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1964
1965 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001966 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07001967 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001968 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001969 VerifyNoLimitation(source.sink_wants());
1970 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1971 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1972
1973 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001974 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001975 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001976 WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07001977 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001978 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1979 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1980
1981 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001982 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson09f05612017-05-15 23:40:18 -07001983 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1984 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001985 VerifyNoLimitation(source.sink_wants());
1986 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1987 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1988
mflodmancc3d4422017-08-03 08:27:51 -07001989 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001990}
1991
mflodmancc3d4422017-08-03 08:27:51 -07001992TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07001993 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
1994 const int kWidth = 1280;
1995 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001996 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001997
1998 // Enable kBalanced preference, no initial limitation.
1999 AdaptingFrameForwarder source;
2000 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002001 video_stream_encoder_->SetSource(
2002 &source,
2003 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002004
2005 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2006 sink_.WaitForEncodedFrame(kWidth, kHeight);
2007 VerifyNoLimitation(source.sink_wants());
2008 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2009 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2010
2011 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002012 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002013 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
2014 sink_.WaitForEncodedFrame(2);
2015 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2016 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2017 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2018
2019 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002020 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002021 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
2022 sink_.WaitForEncodedFrame(kWidth, kHeight);
2023 VerifyNoLimitation(source.sink_wants());
2024 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2025 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2026
2027 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002028 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002029 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
2030 sink_.WaitForEncodedFrame(4);
2031 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2032 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2033 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2034
2035 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002036 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002037 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
2038 sink_.WaitForEncodedFrame(kWidth, kHeight);
2039 VerifyNoLimitation(source.sink_wants());
2040 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2041 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2042
mflodmancc3d4422017-08-03 08:27:51 -07002043 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002044}
2045
mflodmancc3d4422017-08-03 08:27:51 -07002046TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002047 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
2048 const int kWidth = 1280;
2049 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07002050 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002051
2052 // Enable kMaintainFramerate preference, no initial limitation.
2053 AdaptingFrameForwarder source;
2054 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002055 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07002056 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
2057
2058 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002059 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002060 VerifyNoLimitation(source.sink_wants());
2061 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2062 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2063 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2064 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2065
2066 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002067 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002068 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002069 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07002070 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002071 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2072 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2073 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2074 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2075
2076 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07002077 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002078 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002079 WaitForEncodedFrame(3);
asapersson09f05612017-05-15 23:40:18 -07002080 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2081 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07002082 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2083 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2084 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2085 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2086
2087 // Trigger cpu adapt down, max cpu downgrades reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002088 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002089 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002090 WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07002091 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002092 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2093 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2094 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2095 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2096
2097 // Trigger quality adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002098 video_stream_encoder_->TriggerQualityLow();
asaperssond0de2952017-04-21 01:47:31 -07002099 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002100 WaitForEncodedFrame(5);
asapersson09f05612017-05-15 23:40:18 -07002101 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002102 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2103 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2104 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2105 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2106
2107 // Trigger cpu adapt up, expect upscaled resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07002108 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07002109 source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002110 WaitForEncodedFrame(6);
asapersson09f05612017-05-15 23:40:18 -07002111 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002112 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2113 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2114 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2115 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2116
2117 // Trigger cpu adapt up, expect upscaled resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002118 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07002119 source.IncomingCapturedFrame(CreateFrame(7, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002120 WaitForEncodedFrame(7);
asapersson09f05612017-05-15 23:40:18 -07002121 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002122 last_wants = source.sink_wants();
2123 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2124 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2125 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2126 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2127
2128 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002129 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07002130 source.IncomingCapturedFrame(CreateFrame(8, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002131 WaitForEncodedFrame(8);
asapersson09f05612017-05-15 23:40:18 -07002132 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002133 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2134 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2135 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2136 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2137
2138 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002139 video_stream_encoder_->TriggerQualityHigh();
asaperssond0de2952017-04-21 01:47:31 -07002140 source.IncomingCapturedFrame(CreateFrame(9, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002141 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002142 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002143 VerifyNoLimitation(source.sink_wants());
2144 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2145 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2146 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2147 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002148
mflodmancc3d4422017-08-03 08:27:51 -07002149 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002150}
2151
mflodmancc3d4422017-08-03 08:27:51 -07002152TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002153 const int kWidth = 640;
2154 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002155
mflodmancc3d4422017-08-03 08:27:51 -07002156 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002157
perkj803d97f2016-11-01 11:45:46 -07002158 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002159 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002160 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002161 }
2162
mflodmancc3d4422017-08-03 08:27:51 -07002163 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002164 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002165 video_source_.IncomingCapturedFrame(CreateFrame(
2166 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002167 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002168 }
2169
mflodmancc3d4422017-08-03 08:27:51 -07002170 video_stream_encoder_->Stop();
2171 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002172 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002173
perkj803d97f2016-11-01 11:45:46 -07002174 EXPECT_EQ(1,
2175 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2176 EXPECT_EQ(
2177 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2178}
2179
mflodmancc3d4422017-08-03 08:27:51 -07002180TEST_F(VideoStreamEncoderTest,
2181 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2182 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002183 const int kWidth = 640;
2184 const int kHeight = 360;
2185
mflodmancc3d4422017-08-03 08:27:51 -07002186 video_stream_encoder_->SetSource(
asaperssonf4e44af2017-04-19 02:01:06 -07002187 &video_source_,
2188 VideoSendStream::DegradationPreference::kDegradationDisabled);
2189
2190 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2191 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002192 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002193 }
2194
mflodmancc3d4422017-08-03 08:27:51 -07002195 video_stream_encoder_->Stop();
2196 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002197 stats_proxy_.reset();
2198
2199 EXPECT_EQ(0,
2200 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2201}
2202
mflodmancc3d4422017-08-03 08:27:51 -07002203TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002204 MockBitrateObserver bitrate_observer;
mflodmancc3d4422017-08-03 08:27:51 -07002205 video_stream_encoder_->SetBitrateObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002206
2207 const int kDefaultFps = 30;
2208 const BitrateAllocation expected_bitrate =
2209 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002210 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002211
2212 // First called on bitrate updated, then again on first frame.
2213 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2214 .Times(2);
mflodmancc3d4422017-08-03 08:27:51 -07002215 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002216
2217 const int64_t kStartTimeMs = 1;
2218 video_source_.IncomingCapturedFrame(
2219 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002220 WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002221
2222 // Not called on second frame.
2223 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2224 .Times(0);
2225 video_source_.IncomingCapturedFrame(
2226 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002227 WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002228
2229 // Called after a process interval.
2230 const int64_t kProcessIntervalMs =
2231 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang4847ae62017-06-27 07:06:52 -07002232 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec *
2233 (kProcessIntervalMs + (1000 / kDefaultFps)));
sprang57c2fff2017-01-16 06:24:02 -08002234 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2235 .Times(1);
2236 video_source_.IncomingCapturedFrame(CreateFrame(
2237 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002238 WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002239
mflodmancc3d4422017-08-03 08:27:51 -07002240 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002241}
2242
mflodmancc3d4422017-08-03 08:27:51 -07002243TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
sprangfda496a2017-06-15 04:21:07 -07002244 const int kFrameWidth = 1280;
2245 const int kFrameHeight = 720;
2246 const int kFramerate = 24;
2247
mflodmancc3d4422017-08-03 08:27:51 -07002248 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002249 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002250 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002251 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2252
2253 // Insert a single frame, triggering initial configuration.
2254 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002255 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002256
mflodmancc3d4422017-08-03 08:27:51 -07002257 EXPECT_EQ(
2258 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2259 kDefaultFramerate);
sprangfda496a2017-06-15 04:21:07 -07002260
2261 // Trigger reconfigure encoder (without resetting the entire instance).
2262 VideoEncoderConfig video_encoder_config;
2263 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2264 video_encoder_config.number_of_streams = 1;
2265 video_encoder_config.video_stream_factory =
2266 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07002267 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2268 kMaxPayloadLength, false);
2269 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002270
2271 // Detector should be updated with fps limit from codec config.
mflodmancc3d4422017-08-03 08:27:51 -07002272 EXPECT_EQ(
2273 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2274 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002275
2276 // Trigger overuse, max framerate should be reduced.
2277 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2278 stats.input_frame_rate = kFramerate;
2279 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002280 video_stream_encoder_->TriggerCpuOveruse();
2281 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002282 int adapted_framerate =
mflodmancc3d4422017-08-03 08:27:51 -07002283 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002284 EXPECT_LT(adapted_framerate, kFramerate);
2285
2286 // Trigger underuse, max framerate should go back to codec configured fps.
2287 // Set extra low fps, to make sure it's actually reset, not just incremented.
2288 stats = stats_proxy_->GetStats();
2289 stats.input_frame_rate = adapted_framerate / 2;
2290 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002291 video_stream_encoder_->TriggerCpuNormalUsage();
2292 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2293 EXPECT_EQ(
2294 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2295 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002296
mflodmancc3d4422017-08-03 08:27:51 -07002297 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002298}
2299
mflodmancc3d4422017-08-03 08:27:51 -07002300TEST_F(VideoStreamEncoderTest,
2301 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
sprangfda496a2017-06-15 04:21:07 -07002302 const int kFrameWidth = 1280;
2303 const int kFrameHeight = 720;
2304 const int kLowFramerate = 15;
2305 const int kHighFramerate = 25;
2306
mflodmancc3d4422017-08-03 08:27:51 -07002307 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002308 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002309 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002310 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2311
2312 // Trigger initial configuration.
2313 VideoEncoderConfig video_encoder_config;
2314 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2315 video_encoder_config.number_of_streams = 1;
2316 video_encoder_config.video_stream_factory =
2317 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2318 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002319 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2320 kMaxPayloadLength, false);
2321 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002322
mflodmancc3d4422017-08-03 08:27:51 -07002323 EXPECT_EQ(
2324 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2325 kLowFramerate);
sprangfda496a2017-06-15 04:21:07 -07002326
2327 // Trigger overuse, max framerate should be reduced.
2328 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2329 stats.input_frame_rate = kLowFramerate;
2330 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002331 video_stream_encoder_->TriggerCpuOveruse();
2332 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002333 int adapted_framerate =
mflodmancc3d4422017-08-03 08:27:51 -07002334 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002335 EXPECT_LT(adapted_framerate, kLowFramerate);
2336
2337 // Reconfigure the encoder with a new (higher max framerate), max fps should
2338 // still respect the adaptation.
2339 video_encoder_config.video_stream_factory =
2340 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2341 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002342 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2343 kMaxPayloadLength, false);
2344 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002345
mflodmancc3d4422017-08-03 08:27:51 -07002346 EXPECT_EQ(
2347 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2348 adapted_framerate);
sprangfda496a2017-06-15 04:21:07 -07002349
2350 // Trigger underuse, max framerate should go back to codec configured fps.
2351 stats = stats_proxy_->GetStats();
2352 stats.input_frame_rate = adapted_framerate;
2353 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002354 video_stream_encoder_->TriggerCpuNormalUsage();
2355 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2356 EXPECT_EQ(
2357 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2358 kHighFramerate);
sprangfda496a2017-06-15 04:21:07 -07002359
mflodmancc3d4422017-08-03 08:27:51 -07002360 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002361}
2362
mflodmancc3d4422017-08-03 08:27:51 -07002363TEST_F(VideoStreamEncoderTest,
2364 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002365 const int kFrameWidth = 1280;
2366 const int kFrameHeight = 720;
2367 const int kFramerate = 24;
2368
mflodmancc3d4422017-08-03 08:27:51 -07002369 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002370 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002371 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002372 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2373
2374 // Trigger initial configuration.
2375 VideoEncoderConfig video_encoder_config;
2376 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2377 video_encoder_config.number_of_streams = 1;
2378 video_encoder_config.video_stream_factory =
2379 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2380 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002381 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2382 kMaxPayloadLength, false);
2383 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002384
mflodmancc3d4422017-08-03 08:27:51 -07002385 EXPECT_EQ(
2386 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2387 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002388
2389 // Trigger overuse, max framerate should be reduced.
2390 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2391 stats.input_frame_rate = kFramerate;
2392 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002393 video_stream_encoder_->TriggerCpuOveruse();
2394 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002395 int adapted_framerate =
mflodmancc3d4422017-08-03 08:27:51 -07002396 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002397 EXPECT_LT(adapted_framerate, kFramerate);
2398
2399 // Change degradation preference to not enable framerate scaling. Target
2400 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002401 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002402 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07002403 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2404 EXPECT_EQ(
2405 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2406 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002407
mflodmancc3d4422017-08-03 08:27:51 -07002408 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002409}
2410
mflodmancc3d4422017-08-03 08:27:51 -07002411TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002412 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002413 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002414 const int kWidth = 640;
2415 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002416
asaperssonfab67072017-04-04 05:51:49 -07002417 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002418
2419 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002420 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002421
2422 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002423 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002424
sprangc5d62e22017-04-02 23:53:04 -07002425 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002426
asaperssonfab67072017-04-04 05:51:49 -07002427 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002428 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002429 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002430
2431 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002432 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002433
sprangc5d62e22017-04-02 23:53:04 -07002434 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002435
mflodmancc3d4422017-08-03 08:27:51 -07002436 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002437}
2438
mflodmancc3d4422017-08-03 08:27:51 -07002439TEST_F(VideoStreamEncoderTest,
2440 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002441 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002442 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002443 const int kWidth = 640;
2444 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002445
2446 // We expect the n initial frames to get dropped.
2447 int i;
2448 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002449 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002450 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002451 }
2452 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002453 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002454 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002455
2456 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002457 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002458
mflodmancc3d4422017-08-03 08:27:51 -07002459 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002460}
2461
mflodmancc3d4422017-08-03 08:27:51 -07002462TEST_F(VideoStreamEncoderTest,
2463 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002464 const int kWidth = 640;
2465 const int kHeight = 360;
mflodmancc3d4422017-08-03 08:27:51 -07002466 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002467
2468 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002469 video_stream_encoder_->SetSource(
kthelgason2bc68642017-02-07 07:02:22 -08002470 &video_source_,
2471 VideoSendStream::DegradationPreference::kMaintainResolution);
2472
asaperssonfab67072017-04-04 05:51:49 -07002473 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002474 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002475 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002476
mflodmancc3d4422017-08-03 08:27:51 -07002477 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002478}
2479
mflodmancc3d4422017-08-03 08:27:51 -07002480TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002481 const int kWidth = 640;
2482 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002483 fake_encoder_.SetQualityScaling(false);
mflodmancc3d4422017-08-03 08:27:51 -07002484 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002485
kthelgasonb83797b2017-02-14 11:57:25 -08002486 // Force quality scaler reconfiguration by resetting the source.
mflodmancc3d4422017-08-03 08:27:51 -07002487 video_stream_encoder_->SetSource(
2488 &video_source_,
2489 VideoSendStream::DegradationPreference::kBalanced);
kthelgasonad9010c2017-02-14 00:46:51 -08002490
asaperssonfab67072017-04-04 05:51:49 -07002491 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002492 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002493 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002494
mflodmancc3d4422017-08-03 08:27:51 -07002495 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002496 fake_encoder_.SetQualityScaling(true);
2497}
2498
mflodmancc3d4422017-08-03 08:27:51 -07002499TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002500 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2501 const int kTooSmallWidth = 10;
2502 const int kTooSmallHeight = 10;
mflodmancc3d4422017-08-03 08:27:51 -07002503 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002504
2505 // Enable kMaintainFramerate preference, no initial limitation.
2506 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002507 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07002508 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
2509 VerifyNoLimitation(source.sink_wants());
2510 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2511
2512 // Trigger adapt down, too small frame, expect no change.
2513 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002514 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002515 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002516 VerifyNoLimitation(source.sink_wants());
2517 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2518 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2519
mflodmancc3d4422017-08-03 08:27:51 -07002520 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002521}
2522
mflodmancc3d4422017-08-03 08:27:51 -07002523TEST_F(VideoStreamEncoderTest,
2524 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002525 const int kTooSmallWidth = 10;
2526 const int kTooSmallHeight = 10;
2527 const int kFpsLimit = 7;
mflodmancc3d4422017-08-03 08:27:51 -07002528 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002529
2530 // Enable kBalanced preference, no initial limitation.
2531 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002532 video_stream_encoder_->SetSource(
2533 &source,
2534 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002535 VerifyNoLimitation(source.sink_wants());
2536 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2537 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2538
2539 // Trigger adapt down, expect limited framerate.
2540 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002541 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002542 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002543 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2544 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2545 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2546 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2547
2548 // Trigger adapt down, too small frame, expect no change.
2549 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002550 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002551 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002552 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2553 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2554 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2555 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2556
mflodmancc3d4422017-08-03 08:27:51 -07002557 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002558}
2559
mflodmancc3d4422017-08-03 08:27:51 -07002560TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002561 fake_encoder_.ForceInitEncodeFailure(true);
mflodmancc3d4422017-08-03 08:27:51 -07002562 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson6b463fa2017-08-17 07:28:10 -07002563 ResetEncoder("VP8", 2, 1, 1, true, false);
asapersson02465b82017-04-10 01:12:52 -07002564 const int kFrameWidth = 1280;
2565 const int kFrameHeight = 720;
2566 video_source_.IncomingCapturedFrame(
2567 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002568 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002569 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002570}
2571
sprangb1ca0732017-02-01 08:38:12 -08002572// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002573TEST_F(VideoStreamEncoderTest,
2574 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
2575 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002576
2577 const int kFrameWidth = 1280;
2578 const int kFrameHeight = 720;
2579 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002580 // requested by
2581 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002582 video_source_.set_adaptation_enabled(true);
2583
2584 video_source_.IncomingCapturedFrame(
2585 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002586 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002587
2588 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002589 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002590 video_source_.IncomingCapturedFrame(
2591 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002592 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002593
asaperssonfab67072017-04-04 05:51:49 -07002594 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002595 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002596 video_source_.IncomingCapturedFrame(
2597 CreateFrame(3, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002598 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002599
mflodmancc3d4422017-08-03 08:27:51 -07002600 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002601}
sprangfe627f32017-03-29 08:24:59 -07002602
mflodmancc3d4422017-08-03 08:27:51 -07002603TEST_F(VideoStreamEncoderTest,
2604 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002605 const int kFrameWidth = 1280;
2606 const int kFrameHeight = 720;
sprang4847ae62017-06-27 07:06:52 -07002607 int kFrameIntervalMs = rtc::kNumMillisecsPerSec / max_framerate_;
sprangc5d62e22017-04-02 23:53:04 -07002608
mflodmancc3d4422017-08-03 08:27:51 -07002609 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2610 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07002611 &video_source_,
2612 VideoSendStream::DegradationPreference::kMaintainResolution);
2613 video_source_.set_adaptation_enabled(true);
2614
sprang4847ae62017-06-27 07:06:52 -07002615 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002616
2617 video_source_.IncomingCapturedFrame(
2618 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002619 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002620
2621 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002622 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002623
2624 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002625 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002626 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002627 video_source_.IncomingCapturedFrame(
2628 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002629 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002630 }
2631
2632 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002633 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002634 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002635 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002636 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002637 video_source_.IncomingCapturedFrame(
2638 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002639 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002640 ++num_frames_dropped;
2641 } else {
2642 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2643 }
2644 }
2645
sprang4847ae62017-06-27 07:06:52 -07002646 // Add some slack to account for frames dropped by the frame dropper.
2647 const int kErrorMargin = 1;
2648 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002649 kErrorMargin);
2650
2651 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002652 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002653 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002654 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002655 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002656 video_source_.IncomingCapturedFrame(
2657 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002658 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002659 ++num_frames_dropped;
2660 } else {
2661 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2662 }
2663 }
sprang4847ae62017-06-27 07:06:52 -07002664 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002665 kErrorMargin);
2666
2667 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002668 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002669 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002670 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002671 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002672 video_source_.IncomingCapturedFrame(
2673 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002674 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002675 ++num_frames_dropped;
2676 } else {
2677 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2678 }
2679 }
sprang4847ae62017-06-27 07:06:52 -07002680 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002681 kErrorMargin);
2682
2683 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002684 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002685 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002686 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002687 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002688 video_source_.IncomingCapturedFrame(
2689 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002690 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002691 ++num_frames_dropped;
2692 } else {
2693 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2694 }
2695 }
2696 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2697
mflodmancc3d4422017-08-03 08:27:51 -07002698 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002699}
2700
mflodmancc3d4422017-08-03 08:27:51 -07002701TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002702 const int kFramerateFps = 5;
2703 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
2704 const int kMinFpsFrameInterval = rtc::kNumMillisecsPerSec / kMinFramerateFps;
2705 const int kFrameWidth = 1280;
2706 const int kFrameHeight = 720;
2707
sprang4847ae62017-06-27 07:06:52 -07002708 // Reconfigure encoder with two temporal layers and screensharing, which will
2709 // disable frame dropping and make testing easier.
asapersson6b463fa2017-08-17 07:28:10 -07002710 ResetEncoder("VP8", 1, 2, 1, true, true);
sprang4847ae62017-06-27 07:06:52 -07002711
mflodmancc3d4422017-08-03 08:27:51 -07002712 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2713 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07002714 &video_source_,
2715 VideoSendStream::DegradationPreference::kMaintainResolution);
2716 video_source_.set_adaptation_enabled(true);
2717
sprang4847ae62017-06-27 07:06:52 -07002718 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002719
2720 // Trigger overuse as much as we can.
mflodmancc3d4422017-08-03 08:27:51 -07002721 for (int i = 0; i < VideoStreamEncoder::kMaxCpuResolutionDowngrades; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002722 // Insert frames to get a new fps estimate...
2723 for (int j = 0; j < kFramerateFps; ++j) {
2724 video_source_.IncomingCapturedFrame(
2725 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
2726 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002727 }
2728 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002729 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002730 }
2731
2732 // Drain any frame in the pipeline.
sprang4847ae62017-06-27 07:06:52 -07002733 WaitForFrame(kDefaultTimeoutMs);
sprangc5d62e22017-04-02 23:53:04 -07002734
2735 // Insert frames at min fps, all should go through.
2736 for (int i = 0; i < 10; ++i) {
2737 timestamp_ms += kMinFpsFrameInterval;
sprangc5d62e22017-04-02 23:53:04 -07002738 video_source_.IncomingCapturedFrame(
2739 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002740 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002741 }
asaperssonf7e294d2017-06-13 23:25:22 -07002742
mflodmancc3d4422017-08-03 08:27:51 -07002743 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002744}
asaperssonf7e294d2017-06-13 23:25:22 -07002745
mflodmancc3d4422017-08-03 08:27:51 -07002746TEST_F(VideoStreamEncoderTest,
2747 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002748 const int kWidth = 1280;
2749 const int kHeight = 720;
2750 const int64_t kFrameIntervalMs = 150;
2751 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002752 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002753
2754 // Enable kBalanced preference, no initial limitation.
2755 AdaptingFrameForwarder source;
2756 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002757 video_stream_encoder_->SetSource(
2758 &source,
2759 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002760 timestamp_ms += kFrameIntervalMs;
2761 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002762 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002763 VerifyNoLimitation(source.sink_wants());
2764 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2765 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2766 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2767
2768 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002769 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002770 timestamp_ms += kFrameIntervalMs;
2771 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002772 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002773 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2774 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2775 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2776 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2777
2778 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002779 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002780 timestamp_ms += kFrameIntervalMs;
2781 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002782 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002783 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2784 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2785 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2786 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2787
2788 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002789 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002790 timestamp_ms += kFrameIntervalMs;
2791 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002792 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002793 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2794 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2795 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2796 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2797
2798 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002799 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002800 timestamp_ms += kFrameIntervalMs;
2801 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002802 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002803 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2804 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2805 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2806 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2807
2808 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002809 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002810 timestamp_ms += kFrameIntervalMs;
2811 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002812 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002813 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2814 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2815 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2816 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2817
2818 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002819 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002820 timestamp_ms += kFrameIntervalMs;
2821 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002822 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002823 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2824 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2825 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2826 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2827
2828 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002829 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002830 timestamp_ms += kFrameIntervalMs;
2831 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002832 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002833 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2834 rtc::VideoSinkWants last_wants = source.sink_wants();
2835 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2836 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2837 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2838
2839 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002840 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002841 timestamp_ms += kFrameIntervalMs;
2842 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002843 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002844 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2845 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2846 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2847 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2848
2849 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002850 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002851 timestamp_ms += kFrameIntervalMs;
2852 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002853 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002854 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2855 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2856 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2857 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2858
2859 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002860 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002861 timestamp_ms += kFrameIntervalMs;
2862 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002863 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002864 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2865 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2866 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2867 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2868
2869 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002870 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002871 timestamp_ms += kFrameIntervalMs;
2872 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002873 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002874 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2875 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2876 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2877 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2878
2879 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002880 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002881 timestamp_ms += kFrameIntervalMs;
2882 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002883 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002884 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2885 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2886 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2887 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2888
2889 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002890 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002891 timestamp_ms += kFrameIntervalMs;
2892 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002893 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002894 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2895 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2896 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2897 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2898
2899 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002900 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002901 timestamp_ms += kFrameIntervalMs;
2902 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002903 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002904 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2905 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2906 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2907 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2908
2909 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002910 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002911 timestamp_ms += kFrameIntervalMs;
2912 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002913 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002914 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2915 VerifyNoLimitation(source.sink_wants());
2916 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2917 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2918 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2919
2920 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002921 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002922 VerifyNoLimitation(source.sink_wants());
2923 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2924
mflodmancc3d4422017-08-03 08:27:51 -07002925 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002926}
2927
mflodmancc3d4422017-08-03 08:27:51 -07002928TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07002929 const int kWidth = 1280;
2930 const int kHeight = 720;
2931 const int64_t kFrameIntervalMs = 150;
2932 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002933 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002934
2935 // Enable kBalanced preference, no initial limitation.
2936 AdaptingFrameForwarder source;
2937 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002938 video_stream_encoder_->SetSource(
2939 &source,
2940 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002941 timestamp_ms += kFrameIntervalMs;
2942 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002943 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002944 VerifyNoLimitation(source.sink_wants());
2945 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2946 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2947 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2948 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2949 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2950 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2951
2952 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002953 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002954 timestamp_ms += kFrameIntervalMs;
2955 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002956 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002957 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2958 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2959 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2960 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2961 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2962 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2963 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2964
2965 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002966 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002967 timestamp_ms += kFrameIntervalMs;
2968 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002969 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002970 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2971 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2972 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2973 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2974 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2975 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2976 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2977
2978 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002979 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002980 timestamp_ms += kFrameIntervalMs;
2981 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002982 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002983 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2984 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2985 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2986 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2987 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2988 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2989 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2990
2991 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002992 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002993 timestamp_ms += kFrameIntervalMs;
2994 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002995 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002996 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2997 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2998 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2999 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3000 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3001 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3002 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3003
3004 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003005 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003006 timestamp_ms += kFrameIntervalMs;
3007 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003008 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003009 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3010 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3011 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3012 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3013 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3014 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3015 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3016
3017 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003018 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003019 timestamp_ms += kFrameIntervalMs;
3020 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003021 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003022 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3023 VerifyNoLimitation(source.sink_wants());
3024 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3025 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3026 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3027 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3028 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3029 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3030
3031 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003032 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003033 VerifyNoLimitation(source.sink_wants());
3034 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3035 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3036
mflodmancc3d4422017-08-03 08:27:51 -07003037 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003038}
3039
mflodmancc3d4422017-08-03 08:27:51 -07003040TEST_F(VideoStreamEncoderTest,
3041 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07003042 const int kWidth = 640;
3043 const int kHeight = 360;
3044 const int kFpsLimit = 15;
3045 const int64_t kFrameIntervalMs = 150;
3046 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07003047 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07003048
3049 // Enable kBalanced preference, no initial limitation.
3050 AdaptingFrameForwarder source;
3051 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07003052 video_stream_encoder_->SetSource(
3053 &source,
3054 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07003055 timestamp_ms += kFrameIntervalMs;
3056 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003057 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003058 VerifyNoLimitation(source.sink_wants());
3059 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3060 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3061 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3062 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3063 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3064 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3065
3066 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003067 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003068 timestamp_ms += kFrameIntervalMs;
3069 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003070 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003071 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
3072 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3073 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3074 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3075 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3076 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3077 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3078
3079 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003080 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003081 timestamp_ms += kFrameIntervalMs;
3082 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003083 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003084 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
3085 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3086 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3087 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3088 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3089 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3090 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3091
3092 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003093 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003094 timestamp_ms += kFrameIntervalMs;
3095 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003096 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003097 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3098 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3099 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3100 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3101 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3102 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3103 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3104
3105 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003106 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003107 timestamp_ms += kFrameIntervalMs;
3108 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003109 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003110 VerifyNoLimitation(source.sink_wants());
3111 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3112 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3113 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3114 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3115 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3116 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3117
3118 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003119 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003120 VerifyNoLimitation(source.sink_wants());
3121 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3122 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3123
mflodmancc3d4422017-08-03 08:27:51 -07003124 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003125}
3126
mflodmancc3d4422017-08-03 08:27:51 -07003127TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003128 // Simulates simulcast behavior and makes highest stream resolutions divisible
3129 // by 4.
3130 class CroppingVideoStreamFactory
3131 : public VideoEncoderConfig::VideoStreamFactoryInterface {
3132 public:
3133 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
3134 int framerate)
3135 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
3136 EXPECT_GT(num_temporal_layers, 0u);
3137 EXPECT_GT(framerate, 0);
3138 }
3139
3140 private:
3141 std::vector<VideoStream> CreateEncoderStreams(
3142 int width,
3143 int height,
3144 const VideoEncoderConfig& encoder_config) override {
3145 std::vector<VideoStream> streams =
3146 test::CreateVideoStreams(width - width % 4, height - height % 4,
3147 encoder_config);
3148 for (VideoStream& stream : streams) {
3149 stream.temporal_layer_thresholds_bps.resize(num_temporal_layers_ - 1);
3150 stream.max_framerate = framerate_;
3151 }
3152 return streams;
3153 }
3154
3155 const size_t num_temporal_layers_;
3156 const int framerate_;
3157 };
3158
3159 const int kFrameWidth = 1920;
3160 const int kFrameHeight = 1080;
3161 // 3/4 of 1920.
3162 const int kAdaptedFrameWidth = 1440;
3163 // 3/4 of 1080 rounded down to multiple of 4.
3164 const int kAdaptedFrameHeight = 808;
3165 const int kFramerate = 24;
3166
mflodmancc3d4422017-08-03 08:27:51 -07003167 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003168 // Trigger reconfigure encoder (without resetting the entire instance).
3169 VideoEncoderConfig video_encoder_config;
3170 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3171 video_encoder_config.number_of_streams = 1;
3172 video_encoder_config.video_stream_factory =
3173 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003174 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
3175 kMaxPayloadLength, false);
3176 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003177
3178 video_source_.set_adaptation_enabled(true);
3179
3180 video_source_.IncomingCapturedFrame(
3181 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003182 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003183
3184 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003185 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003186 video_source_.IncomingCapturedFrame(
3187 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003188 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003189
mflodmancc3d4422017-08-03 08:27:51 -07003190 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003191}
3192
mflodmancc3d4422017-08-03 08:27:51 -07003193TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003194 const int kFrameWidth = 1280;
3195 const int kFrameHeight = 720;
3196 const int kLowFps = 2;
3197 const int kHighFps = 30;
3198
mflodmancc3d4422017-08-03 08:27:51 -07003199 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003200
3201 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3202 max_framerate_ = kLowFps;
3203
3204 // Insert 2 seconds of 2fps video.
3205 for (int i = 0; i < kLowFps * 2; ++i) {
3206 video_source_.IncomingCapturedFrame(
3207 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3208 WaitForEncodedFrame(timestamp_ms);
3209 timestamp_ms += 1000 / kLowFps;
3210 }
3211
3212 // Make sure encoder is updated with new target.
mflodmancc3d4422017-08-03 08:27:51 -07003213 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003214 video_source_.IncomingCapturedFrame(
3215 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3216 WaitForEncodedFrame(timestamp_ms);
3217 timestamp_ms += 1000 / kLowFps;
3218
3219 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3220
3221 // Insert 30fps frames for just a little more than the forced update period.
3222 const int kVcmTimerIntervalFrames =
3223 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3224 const int kFrameIntervalMs = 1000 / kHighFps;
3225 max_framerate_ = kHighFps;
3226 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3227 video_source_.IncomingCapturedFrame(
3228 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3229 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3230 // be dropped if the encoder hans't been updated with the new higher target
3231 // framerate yet, causing it to overshoot the target bitrate and then
3232 // suffering the wrath of the media optimizer.
3233 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3234 timestamp_ms += kFrameIntervalMs;
3235 }
3236
3237 // Don expect correct measurement just yet, but it should be higher than
3238 // before.
3239 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3240
mflodmancc3d4422017-08-03 08:27:51 -07003241 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003242}
3243
mflodmancc3d4422017-08-03 08:27:51 -07003244TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003245 const int kFrameWidth = 1280;
3246 const int kFrameHeight = 720;
3247 const int kTargetBitrateBps = 1000000;
3248
3249 MockBitrateObserver bitrate_observer;
mflodmancc3d4422017-08-03 08:27:51 -07003250 video_stream_encoder_->SetBitrateObserver(&bitrate_observer);
sprang4847ae62017-06-27 07:06:52 -07003251
3252 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3253 // Initial bitrate update.
mflodmancc3d4422017-08-03 08:27:51 -07003254 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3255 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003256
3257 // Insert a first video frame, causes another bitrate update.
3258 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3259 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3260 video_source_.IncomingCapturedFrame(
3261 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3262 WaitForEncodedFrame(timestamp_ms);
3263
3264 // Next, simulate video suspension due to pacer queue overrun.
mflodmancc3d4422017-08-03 08:27:51 -07003265 video_stream_encoder_->OnBitrateUpdated(0, 0, 1);
sprang4847ae62017-06-27 07:06:52 -07003266
3267 // Skip ahead until a new periodic parameter update should have occured.
3268 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3269 fake_clock_.AdvanceTimeMicros(
3270 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3271 rtc::kNumMicrosecsPerMillisec);
3272
3273 // Bitrate observer should not be called.
3274 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3275 video_source_.IncomingCapturedFrame(
3276 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3277 ExpectDroppedFrame();
3278
mflodmancc3d4422017-08-03 08:27:51 -07003279 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003280}
ilnik6b826ef2017-06-16 06:53:48 -07003281
perkj26091b12016-09-01 01:17:40 -07003282} // namespace webrtc