blob: 71e80631c49dbef7feecf1d209fa9e2374930e91 [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
Erik Språng4529fbc2018-10-12 10:30:31 +020011#include "video/video_stream_encoder.h"
12
sprangfe627f32017-03-29 08:24:59 -070013#include <algorithm>
perkj803d97f2016-11-01 11:45:46 -070014#include <limits>
Per512ecb32016-09-23 15:52:06 +020015#include <utility>
16
Sebastian Jansson74682c12019-03-01 11:50:20 +010017#include "api/task_queue/global_task_queue_factory.h"
Jiawei Ouc2ebe212018-11-08 10:02:56 -080018#include "api/video/builtin_video_bitrate_allocator_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "api/video/i420_buffer.h"
Erik Språngf93eda12019-01-16 17:10:57 +010020#include "api/video/video_bitrate_allocation.h"
Erik Språng4529fbc2018-10-12 10:30:31 +020021#include "api/video_codecs/vp8_temporal_layers.h"
Elad Aloncde8ab22019-03-20 11:56:20 +010022#include "api/video_codecs/vp8_temporal_layers_factory.h"
Steve Anton10542f22019-01-11 09:11:00 -080023#include "media/base/video_adapter.h"
Sergey Silkin86684962018-03-28 19:32:37 +020024#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
Åsa Perssonc29cb2c2019-03-25 12:06:59 +010026#include "modules/video_coding/utility/simulcast_rate_allocator.h"
Steve Anton10542f22019-01-11 09:11:00 -080027#include "rtc_base/fake_clock.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020028#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080029#include "rtc_base/ref_counted_object.h"
Erik Språng7ca375c2019-02-06 16:20:17 +010030#include "system_wrappers/include/field_trial.h"
Mirko Bonadei17f48782018-09-28 08:51:10 +020031#include "system_wrappers/include/metrics.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020032#include "system_wrappers/include/sleep.h"
33#include "test/encoder_settings.h"
34#include "test/fake_encoder.h"
Kári Tristan Helgason639602a2018-08-02 10:51:40 +020035#include "test/field_trial.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020036#include "test/frame_generator.h"
37#include "test/gmock.h"
38#include "test/gtest.h"
Niels Möllercbcbc222018-09-28 09:07:24 +020039#include "test/video_encoder_proxy_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020040#include "video/send_statistics_proxy.h"
perkj26091b12016-09-01 01:17:40 -070041
42namespace webrtc {
43
sprangb1ca0732017-02-01 08:38:12 -080044using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080045using ::testing::_;
kthelgason876222f2016-11-29 01:44:11 -080046
perkj803d97f2016-11-01 11:45:46 -070047namespace {
Åsa Persson8c1bf952018-09-13 10:42:19 +020048const int kMinPixelsPerFrame = 320 * 180;
49const int kMinFramerateFps = 2;
50const int kMinBalancedFramerateFps = 7;
51const int64_t kFrameTimeoutMs = 100;
asapersson5f7226f2016-11-25 04:37:00 -080052const size_t kMaxPayloadLength = 1440;
Erik Språngd7329ca2019-02-21 21:19:53 +010053const uint32_t kTargetBitrateBps = 1000000;
54const uint32_t kSimulcastTargetBitrateBps = 3150000;
55const uint32_t kLowTargetBitrateBps = kTargetBitrateBps / 10;
kthelgason2bc68642017-02-07 07:02:22 -080056const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070057const int kDefaultFramerate = 30;
Åsa Persson8c1bf952018-09-13 10:42:19 +020058const int64_t kFrameIntervalMs = rtc::kNumMillisecsPerSec / kDefaultFramerate;
asapersson5f7226f2016-11-25 04:37:00 -080059
perkj803d97f2016-11-01 11:45:46 -070060class TestBuffer : public webrtc::I420Buffer {
61 public:
62 TestBuffer(rtc::Event* event, int width, int height)
63 : I420Buffer(width, height), event_(event) {}
64
65 private:
66 friend class rtc::RefCountedObject<TestBuffer>;
67 ~TestBuffer() override {
68 if (event_)
69 event_->Set();
70 }
71 rtc::Event* const event_;
72};
73
Niels Möller7dc26b72017-12-06 10:27:48 +010074class CpuOveruseDetectorProxy : public OveruseFrameDetector {
75 public:
Niels Möllerd1f7eb62018-03-28 16:40:58 +020076 explicit CpuOveruseDetectorProxy(CpuOveruseMetricsObserver* metrics_observer)
77 : OveruseFrameDetector(metrics_observer),
Niels Möller7dc26b72017-12-06 10:27:48 +010078 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
Niels Möller4db138e2018-04-19 09:04:13 +020092 CpuOveruseOptions GetOptions() { return options_; }
93
Niels Möller7dc26b72017-12-06 10:27:48 +010094 private:
95 rtc::CriticalSection lock_;
96 int last_target_framerate_fps_ RTC_GUARDED_BY(lock_);
97};
98
mflodmancc3d4422017-08-03 08:27:51 -070099class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -0700100 public:
Niels Möller213618e2018-07-24 09:29:58 +0200101 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
102 const VideoStreamEncoderSettings& settings)
Sebastian Jansson572c60f2019-03-04 18:30:41 +0100103 : VideoStreamEncoder(Clock::GetRealTimeClock(),
104 1 /* number_of_cores */,
Yves Gerey665174f2018-06-19 15:03:05 +0200105 stats_proxy,
106 settings,
Yves Gerey665174f2018-06-19 15:03:05 +0200107 std::unique_ptr<OveruseFrameDetector>(
108 overuse_detector_proxy_ =
Sebastian Jansson74682c12019-03-01 11:50:20 +0100109 new CpuOveruseDetectorProxy(stats_proxy)),
110 &GlobalTaskQueueFactory()) {}
perkj803d97f2016-11-01 11:45:46 -0700111
sprangb1ca0732017-02-01 08:38:12 -0800112 void PostTaskAndWait(bool down, AdaptReason reason) {
Niels Möllerc572ff32018-11-07 08:43:50 +0100113 rtc::Event event;
kthelgason876222f2016-11-29 01:44:11 -0800114 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800115 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700116 event.Set();
117 });
perkj070ba852017-02-16 15:46:27 -0800118 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700119 }
120
kthelgason2fc52542017-03-03 00:24:41 -0800121 // This is used as a synchronisation mechanism, to make sure that the
122 // encoder queue is not blocked before we start sending it frames.
123 void WaitUntilTaskQueueIsIdle() {
Niels Möllerc572ff32018-11-07 08:43:50 +0100124 rtc::Event event;
Yves Gerey665174f2018-06-19 15:03:05 +0200125 encoder_queue()->PostTask([&event] { event.Set(); });
kthelgason2fc52542017-03-03 00:24:41 -0800126 ASSERT_TRUE(event.Wait(5000));
127 }
128
sprangb1ca0732017-02-01 08:38:12 -0800129 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800130
sprangb1ca0732017-02-01 08:38:12 -0800131 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800132
sprangb1ca0732017-02-01 08:38:12 -0800133 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800134
sprangb1ca0732017-02-01 08:38:12 -0800135 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700136
Niels Möller7dc26b72017-12-06 10:27:48 +0100137 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700138};
139
asapersson5f7226f2016-11-25 04:37:00 -0800140class VideoStreamFactory
141 : public VideoEncoderConfig::VideoStreamFactoryInterface {
142 public:
sprangfda496a2017-06-15 04:21:07 -0700143 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
144 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800145 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700146 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800147 }
148
149 private:
150 std::vector<VideoStream> CreateEncoderStreams(
151 int width,
152 int height,
153 const VideoEncoderConfig& encoder_config) override {
154 std::vector<VideoStream> streams =
155 test::CreateVideoStreams(width, height, encoder_config);
156 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +0100157 stream.num_temporal_layers = num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700158 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800159 }
160 return streams;
161 }
sprangfda496a2017-06-15 04:21:07 -0700162
asapersson5f7226f2016-11-25 04:37:00 -0800163 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700164 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800165};
166
sprangb1ca0732017-02-01 08:38:12 -0800167class AdaptingFrameForwarder : public test::FrameForwarder {
168 public:
169 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700170 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800171
172 void set_adaptation_enabled(bool enabled) {
173 rtc::CritScope cs(&crit_);
174 adaptation_enabled_ = enabled;
175 }
176
asaperssonfab67072017-04-04 05:51:49 -0700177 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800178 rtc::CritScope cs(&crit_);
179 return adaptation_enabled_;
180 }
181
asapersson09f05612017-05-15 23:40:18 -0700182 rtc::VideoSinkWants last_wants() const {
183 rtc::CritScope cs(&crit_);
184 return last_wants_;
185 }
186
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200187 absl::optional<int> last_sent_width() const { return last_width_; }
188 absl::optional<int> last_sent_height() const { return last_height_; }
Jonathan Yubc771b72017-12-08 17:04:29 -0800189
sprangb1ca0732017-02-01 08:38:12 -0800190 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
191 int cropped_width = 0;
192 int cropped_height = 0;
193 int out_width = 0;
194 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700195 if (adaption_enabled()) {
196 if (adapter_.AdaptFrameResolution(
197 video_frame.width(), video_frame.height(),
198 video_frame.timestamp_us() * 1000, &cropped_width,
199 &cropped_height, &out_width, &out_height)) {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100200 VideoFrame adapted_frame =
201 VideoFrame::Builder()
202 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
203 nullptr, out_width, out_height))
204 .set_timestamp_rtp(99)
205 .set_timestamp_ms(99)
206 .set_rotation(kVideoRotation_0)
207 .build();
sprangc5d62e22017-04-02 23:53:04 -0700208 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
209 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800210 last_width_.emplace(adapted_frame.width());
211 last_height_.emplace(adapted_frame.height());
212 } else {
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200213 last_width_ = absl::nullopt;
214 last_height_ = absl::nullopt;
sprangc5d62e22017-04-02 23:53:04 -0700215 }
sprangb1ca0732017-02-01 08:38:12 -0800216 } else {
217 test::FrameForwarder::IncomingCapturedFrame(video_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800218 last_width_.emplace(video_frame.width());
219 last_height_.emplace(video_frame.height());
sprangb1ca0732017-02-01 08:38:12 -0800220 }
221 }
222
223 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
224 const rtc::VideoSinkWants& wants) override {
225 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700226 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700227 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
228 wants.max_pixel_count,
229 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800230 test::FrameForwarder::AddOrUpdateSink(sink, wants);
231 }
sprangb1ca0732017-02-01 08:38:12 -0800232 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700233 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
234 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200235 absl::optional<int> last_width_;
236 absl::optional<int> last_height_;
sprangb1ca0732017-02-01 08:38:12 -0800237};
sprangc5d62e22017-04-02 23:53:04 -0700238
Niels Möller213618e2018-07-24 09:29:58 +0200239// TODO(nisse): Mock only VideoStreamEncoderObserver.
sprangc5d62e22017-04-02 23:53:04 -0700240class MockableSendStatisticsProxy : public SendStatisticsProxy {
241 public:
242 MockableSendStatisticsProxy(Clock* clock,
243 const VideoSendStream::Config& config,
244 VideoEncoderConfig::ContentType content_type)
245 : SendStatisticsProxy(clock, config, content_type) {}
246
247 VideoSendStream::Stats GetStats() override {
248 rtc::CritScope cs(&lock_);
249 if (mock_stats_)
250 return *mock_stats_;
251 return SendStatisticsProxy::GetStats();
252 }
253
Niels Möller213618e2018-07-24 09:29:58 +0200254 int GetInputFrameRate() const override {
255 rtc::CritScope cs(&lock_);
256 if (mock_stats_)
257 return mock_stats_->input_frame_rate;
258 return SendStatisticsProxy::GetInputFrameRate();
259 }
sprangc5d62e22017-04-02 23:53:04 -0700260 void SetMockStats(const VideoSendStream::Stats& stats) {
261 rtc::CritScope cs(&lock_);
262 mock_stats_.emplace(stats);
263 }
264
265 void ResetMockStats() {
266 rtc::CritScope cs(&lock_);
267 mock_stats_.reset();
268 }
269
270 private:
271 rtc::CriticalSection lock_;
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200272 absl::optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700273};
274
sprang4847ae62017-06-27 07:06:52 -0700275class MockBitrateObserver : public VideoBitrateAllocationObserver {
276 public:
Erik Språng566124a2018-04-23 12:32:22 +0200277 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const VideoBitrateAllocation&));
sprang4847ae62017-06-27 07:06:52 -0700278};
279
perkj803d97f2016-11-01 11:45:46 -0700280} // namespace
281
mflodmancc3d4422017-08-03 08:27:51 -0700282class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700283 public:
284 static const int kDefaultTimeoutMs = 30 * 1000;
285
mflodmancc3d4422017-08-03 08:27:51 -0700286 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700287 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700288 codec_width_(320),
289 codec_height_(240),
Åsa Persson8c1bf952018-09-13 10:42:19 +0200290 max_framerate_(kDefaultFramerate),
perkj26091b12016-09-01 01:17:40 -0700291 fake_encoder_(),
Niels Möller4db138e2018-04-19 09:04:13 +0200292 encoder_factory_(&fake_encoder_),
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800293 bitrate_allocator_factory_(CreateBuiltinVideoBitrateAllocatorFactory()),
sprangc5d62e22017-04-02 23:53:04 -0700294 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700295 Clock::GetRealTimeClock(),
296 video_send_config_,
297 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700298 sink_(&fake_encoder_) {}
299
300 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700301 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700302 video_send_config_ = VideoSendStream::Config(nullptr);
Niels Möller4db138e2018-04-19 09:04:13 +0200303 video_send_config_.encoder_settings.encoder_factory = &encoder_factory_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800304 video_send_config_.encoder_settings.bitrate_allocator_factory =
305 bitrate_allocator_factory_.get();
Niels Möller259a4972018-04-05 15:36:51 +0200306 video_send_config_.rtp.payload_name = "FAKE";
307 video_send_config_.rtp.payload_type = 125;
perkj26091b12016-09-01 01:17:40 -0700308
Per512ecb32016-09-23 15:52:06 +0200309 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200310 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700311 video_encoder_config.video_stream_factory =
312 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100313 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700314
315 // Framerate limit is specified by the VideoStreamFactory.
316 std::vector<VideoStream> streams =
317 video_encoder_config.video_stream_factory->CreateEncoderStreams(
318 codec_width_, codec_height_, video_encoder_config);
319 max_framerate_ = streams[0].max_framerate;
320 fake_clock_.SetTimeMicros(1234);
321
Niels Möllerf1338562018-04-26 09:51:47 +0200322 ConfigureEncoder(std::move(video_encoder_config));
asapersson5f7226f2016-11-25 04:37:00 -0800323 }
324
Niels Möllerf1338562018-04-26 09:51:47 +0200325 void ConfigureEncoder(VideoEncoderConfig video_encoder_config) {
mflodmancc3d4422017-08-03 08:27:51 -0700326 if (video_stream_encoder_)
327 video_stream_encoder_->Stop();
328 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700329 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700330 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
331 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700332 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -0700333 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
334 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200335 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -0700336 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800337 }
338
339 void ResetEncoder(const std::string& payload_name,
340 size_t num_streams,
341 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700342 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700343 bool screenshare) {
Niels Möller259a4972018-04-05 15:36:51 +0200344 video_send_config_.rtp.payload_name = payload_name;
asapersson5f7226f2016-11-25 04:37:00 -0800345
346 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200347 video_encoder_config.codec_type = PayloadStringToCodecType(payload_name);
asapersson5f7226f2016-11-25 04:37:00 -0800348 video_encoder_config.number_of_streams = num_streams;
Erik Språngd7329ca2019-02-21 21:19:53 +0100349 video_encoder_config.max_bitrate_bps =
350 num_streams == 1 ? kTargetBitrateBps : kSimulcastTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800351 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700352 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
353 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700354 video_encoder_config.content_type =
355 screenshare ? VideoEncoderConfig::ContentType::kScreen
356 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700357 if (payload_name == "VP9") {
358 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
359 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
360 video_encoder_config.encoder_specific_settings =
361 new rtc::RefCountedObject<
362 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
363 }
Niels Möllerf1338562018-04-26 09:51:47 +0200364 ConfigureEncoder(std::move(video_encoder_config));
perkj26091b12016-09-01 01:17:40 -0700365 }
366
sprang57c2fff2017-01-16 06:24:02 -0800367 VideoFrame CreateFrame(int64_t ntp_time_ms,
368 rtc::Event* destruction_event) const {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100369 VideoFrame frame =
370 VideoFrame::Builder()
371 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
372 destruction_event, codec_width_, codec_height_))
373 .set_timestamp_rtp(99)
374 .set_timestamp_ms(99)
375 .set_rotation(kVideoRotation_0)
376 .build();
sprang57c2fff2017-01-16 06:24:02 -0800377 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700378 return frame;
379 }
380
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100381 VideoFrame CreateFrameWithUpdatedPixel(int64_t ntp_time_ms,
382 rtc::Event* destruction_event,
383 int offset_x) const {
384 VideoFrame frame =
385 VideoFrame::Builder()
386 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
387 destruction_event, codec_width_, codec_height_))
388 .set_timestamp_rtp(99)
389 .set_timestamp_ms(99)
390 .set_rotation(kVideoRotation_0)
391 .set_update_rect({offset_x, 0, 1, 1})
392 .build();
393 frame.set_ntp_time_ms(ntp_time_ms);
394 return frame;
395 }
396
sprang57c2fff2017-01-16 06:24:02 -0800397 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100398 VideoFrame frame =
399 VideoFrame::Builder()
400 .set_video_frame_buffer(
401 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height))
402 .set_timestamp_rtp(99)
403 .set_timestamp_ms(99)
404 .set_rotation(kVideoRotation_0)
405 .build();
sprang57c2fff2017-01-16 06:24:02 -0800406 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700407 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700408 return frame;
409 }
410
Åsa Perssonc29cb2c2019-03-25 12:06:59 +0100411 void VerifyAllocatedBitrate(const VideoBitrateAllocation& expected_bitrate) {
412 MockBitrateObserver bitrate_observer;
413 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
414
415 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
416 .Times(1);
417 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
Erik Språng4c6ca302019-04-08 15:14:01 +0200418 DataRate::bps(kTargetBitrateBps), 0,
419 0);
Åsa Perssonc29cb2c2019-03-25 12:06:59 +0100420
421 video_source_.IncomingCapturedFrame(
422 CreateFrame(1, codec_width_, codec_height_));
423 WaitForEncodedFrame(1);
424 }
425
asapersson02465b82017-04-10 01:12:52 -0700426 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700427 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700428 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
asapersson09f05612017-05-15 23:40:18 -0700432 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
433 const rtc::VideoSinkWants& wants2) {
434 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
435 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
436 }
437
Åsa Persson8c1bf952018-09-13 10:42:19 +0200438 void VerifyFpsMaxResolutionMax(const rtc::VideoSinkWants& wants) {
439 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
440 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
441 EXPECT_FALSE(wants.target_pixel_count);
442 }
443
asapersson09f05612017-05-15 23:40:18 -0700444 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
445 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200446 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700447 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
448 EXPECT_GT(wants1.max_pixel_count, 0);
449 }
450
451 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
452 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200453 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700454 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
455 }
456
asaperssonf7e294d2017-06-13 23:25:22 -0700457 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
458 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200459 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700460 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
461 }
462
463 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
464 const rtc::VideoSinkWants& wants2) {
465 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
466 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
467 }
468
469 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
470 const rtc::VideoSinkWants& wants2) {
471 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
472 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
473 }
474
475 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
476 const rtc::VideoSinkWants& wants2) {
477 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
478 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
479 EXPECT_GT(wants1.max_pixel_count, 0);
480 }
481
482 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
483 const rtc::VideoSinkWants& wants2) {
484 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
485 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
486 }
487
asapersson09f05612017-05-15 23:40:18 -0700488 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
489 int pixel_count) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200490 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700491 EXPECT_LT(wants.max_pixel_count, pixel_count);
492 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700493 }
494
495 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
496 EXPECT_LT(wants.max_framerate_fps, fps);
497 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
498 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700499 }
500
asaperssonf7e294d2017-06-13 23:25:22 -0700501 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
502 int expected_fps) {
503 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
504 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
505 EXPECT_FALSE(wants.target_pixel_count);
506 }
507
Jonathan Yubc771b72017-12-08 17:04:29 -0800508 void VerifyBalancedModeFpsRange(const rtc::VideoSinkWants& wants,
509 int last_frame_pixels) {
510 // Balanced mode should always scale FPS to the desired range before
511 // attempting to scale resolution.
512 int fps_limit = wants.max_framerate_fps;
513 if (last_frame_pixels <= 320 * 240) {
514 EXPECT_TRUE(7 <= fps_limit && fps_limit <= 10);
515 } else if (last_frame_pixels <= 480 * 270) {
516 EXPECT_TRUE(10 <= fps_limit && fps_limit <= 15);
517 } else if (last_frame_pixels <= 640 * 480) {
518 EXPECT_LE(15, fps_limit);
519 } else {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200520 EXPECT_EQ(kDefaultFramerate, fps_limit);
Jonathan Yubc771b72017-12-08 17:04:29 -0800521 }
522 }
523
sprang4847ae62017-06-27 07:06:52 -0700524 void WaitForEncodedFrame(int64_t expected_ntp_time) {
525 sink_.WaitForEncodedFrame(expected_ntp_time);
526 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
527 }
528
529 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
530 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
531 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
532 return ok;
533 }
534
535 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
536 sink_.WaitForEncodedFrame(expected_width, expected_height);
537 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
538 }
539
540 void ExpectDroppedFrame() {
541 sink_.ExpectDroppedFrame();
542 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
543 }
544
545 bool WaitForFrame(int64_t timeout_ms) {
546 bool ok = sink_.WaitForFrame(timeout_ms);
547 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
548 return ok;
549 }
550
perkj26091b12016-09-01 01:17:40 -0700551 class TestEncoder : public test::FakeEncoder {
552 public:
Niels Möllerc572ff32018-11-07 08:43:50 +0100553 TestEncoder() : FakeEncoder(Clock::GetRealTimeClock()) {}
perkj26091b12016-09-01 01:17:40 -0700554
asaperssonfab67072017-04-04 05:51:49 -0700555 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800556 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700557 return config_;
558 }
559
560 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800561 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700562 block_next_encode_ = true;
563 }
564
Erik Språngaed30702018-11-05 12:57:17 +0100565 VideoEncoder::EncoderInfo GetEncoderInfo() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800566 rtc::CritScope lock(&local_crit_sect_);
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100567 EncoderInfo info;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100568 if (initialized_ == EncoderState::kInitialized) {
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100569 if (quality_scaling_) {
570 info.scaling_settings =
571 VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
572 }
573 info.is_hardware_accelerated = is_hardware_accelerated_;
Åsa Perssonc29cb2c2019-03-25 12:06:59 +0100574 for (int i = 0; i < kMaxSpatialLayers; ++i) {
575 if (temporal_layers_supported_[i]) {
576 int num_layers = temporal_layers_supported_[i].value() ? 2 : 1;
577 info.fps_allocation[i].resize(num_layers);
578 }
579 }
Erik Språngaed30702018-11-05 12:57:17 +0100580 }
581 return info;
kthelgason876222f2016-11-29 01:44:11 -0800582 }
583
Erik Språngb7cb7b52019-02-26 15:52:33 +0100584 int32_t RegisterEncodeCompleteCallback(
585 EncodedImageCallback* callback) override {
586 rtc::CritScope lock(&local_crit_sect_);
587 encoded_image_callback_ = callback;
588 return FakeEncoder::RegisterEncodeCompleteCallback(callback);
589 }
590
perkjfa10b552016-10-02 23:45:26 -0700591 void ContinueEncode() { continue_encode_event_.Set(); }
592
593 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
594 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800595 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700596 EXPECT_EQ(timestamp_, timestamp);
597 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
598 }
599
kthelgason2fc52542017-03-03 00:24:41 -0800600 void SetQualityScaling(bool b) {
601 rtc::CritScope lock(&local_crit_sect_);
602 quality_scaling_ = b;
603 }
kthelgasonad9010c2017-02-14 00:46:51 -0800604
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100605 void SetIsHardwareAccelerated(bool is_hardware_accelerated) {
606 rtc::CritScope lock(&local_crit_sect_);
607 is_hardware_accelerated_ = is_hardware_accelerated;
608 }
609
Åsa Perssonc29cb2c2019-03-25 12:06:59 +0100610 void SetTemporalLayersSupported(size_t spatial_idx, bool supported) {
611 RTC_DCHECK_LT(spatial_idx, kMaxSpatialLayers);
612 rtc::CritScope lock(&local_crit_sect_);
613 temporal_layers_supported_[spatial_idx] = supported;
614 }
615
sprangfe627f32017-03-29 08:24:59 -0700616 void ForceInitEncodeFailure(bool force_failure) {
617 rtc::CritScope lock(&local_crit_sect_);
618 force_init_encode_failed_ = force_failure;
619 }
620
Niels Möller6bb5ab92019-01-11 11:11:10 +0100621 void SimulateOvershoot(double rate_factor) {
622 rtc::CritScope lock(&local_crit_sect_);
623 rate_factor_ = rate_factor;
624 }
625
Erik Språngd7329ca2019-02-21 21:19:53 +0100626 uint32_t GetLastFramerate() const {
Niels Möller6bb5ab92019-01-11 11:11:10 +0100627 rtc::CritScope lock(&local_crit_sect_);
628 return last_framerate_;
629 }
630
Erik Språngd7329ca2019-02-21 21:19:53 +0100631 VideoFrame::UpdateRect GetLastUpdateRect() const {
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100632 rtc::CritScope lock(&local_crit_sect_);
633 return last_update_rect_;
634 }
635
Niels Möller87e2d782019-03-07 10:18:23 +0100636 const std::vector<VideoFrameType>& LastFrameTypes() const {
Erik Språngd7329ca2019-02-21 21:19:53 +0100637 rtc::CritScope lock(&local_crit_sect_);
638 return last_frame_types_;
639 }
640
641 void InjectFrame(const VideoFrame& input_image, bool keyframe) {
Niels Möller87e2d782019-03-07 10:18:23 +0100642 const std::vector<VideoFrameType> frame_type = {
Niels Möller8f7ce222019-03-21 15:43:58 +0100643 keyframe ? VideoFrameType::kVideoFrameKey
644 : VideoFrameType::kVideoFrameDelta};
Erik Språngd7329ca2019-02-21 21:19:53 +0100645 {
646 rtc::CritScope lock(&local_crit_sect_);
647 last_frame_types_ = frame_type;
648 }
Niels Möllerb859b322019-03-07 12:40:01 +0100649 FakeEncoder::Encode(input_image, &frame_type);
Erik Språngd7329ca2019-02-21 21:19:53 +0100650 }
651
Erik Språngb7cb7b52019-02-26 15:52:33 +0100652 void InjectEncodedImage(const EncodedImage& image) {
653 rtc::CritScope lock(&local_crit_sect_);
654 encoded_image_callback_->OnEncodedImage(image, nullptr, nullptr);
655 }
656
Erik Språngd7329ca2019-02-21 21:19:53 +0100657 void ExpectNullFrame() {
658 rtc::CritScope lock(&local_crit_sect_);
659 expect_null_frame_ = true;
660 }
661
662 absl::optional<VideoBitrateAllocation> GetAndResetLastBitrateAllocation() {
663 auto allocation = last_bitrate_allocation_;
664 last_bitrate_allocation_.reset();
665 return allocation;
666 }
667
perkjfa10b552016-10-02 23:45:26 -0700668 private:
perkj26091b12016-09-01 01:17:40 -0700669 int32_t Encode(const VideoFrame& input_image,
Niels Möller87e2d782019-03-07 10:18:23 +0100670 const std::vector<VideoFrameType>* frame_types) override {
perkj26091b12016-09-01 01:17:40 -0700671 bool block_encode;
672 {
brandtre78d2662017-01-16 05:57:16 -0800673 rtc::CritScope lock(&local_crit_sect_);
Erik Språngd7329ca2019-02-21 21:19:53 +0100674 if (expect_null_frame_) {
675 EXPECT_EQ(input_image.timestamp(), 0u);
676 EXPECT_EQ(input_image.width(), 1);
677 last_frame_types_ = *frame_types;
678 expect_null_frame_ = false;
679 } else {
680 EXPECT_GT(input_image.timestamp(), timestamp_);
681 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
682 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
683 }
perkj26091b12016-09-01 01:17:40 -0700684
685 timestamp_ = input_image.timestamp();
686 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700687 last_input_width_ = input_image.width();
688 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700689 block_encode = block_next_encode_;
690 block_next_encode_ = false;
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100691 last_update_rect_ = input_image.update_rect();
Erik Språngd7329ca2019-02-21 21:19:53 +0100692 last_frame_types_ = *frame_types;
perkj26091b12016-09-01 01:17:40 -0700693 }
Niels Möllerb859b322019-03-07 12:40:01 +0100694 int32_t result = FakeEncoder::Encode(input_image, frame_types);
perkj26091b12016-09-01 01:17:40 -0700695 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700696 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700697 return result;
698 }
699
sprangfe627f32017-03-29 08:24:59 -0700700 int32_t InitEncode(const VideoCodec* config,
701 int32_t number_of_cores,
702 size_t max_payload_size) override {
703 int res =
704 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
705 rtc::CritScope lock(&local_crit_sect_);
Erik Språngb7cb7b52019-02-26 15:52:33 +0100706 EXPECT_EQ(initialized_, EncoderState::kUninitialized);
Erik Språng82fad3d2018-03-21 09:57:23 +0100707 if (config->codecType == kVideoCodecVP8) {
sprangfe627f32017-03-29 08:24:59 -0700708 // Simulate setting up temporal layers, in order to validate the life
709 // cycle of these objects.
Elad Aloncde8ab22019-03-20 11:56:20 +0100710 Vp8TemporalLayersFactory factory;
711 frame_buffer_controller_ = factory.Create(*config);
sprangfe627f32017-03-29 08:24:59 -0700712 }
Erik Språngb7cb7b52019-02-26 15:52:33 +0100713 if (force_init_encode_failed_) {
714 initialized_ = EncoderState::kInitializationFailed;
sprangfe627f32017-03-29 08:24:59 -0700715 return -1;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100716 }
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100717
Erik Språngb7cb7b52019-02-26 15:52:33 +0100718 initialized_ = EncoderState::kInitialized;
sprangfe627f32017-03-29 08:24:59 -0700719 return res;
720 }
721
Erik Språngb7cb7b52019-02-26 15:52:33 +0100722 int32_t Release() override {
723 rtc::CritScope lock(&local_crit_sect_);
724 EXPECT_NE(initialized_, EncoderState::kUninitialized);
725 initialized_ = EncoderState::kUninitialized;
726 return FakeEncoder::Release();
727 }
728
Niels Möller6bb5ab92019-01-11 11:11:10 +0100729 int32_t SetRateAllocation(const VideoBitrateAllocation& rate_allocation,
730 uint32_t framerate) {
731 rtc::CritScope lock(&local_crit_sect_);
732 VideoBitrateAllocation adjusted_rate_allocation;
733 for (size_t si = 0; si < kMaxSpatialLayers; ++si) {
734 for (size_t ti = 0; ti < kMaxTemporalStreams; ++ti) {
735 if (rate_allocation.HasBitrate(si, ti)) {
736 adjusted_rate_allocation.SetBitrate(
737 si, ti,
738 static_cast<uint32_t>(rate_allocation.GetBitrate(si, ti) *
739 rate_factor_));
740 }
741 }
742 }
743 last_framerate_ = framerate;
Erik Språngd7329ca2019-02-21 21:19:53 +0100744 last_bitrate_allocation_ = rate_allocation;
Niels Möller6bb5ab92019-01-11 11:11:10 +0100745 return FakeEncoder::SetRateAllocation(adjusted_rate_allocation,
746 framerate);
747 }
748
brandtre78d2662017-01-16 05:57:16 -0800749 rtc::CriticalSection local_crit_sect_;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100750 enum class EncoderState {
751 kUninitialized,
752 kInitializationFailed,
753 kInitialized
754 } initialized_ RTC_GUARDED_BY(local_crit_sect_) =
755 EncoderState::kUninitialized;
danilchapa37de392017-09-09 04:17:22 -0700756 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700757 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700758 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
759 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
760 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
761 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
762 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100763 bool is_hardware_accelerated_ RTC_GUARDED_BY(local_crit_sect_) = false;
Elad Aloncde8ab22019-03-20 11:56:20 +0100764 std::unique_ptr<Vp8FrameBufferController> frame_buffer_controller_
danilchapa37de392017-09-09 04:17:22 -0700765 RTC_GUARDED_BY(local_crit_sect_);
Åsa Perssonc29cb2c2019-03-25 12:06:59 +0100766 absl::optional<bool>
767 temporal_layers_supported_[kMaxSpatialLayers] RTC_GUARDED_BY(
768 local_crit_sect_);
danilchapa37de392017-09-09 04:17:22 -0700769 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
Niels Möller6bb5ab92019-01-11 11:11:10 +0100770 double rate_factor_ RTC_GUARDED_BY(local_crit_sect_) = 1.0;
771 uint32_t last_framerate_ RTC_GUARDED_BY(local_crit_sect_) = 0;
Erik Språngd7329ca2019-02-21 21:19:53 +0100772 absl::optional<VideoBitrateAllocation> last_bitrate_allocation_;
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100773 VideoFrame::UpdateRect last_update_rect_
774 RTC_GUARDED_BY(local_crit_sect_) = {0, 0, 0, 0};
Niels Möller87e2d782019-03-07 10:18:23 +0100775 std::vector<VideoFrameType> last_frame_types_;
Erik Språngd7329ca2019-02-21 21:19:53 +0100776 bool expect_null_frame_ = false;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100777 EncodedImageCallback* encoded_image_callback_
778 RTC_GUARDED_BY(local_crit_sect_) = nullptr;
perkj26091b12016-09-01 01:17:40 -0700779 };
780
mflodmancc3d4422017-08-03 08:27:51 -0700781 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700782 public:
783 explicit TestSink(TestEncoder* test_encoder)
Niels Möllerc572ff32018-11-07 08:43:50 +0100784 : test_encoder_(test_encoder) {}
perkj26091b12016-09-01 01:17:40 -0700785
perkj26091b12016-09-01 01:17:40 -0700786 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700787 EXPECT_TRUE(
788 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
789 }
790
791 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
792 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700793 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700794 if (!encoded_frame_event_.Wait(timeout_ms))
795 return false;
perkj26091b12016-09-01 01:17:40 -0700796 {
797 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800798 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700799 }
800 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700801 return true;
perkj26091b12016-09-01 01:17:40 -0700802 }
803
sprangb1ca0732017-02-01 08:38:12 -0800804 void WaitForEncodedFrame(uint32_t expected_width,
805 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700806 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100807 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700808 }
809
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100810 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700811 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800812 uint32_t width = 0;
813 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800814 {
815 rtc::CritScope lock(&crit_);
816 width = last_width_;
817 height = last_height_;
818 }
819 EXPECT_EQ(expected_height, height);
820 EXPECT_EQ(expected_width, width);
821 }
822
kthelgason2fc52542017-03-03 00:24:41 -0800823 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800824
sprangc5d62e22017-04-02 23:53:04 -0700825 bool WaitForFrame(int64_t timeout_ms) {
826 return encoded_frame_event_.Wait(timeout_ms);
827 }
828
perkj26091b12016-09-01 01:17:40 -0700829 void SetExpectNoFrames() {
830 rtc::CritScope lock(&crit_);
831 expect_frames_ = false;
832 }
833
asaperssonfab67072017-04-04 05:51:49 -0700834 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200835 rtc::CritScope lock(&crit_);
836 return number_of_reconfigurations_;
837 }
838
asaperssonfab67072017-04-04 05:51:49 -0700839 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200840 rtc::CritScope lock(&crit_);
841 return min_transmit_bitrate_bps_;
842 }
843
Erik Språngd7329ca2019-02-21 21:19:53 +0100844 void SetNumExpectedLayers(size_t num_layers) {
845 rtc::CritScope lock(&crit_);
846 num_expected_layers_ = num_layers;
847 }
848
Erik Språngb7cb7b52019-02-26 15:52:33 +0100849 int64_t GetLastCaptureTimeMs() const {
850 rtc::CritScope lock(&crit_);
851 return last_capture_time_ms_;
852 }
853
perkj26091b12016-09-01 01:17:40 -0700854 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700855 Result OnEncodedImage(
856 const EncodedImage& encoded_image,
857 const CodecSpecificInfo* codec_specific_info,
858 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200859 rtc::CritScope lock(&crit_);
860 EXPECT_TRUE(expect_frames_);
Erik Språngd7329ca2019-02-21 21:19:53 +0100861 uint32_t timestamp = encoded_image.Timestamp();
862 if (last_timestamp_ != timestamp) {
863 num_received_layers_ = 1;
864 } else {
865 ++num_received_layers_;
866 }
867 last_timestamp_ = timestamp;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100868 last_capture_time_ms_ = encoded_image.capture_time_ms_;
sprangb1ca0732017-02-01 08:38:12 -0800869 last_width_ = encoded_image._encodedWidth;
870 last_height_ = encoded_image._encodedHeight;
Erik Språngd7329ca2019-02-21 21:19:53 +0100871 if (num_received_layers_ == num_expected_layers_) {
872 encoded_frame_event_.Set();
873 }
sprangb1ca0732017-02-01 08:38:12 -0800874 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200875 }
876
Rasmus Brandtc402dbe2019-02-04 11:09:46 +0100877 void OnEncoderConfigurationChanged(
878 std::vector<VideoStream> streams,
879 VideoEncoderConfig::ContentType content_type,
880 int min_transmit_bitrate_bps) override {
Per512ecb32016-09-23 15:52:06 +0200881 rtc::CriticalSection crit_;
882 ++number_of_reconfigurations_;
883 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
884 }
885
perkj26091b12016-09-01 01:17:40 -0700886 rtc::CriticalSection crit_;
887 TestEncoder* test_encoder_;
888 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800889 uint32_t last_timestamp_ = 0;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100890 int64_t last_capture_time_ms_ = 0;
sprangb1ca0732017-02-01 08:38:12 -0800891 uint32_t last_height_ = 0;
892 uint32_t last_width_ = 0;
Erik Språngd7329ca2019-02-21 21:19:53 +0100893 size_t num_expected_layers_ = 1;
894 size_t num_received_layers_ = 0;
perkj26091b12016-09-01 01:17:40 -0700895 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200896 int number_of_reconfigurations_ = 0;
897 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700898 };
899
900 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100901 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200902 int codec_width_;
903 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700904 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700905 TestEncoder fake_encoder_;
Niels Möllercbcbc222018-09-28 09:07:24 +0200906 test::VideoEncoderProxyFactory encoder_factory_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800907 std::unique_ptr<VideoBitrateAllocatorFactory> bitrate_allocator_factory_;
sprangc5d62e22017-04-02 23:53:04 -0700908 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700909 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800910 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700911 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700912 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700913};
914
mflodmancc3d4422017-08-03 08:27:51 -0700915TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
Erik Språng4c6ca302019-04-08 15:14:01 +0200916 video_stream_encoder_->OnBitrateUpdated(
917 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möllerc572ff32018-11-07 08:43:50 +0100918 rtc::Event frame_destroyed_event;
perkja49cbd32016-09-16 07:53:41 -0700919 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700920 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700921 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700922 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700923}
924
mflodmancc3d4422017-08-03 08:27:51 -0700925TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700926 // Dropped since no target bitrate has been set.
Niels Möllerc572ff32018-11-07 08:43:50 +0100927 rtc::Event frame_destroyed_event;
Sebastian Janssona3177052018-04-10 13:05:49 +0200928 // The encoder will cache up to one frame for a short duration. Adding two
929 // frames means that the first frame will be dropped and the second frame will
930 // be sent when the encoder is enabled.
perkja49cbd32016-09-16 07:53:41 -0700931 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
Sebastian Janssona3177052018-04-10 13:05:49 +0200932 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkja49cbd32016-09-16 07:53:41 -0700933 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700934
Erik Språng4c6ca302019-04-08 15:14:01 +0200935 video_stream_encoder_->OnBitrateUpdated(
936 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkj26091b12016-09-01 01:17:40 -0700937
Sebastian Janssona3177052018-04-10 13:05:49 +0200938 // The pending frame should be received.
sprang4847ae62017-06-27 07:06:52 -0700939 WaitForEncodedFrame(2);
Sebastian Janssona3177052018-04-10 13:05:49 +0200940 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
941
942 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700943 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700944}
945
mflodmancc3d4422017-08-03 08:27:51 -0700946TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
Erik Språng4c6ca302019-04-08 15:14:01 +0200947 video_stream_encoder_->OnBitrateUpdated(
948 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700949 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700950 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700951
Erik Språng4c6ca302019-04-08 15:14:01 +0200952 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(0), DataRate::bps(0), 0,
Erik Språng610c7632019-03-06 15:37:33 +0100953 0);
Sebastian Janssona3177052018-04-10 13:05:49 +0200954 // The encoder will cache up to one frame for a short duration. Adding two
955 // frames means that the first frame will be dropped and the second frame will
956 // be sent when the encoder is resumed.
perkja49cbd32016-09-16 07:53:41 -0700957 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Sebastian Janssona3177052018-04-10 13:05:49 +0200958 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700959
Erik Språng4c6ca302019-04-08 15:14:01 +0200960 video_stream_encoder_->OnBitrateUpdated(
961 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
sprang4847ae62017-06-27 07:06:52 -0700962 WaitForEncodedFrame(3);
Sebastian Janssona3177052018-04-10 13:05:49 +0200963 video_source_.IncomingCapturedFrame(CreateFrame(4, nullptr));
964 WaitForEncodedFrame(4);
mflodmancc3d4422017-08-03 08:27:51 -0700965 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700966}
967
mflodmancc3d4422017-08-03 08:27:51 -0700968TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
Erik Språng4c6ca302019-04-08 15:14:01 +0200969 video_stream_encoder_->OnBitrateUpdated(
970 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700971 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700972 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700973
974 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700975 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700976
perkja49cbd32016-09-16 07:53:41 -0700977 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700978 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700979 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700980}
981
mflodmancc3d4422017-08-03 08:27:51 -0700982TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
Erik Språng4c6ca302019-04-08 15:14:01 +0200983 video_stream_encoder_->OnBitrateUpdated(
984 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkj26091b12016-09-01 01:17:40 -0700985
perkja49cbd32016-09-16 07:53:41 -0700986 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700987 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700988
mflodmancc3d4422017-08-03 08:27:51 -0700989 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700990 sink_.SetExpectNoFrames();
Niels Möllerc572ff32018-11-07 08:43:50 +0100991 rtc::Event frame_destroyed_event;
perkja49cbd32016-09-16 07:53:41 -0700992 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
993 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700994}
995
mflodmancc3d4422017-08-03 08:27:51 -0700996TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
Erik Språng4c6ca302019-04-08 15:14:01 +0200997 video_stream_encoder_->OnBitrateUpdated(
998 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkj26091b12016-09-01 01:17:40 -0700999
1000 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -07001001 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001002 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -07001003 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
1004 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -07001005 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
1006 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -07001007 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -07001008 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -07001009
mflodmancc3d4422017-08-03 08:27:51 -07001010 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -07001011}
1012
mflodmancc3d4422017-08-03 08:27:51 -07001013TEST_F(VideoStreamEncoderTest,
1014 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001015 video_stream_encoder_->OnBitrateUpdated(
1016 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Per21d45d22016-10-30 21:37:57 +01001017 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +02001018
1019 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +02001020 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001021 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +01001022 // The encoder will have been configured once when the first frame is
1023 // received.
1024 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +02001025
1026 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02001027 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +02001028 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -07001029 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001030 kMaxPayloadLength);
Per512ecb32016-09-23 15:52:06 +02001031
1032 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +02001033 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001034 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +01001035 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -07001036 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -07001037
mflodmancc3d4422017-08-03 08:27:51 -07001038 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -07001039}
1040
mflodmancc3d4422017-08-03 08:27:51 -07001041TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001042 video_stream_encoder_->OnBitrateUpdated(
1043 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkjfa10b552016-10-02 23:45:26 -07001044
1045 // Capture a frame and wait for it to synchronize with the encoder thread.
1046 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001047 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +01001048 // The encoder will have been configured once.
1049 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -07001050 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
1051 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
1052
1053 codec_width_ *= 2;
1054 codec_height_ *= 2;
1055 // Capture a frame with a higher resolution and wait for it to synchronize
1056 // with the encoder thread.
1057 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001058 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -07001059 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
1060 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +01001061 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -07001062
mflodmancc3d4422017-08-03 08:27:51 -07001063 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -07001064}
1065
mflodmancc3d4422017-08-03 08:27:51 -07001066TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -07001067 EXPECT_TRUE(video_source_.has_sinks());
1068 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001069 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001070 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001071 EXPECT_FALSE(video_source_.has_sinks());
1072 EXPECT_TRUE(new_video_source.has_sinks());
1073
mflodmancc3d4422017-08-03 08:27:51 -07001074 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001075}
1076
mflodmancc3d4422017-08-03 08:27:51 -07001077TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -07001078 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -07001079 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -07001080 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -07001081 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001082}
1083
Jonathan Yubc771b72017-12-08 17:04:29 -08001084TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
1085 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -07001086 const int kWidth = 1280;
1087 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -08001088
1089 // We rely on the automatic resolution adaptation, but we handle framerate
1090 // adaptation manually by mocking the stats proxy.
1091 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -07001092
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001093 // Enable BALANCED preference, no initial limitation.
Erik Språng4c6ca302019-04-08 15:14:01 +02001094 video_stream_encoder_->OnBitrateUpdated(
1095 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001096 video_stream_encoder_->SetSource(&video_source_,
1097 webrtc::DegradationPreference::BALANCED);
Jonathan Yubc771b72017-12-08 17:04:29 -08001098 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001099 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001100 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -07001101 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1102
Jonathan Yubc771b72017-12-08 17:04:29 -08001103 // Adapt down as far as possible.
1104 rtc::VideoSinkWants last_wants;
1105 int64_t t = 1;
1106 int loop_count = 0;
1107 do {
1108 ++loop_count;
1109 last_wants = video_source_.sink_wants();
1110
1111 // Simulate the framerate we've been asked to adapt to.
1112 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
1113 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
1114 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1115 mock_stats.input_frame_rate = fps;
1116 stats_proxy_->SetMockStats(mock_stats);
1117
1118 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1119 sink_.WaitForEncodedFrame(t);
1120 t += frame_interval_ms;
1121
mflodmancc3d4422017-08-03 08:27:51 -07001122 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08001123 VerifyBalancedModeFpsRange(
1124 video_source_.sink_wants(),
1125 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1126 } while (video_source_.sink_wants().max_pixel_count <
1127 last_wants.max_pixel_count ||
1128 video_source_.sink_wants().max_framerate_fps <
1129 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001130
Jonathan Yubc771b72017-12-08 17:04:29 -08001131 // Verify that we've adapted all the way down.
1132 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001133 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001134 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
1135 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -07001136 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -08001137 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
1138 *video_source_.last_sent_height());
1139 EXPECT_EQ(kMinBalancedFramerateFps,
1140 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001141
Jonathan Yubc771b72017-12-08 17:04:29 -08001142 // Adapt back up the same number of times we adapted down.
1143 for (int i = 0; i < loop_count - 1; ++i) {
1144 last_wants = video_source_.sink_wants();
1145
1146 // Simulate the framerate we've been asked to adapt to.
1147 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
1148 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
1149 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1150 mock_stats.input_frame_rate = fps;
1151 stats_proxy_->SetMockStats(mock_stats);
1152
1153 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1154 sink_.WaitForEncodedFrame(t);
1155 t += frame_interval_ms;
1156
mflodmancc3d4422017-08-03 08:27:51 -07001157 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -08001158 VerifyBalancedModeFpsRange(
1159 video_source_.sink_wants(),
1160 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1161 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
1162 last_wants.max_pixel_count ||
1163 video_source_.sink_wants().max_framerate_fps >
1164 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001165 }
1166
Åsa Persson8c1bf952018-09-13 10:42:19 +02001167 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001168 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001169 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001170 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1171 EXPECT_EQ((loop_count - 1) * 2,
1172 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -07001173
mflodmancc3d4422017-08-03 08:27:51 -07001174 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001175}
mflodmancc3d4422017-08-03 08:27:51 -07001176TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001177 video_stream_encoder_->OnBitrateUpdated(
1178 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001179 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001180
sprangc5d62e22017-04-02 23:53:04 -07001181 const int kFrameWidth = 1280;
1182 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07001183
Åsa Persson8c1bf952018-09-13 10:42:19 +02001184 int64_t frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -07001185
kthelgason5e13d412016-12-01 03:59:51 -08001186 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001187 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001188 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001189 frame_timestamp += kFrameIntervalMs;
1190
perkj803d97f2016-11-01 11:45:46 -07001191 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001192 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001193 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001194 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001195 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001196 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -07001197
asapersson0944a802017-04-07 00:57:58 -07001198 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -07001199 // wanted resolution.
1200 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
1201 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
1202 kFrameWidth * kFrameHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001203 EXPECT_EQ(kDefaultFramerate, video_source_.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001204
1205 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -07001206 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001207 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001208 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001209
sprangc5d62e22017-04-02 23:53:04 -07001210 // Initially no degradation registered.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001211 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001212
sprangc5d62e22017-04-02 23:53:04 -07001213 // Force an input frame rate to be available, or the adaptation call won't
1214 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -07001215 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -07001216 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -07001217 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -07001218 stats_proxy_->SetMockStats(stats);
1219
mflodmancc3d4422017-08-03 08:27:51 -07001220 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001221 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001222 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001223 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001224 frame_timestamp += kFrameIntervalMs;
1225
1226 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001227 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001228 EXPECT_EQ(std::numeric_limits<int>::max(),
1229 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001230 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001231
asapersson02465b82017-04-10 01:12:52 -07001232 // Turn off degradation completely.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001233 video_stream_encoder_->SetSource(&new_video_source,
1234 webrtc::DegradationPreference::DISABLED);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001235 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001236
mflodmancc3d4422017-08-03 08:27:51 -07001237 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001238 new_video_source.IncomingCapturedFrame(
1239 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001240 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001241 frame_timestamp += kFrameIntervalMs;
1242
1243 // Still no degradation.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001244 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001245
1246 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001247 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001248 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
sprangc5d62e22017-04-02 23:53:04 -07001249 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1250 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001251 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001252 EXPECT_EQ(kDefaultFramerate, new_video_source.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001253
1254 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001255 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001256 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001257 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1258 EXPECT_EQ(std::numeric_limits<int>::max(),
1259 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001260 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001261
mflodmancc3d4422017-08-03 08:27:51 -07001262 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001263}
1264
mflodmancc3d4422017-08-03 08:27:51 -07001265TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001266 video_stream_encoder_->OnBitrateUpdated(
1267 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001268
asaperssonfab67072017-04-04 05:51:49 -07001269 const int kWidth = 1280;
1270 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001271 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001272 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001273 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1274 EXPECT_FALSE(stats.bw_limited_resolution);
1275 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1276
1277 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001278 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001279 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001280 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001281
1282 stats = stats_proxy_->GetStats();
1283 EXPECT_TRUE(stats.bw_limited_resolution);
1284 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1285
1286 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001287 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001288 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001289 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001290
1291 stats = stats_proxy_->GetStats();
1292 EXPECT_FALSE(stats.bw_limited_resolution);
1293 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1294 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1295
mflodmancc3d4422017-08-03 08:27:51 -07001296 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001297}
1298
mflodmancc3d4422017-08-03 08:27:51 -07001299TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001300 video_stream_encoder_->OnBitrateUpdated(
1301 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001302
1303 const int kWidth = 1280;
1304 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001305 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001306 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001307 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1308 EXPECT_FALSE(stats.cpu_limited_resolution);
1309 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1310
1311 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001312 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001313 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001314 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001315
1316 stats = stats_proxy_->GetStats();
1317 EXPECT_TRUE(stats.cpu_limited_resolution);
1318 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1319
1320 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001321 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001322 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001323 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001324
1325 stats = stats_proxy_->GetStats();
1326 EXPECT_FALSE(stats.cpu_limited_resolution);
1327 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001328 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001329
mflodmancc3d4422017-08-03 08:27:51 -07001330 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001331}
1332
mflodmancc3d4422017-08-03 08:27:51 -07001333TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001334 video_stream_encoder_->OnBitrateUpdated(
1335 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001336
asaperssonfab67072017-04-04 05:51:49 -07001337 const int kWidth = 1280;
1338 const int kHeight = 720;
1339 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001340 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001341 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001342 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001343 EXPECT_FALSE(stats.cpu_limited_resolution);
1344 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1345
asaperssonfab67072017-04-04 05:51:49 -07001346 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001347 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001348 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001349 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001350 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001351 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001352 EXPECT_TRUE(stats.cpu_limited_resolution);
1353 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1354
1355 // Set new source with adaptation still enabled.
1356 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001357 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001358 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001359
asaperssonfab67072017-04-04 05:51:49 -07001360 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001361 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001362 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001363 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001364 EXPECT_TRUE(stats.cpu_limited_resolution);
1365 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1366
1367 // Set adaptation disabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001368 video_stream_encoder_->SetSource(&new_video_source,
1369 webrtc::DegradationPreference::DISABLED);
kthelgason876222f2016-11-29 01:44:11 -08001370
asaperssonfab67072017-04-04 05:51:49 -07001371 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001372 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001373 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001374 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001375 EXPECT_FALSE(stats.cpu_limited_resolution);
1376 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1377
1378 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001379 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001380 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001381
asaperssonfab67072017-04-04 05:51:49 -07001382 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001383 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001384 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001385 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001386 EXPECT_TRUE(stats.cpu_limited_resolution);
1387 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1388
asaperssonfab67072017-04-04 05:51:49 -07001389 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001390 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001391 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001392 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001393 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001394 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001395 EXPECT_FALSE(stats.cpu_limited_resolution);
1396 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001397 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001398
mflodmancc3d4422017-08-03 08:27:51 -07001399 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001400}
1401
mflodmancc3d4422017-08-03 08:27:51 -07001402TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001403 video_stream_encoder_->OnBitrateUpdated(
1404 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001405
asaperssonfab67072017-04-04 05:51:49 -07001406 const int kWidth = 1280;
1407 const int kHeight = 720;
1408 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001409 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001410 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001411 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001412 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001413 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001414
1415 // Set new source with adaptation still enabled.
1416 test::FrameForwarder new_video_source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001417 video_stream_encoder_->SetSource(&new_video_source,
1418 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001419
asaperssonfab67072017-04-04 05:51:49 -07001420 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001421 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001422 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001423 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001424 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001425 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001426
asaperssonfab67072017-04-04 05:51:49 -07001427 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001428 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001429 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001430 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001431 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001432 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001433 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001434 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001435
asaperssonfab67072017-04-04 05:51:49 -07001436 // Set new source with adaptation still enabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001437 video_stream_encoder_->SetSource(&new_video_source,
1438 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001439
asaperssonfab67072017-04-04 05:51:49 -07001440 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001441 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001442 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001443 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001444 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001445 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001446
asapersson02465b82017-04-10 01:12:52 -07001447 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001448 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001449 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001450
asaperssonfab67072017-04-04 05:51:49 -07001451 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001452 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001453 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001454 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001455 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001456 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1457 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001458
mflodmancc3d4422017-08-03 08:27:51 -07001459 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001460}
1461
mflodmancc3d4422017-08-03 08:27:51 -07001462TEST_F(VideoStreamEncoderTest,
1463 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001464 video_stream_encoder_->OnBitrateUpdated(
1465 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001466
1467 const int kWidth = 1280;
1468 const int kHeight = 720;
Åsa Persson8c1bf952018-09-13 10:42:19 +02001469 int64_t timestamp_ms = kFrameIntervalMs;
asapersson36e9eb42017-03-31 05:29:12 -07001470 video_source_.set_adaptation_enabled(true);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001471 video_source_.IncomingCapturedFrame(
1472 CreateFrame(timestamp_ms, kWidth, kHeight));
1473 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001474 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1475 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1476 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1477
1478 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001479 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001480 timestamp_ms += kFrameIntervalMs;
1481 video_source_.IncomingCapturedFrame(
1482 CreateFrame(timestamp_ms, kWidth, kHeight));
1483 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001484 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1485 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1486 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1487
1488 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001489 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001490 timestamp_ms += kFrameIntervalMs;
1491 video_source_.IncomingCapturedFrame(
1492 CreateFrame(timestamp_ms, kWidth, kHeight));
1493 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001494 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1495 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1496 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1497
Niels Möller4db138e2018-04-19 09:04:13 +02001498 // Leave source unchanged, but disable quality scaler.
asapersson36e9eb42017-03-31 05:29:12 -07001499 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02001500
1501 VideoEncoderConfig video_encoder_config;
1502 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
1503 // Make format different, to force recreation of encoder.
1504 video_encoder_config.video_format.parameters["foo"] = "foo";
1505 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001506 kMaxPayloadLength);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001507 timestamp_ms += kFrameIntervalMs;
1508 video_source_.IncomingCapturedFrame(
1509 CreateFrame(timestamp_ms, kWidth, kHeight));
1510 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001511 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1512 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1513 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1514
mflodmancc3d4422017-08-03 08:27:51 -07001515 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001516}
1517
mflodmancc3d4422017-08-03 08:27:51 -07001518TEST_F(VideoStreamEncoderTest,
1519 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001520 video_stream_encoder_->OnBitrateUpdated(
1521 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001522
asapersson0944a802017-04-07 00:57:58 -07001523 const int kWidth = 1280;
1524 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001525 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001526
asaperssonfab67072017-04-04 05:51:49 -07001527 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001528 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001529 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001530 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001531 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001532 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1533
asapersson02465b82017-04-10 01:12:52 -07001534 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001535 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001536 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001537 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001538 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001539 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001540 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001541 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1542
1543 // Set new source with adaptation still enabled.
1544 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001545 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001546 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001547
1548 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001549 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001550 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001551 stats = stats_proxy_->GetStats();
1552 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001553 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001554 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1555
sprangc5d62e22017-04-02 23:53:04 -07001556 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001557 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001558 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001559 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001560 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001561 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001562 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001563 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001564 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001565 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001566 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1567
sprangc5d62e22017-04-02 23:53:04 -07001568 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001569 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001570 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1571 mock_stats.input_frame_rate = 30;
1572 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001573 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001574 stats_proxy_->ResetMockStats();
1575
1576 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001577 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001578 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001579
1580 // Framerate now adapted.
1581 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001582 EXPECT_FALSE(stats.cpu_limited_resolution);
1583 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001584 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1585
1586 // Disable CPU adaptation.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001587 video_stream_encoder_->SetSource(&new_video_source,
1588 webrtc::DegradationPreference::DISABLED);
sprangc5d62e22017-04-02 23:53:04 -07001589 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001590 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001591 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001592
1593 stats = stats_proxy_->GetStats();
1594 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001595 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001596 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1597
1598 // Try to trigger overuse. Should not succeed.
1599 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001600 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001601 stats_proxy_->ResetMockStats();
1602
1603 stats = stats_proxy_->GetStats();
1604 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001605 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001606 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1607
1608 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001609 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001610 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssonfab67072017-04-04 05:51:49 -07001611 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001612 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001613 stats = stats_proxy_->GetStats();
1614 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001615 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001616 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001617
1618 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001619 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001620 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001621 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001622 stats = stats_proxy_->GetStats();
1623 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001624 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001625 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1626
1627 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001628 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001629 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001630 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001631 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001632 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001633 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001634 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001635 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001636 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001637 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1638
1639 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001640 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001641 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001642 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001643 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001644 stats = stats_proxy_->GetStats();
1645 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001646 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001647 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001648 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001649
mflodmancc3d4422017-08-03 08:27:51 -07001650 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001651}
1652
mflodmancc3d4422017-08-03 08:27:51 -07001653TEST_F(VideoStreamEncoderTest,
1654 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001655 const int kWidth = 1280;
1656 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02001657 video_stream_encoder_->OnBitrateUpdated(
1658 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001659
asaperssonfab67072017-04-04 05:51:49 -07001660 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001661 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001662
asaperssonfab67072017-04-04 05:51:49 -07001663 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001664 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001665
asaperssonfab67072017-04-04 05:51:49 -07001666 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001667 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001668
asaperssonfab67072017-04-04 05:51:49 -07001669 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001670 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001671
kthelgason876222f2016-11-29 01:44:11 -08001672 // Expect a scale down.
1673 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001674 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001675
asapersson02465b82017-04-10 01:12:52 -07001676 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001677 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001678 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001679 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001680
asaperssonfab67072017-04-04 05:51:49 -07001681 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001682 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001683 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001684 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001685
asaperssonfab67072017-04-04 05:51:49 -07001686 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001687 EXPECT_EQ(std::numeric_limits<int>::max(),
1688 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001689
asaperssonfab67072017-04-04 05:51:49 -07001690 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001691 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001692 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001693 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001694
asapersson02465b82017-04-10 01:12:52 -07001695 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001696 EXPECT_EQ(std::numeric_limits<int>::max(),
1697 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001698
mflodmancc3d4422017-08-03 08:27:51 -07001699 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001700}
1701
mflodmancc3d4422017-08-03 08:27:51 -07001702TEST_F(VideoStreamEncoderTest,
1703 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001704 const int kWidth = 1280;
1705 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02001706 video_stream_encoder_->OnBitrateUpdated(
1707 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001708
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001709 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001710 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001711 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001712 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001713
1714 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001715 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001716 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001717 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1718 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1719
1720 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001721 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001722 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001723 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1724 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1725 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1726
1727 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001728 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001729 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1730 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1731 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1732
mflodmancc3d4422017-08-03 08:27:51 -07001733 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001734}
1735
mflodmancc3d4422017-08-03 08:27:51 -07001736TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001737 const int kWidth = 1280;
1738 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02001739 video_stream_encoder_->OnBitrateUpdated(
1740 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001741
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001742 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001743 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001744 video_stream_encoder_->SetSource(&source,
1745 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001746 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1747 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001748 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001749
1750 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001751 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001752 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1753 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1754 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1755 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1756
1757 // Trigger adapt down for same input resolution, expect no change.
1758 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1759 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001760 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001761 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1762 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1763 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1764
1765 // Trigger adapt down for larger input resolution, expect no change.
1766 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1767 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001768 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001769 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1770 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1771 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1772
mflodmancc3d4422017-08-03 08:27:51 -07001773 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001774}
1775
mflodmancc3d4422017-08-03 08:27:51 -07001776TEST_F(VideoStreamEncoderTest,
1777 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001778 const int kWidth = 1280;
1779 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02001780 video_stream_encoder_->OnBitrateUpdated(
1781 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001782
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001783 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001784 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001785 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001786 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001787
1788 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001789 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001790 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001791 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1792 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1793
1794 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001795 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001796 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001797 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1798 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1799
mflodmancc3d4422017-08-03 08:27:51 -07001800 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001801}
1802
mflodmancc3d4422017-08-03 08:27:51 -07001803TEST_F(VideoStreamEncoderTest,
1804 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001805 const int kWidth = 1280;
1806 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02001807 video_stream_encoder_->OnBitrateUpdated(
1808 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001809
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001810 // Enable MAINTAIN_RESOLUTION preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001811 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001812 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001813 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
asapersson02465b82017-04-10 01:12:52 -07001814
1815 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001816 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001817 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001818 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001819 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1820
1821 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001822 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001823 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001824 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001825 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1826
mflodmancc3d4422017-08-03 08:27:51 -07001827 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001828}
1829
mflodmancc3d4422017-08-03 08:27:51 -07001830TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001831 const int kWidth = 1280;
1832 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02001833 video_stream_encoder_->OnBitrateUpdated(
1834 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001835
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001836 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001837 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001838 video_stream_encoder_->SetSource(&source,
1839 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001840
1841 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1842 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001843 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001844 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1845 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1846 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1847
1848 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001849 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001850 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001851 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1852 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1853 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1854
mflodmancc3d4422017-08-03 08:27:51 -07001855 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001856}
1857
mflodmancc3d4422017-08-03 08:27:51 -07001858TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001859 const int kWidth = 1280;
1860 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02001861 video_stream_encoder_->OnBitrateUpdated(
1862 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001863
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001864 // Enable DISABLED preference, no initial limitation.
asapersson09f05612017-05-15 23:40:18 -07001865 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001866 video_stream_encoder_->SetSource(&source,
1867 webrtc::DegradationPreference::DISABLED);
asapersson09f05612017-05-15 23:40:18 -07001868
1869 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1870 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001871 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001872 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1873 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1874 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1875
1876 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001877 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001878 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001879 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1880 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1881 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1882
mflodmancc3d4422017-08-03 08:27:51 -07001883 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001884}
1885
mflodmancc3d4422017-08-03 08:27:51 -07001886TEST_F(VideoStreamEncoderTest,
1887 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001888 const int kWidth = 1280;
1889 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02001890 video_stream_encoder_->OnBitrateUpdated(
1891 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001892
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001893 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001894 AdaptingFrameForwarder source;
1895 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001896 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001897 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001898
1899 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001900 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001901 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001902 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1903 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1904
1905 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001906 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001907 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001908 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001909 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001910 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1911 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1912
1913 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001914 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001915 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001916 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1917 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1918 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1919
mflodmancc3d4422017-08-03 08:27:51 -07001920 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001921}
1922
mflodmancc3d4422017-08-03 08:27:51 -07001923TEST_F(VideoStreamEncoderTest,
1924 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001925 const int kWidth = 1280;
1926 const int kHeight = 720;
1927 const int kInputFps = 30;
Erik Språng4c6ca302019-04-08 15:14:01 +02001928 video_stream_encoder_->OnBitrateUpdated(
1929 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001930
1931 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1932 stats.input_frame_rate = kInputFps;
1933 stats_proxy_->SetMockStats(stats);
1934
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001935 // Expect no scaling to begin with (preference: MAINTAIN_FRAMERATE).
asapersson09f05612017-05-15 23:40:18 -07001936 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1937 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001938 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001939
1940 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001941 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001942 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1943 sink_.WaitForEncodedFrame(2);
1944 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1945
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001946 // Enable MAINTAIN_RESOLUTION preference.
asapersson09f05612017-05-15 23:40:18 -07001947 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001948 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001949 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001950 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001951
1952 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001953 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001954 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1955 sink_.WaitForEncodedFrame(3);
1956 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1957
1958 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001959 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001960 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001961
mflodmancc3d4422017-08-03 08:27:51 -07001962 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001963}
1964
mflodmancc3d4422017-08-03 08:27:51 -07001965TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001966 const int kWidth = 1280;
1967 const int kHeight = 720;
1968 const size_t kNumFrames = 10;
1969
Erik Språng4c6ca302019-04-08 15:14:01 +02001970 video_stream_encoder_->OnBitrateUpdated(
1971 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001972
asaperssond0de2952017-04-21 01:47:31 -07001973 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001974 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001975 video_source_.set_adaptation_enabled(true);
1976
1977 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1978 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1979
1980 int downscales = 0;
1981 for (size_t i = 1; i <= kNumFrames; i++) {
Åsa Persson8c1bf952018-09-13 10:42:19 +02001982 video_source_.IncomingCapturedFrame(
1983 CreateFrame(i * kFrameIntervalMs, kWidth, kHeight));
1984 WaitForEncodedFrame(i * kFrameIntervalMs);
asaperssond0de2952017-04-21 01:47:31 -07001985
asaperssonfab67072017-04-04 05:51:49 -07001986 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001987 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001988 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001989 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001990
1991 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1992 ++downscales;
1993
1994 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1995 EXPECT_EQ(downscales,
1996 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1997 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001998 }
mflodmancc3d4422017-08-03 08:27:51 -07001999 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002000}
2001
mflodmancc3d4422017-08-03 08:27:51 -07002002TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002003 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
2004 const int kWidth = 1280;
2005 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02002006 video_stream_encoder_->OnBitrateUpdated(
2007 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002008
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002009 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002010 AdaptingFrameForwarder source;
2011 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002012 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002013 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002014
Åsa Persson8c1bf952018-09-13 10:42:19 +02002015 int64_t timestamp_ms = kFrameIntervalMs;
2016 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002017 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002018 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002019 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2020 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2021
2022 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002023 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002024 timestamp_ms += kFrameIntervalMs;
2025 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2026 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002027 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002028 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2029 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2030
2031 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002032 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002033 timestamp_ms += kFrameIntervalMs;
2034 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002035 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002036 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002037 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2038 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2039
2040 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002041 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002042 timestamp_ms += kFrameIntervalMs;
2043 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2044 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002045 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002046 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2047 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2048
2049 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002050 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002051 timestamp_ms += kFrameIntervalMs;
2052 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asapersson09f05612017-05-15 23:40:18 -07002053 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002054 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002055 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2056 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2057
mflodmancc3d4422017-08-03 08:27:51 -07002058 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002059}
2060
mflodmancc3d4422017-08-03 08:27:51 -07002061TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07002062 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
2063 const int kWidth = 1280;
2064 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02002065 video_stream_encoder_->OnBitrateUpdated(
2066 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002067
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002068 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002069 AdaptingFrameForwarder source;
2070 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002071 video_stream_encoder_->SetSource(&source,
2072 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002073
Åsa Persson8c1bf952018-09-13 10:42:19 +02002074 int64_t timestamp_ms = kFrameIntervalMs;
2075 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07002076 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002077 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002078 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2079 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2080
2081 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002082 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002083 timestamp_ms += kFrameIntervalMs;
2084 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2085 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002086 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2087 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2088 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2089
2090 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002091 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002092 timestamp_ms += kFrameIntervalMs;
2093 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07002094 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002095 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002096 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2097 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2098
2099 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002100 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002101 timestamp_ms += kFrameIntervalMs;
2102 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2103 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002104 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2105 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2106 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2107
2108 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002109 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002110 timestamp_ms += kFrameIntervalMs;
2111 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07002112 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002113 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002114 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2115 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2116
mflodmancc3d4422017-08-03 08:27:51 -07002117 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002118}
2119
mflodmancc3d4422017-08-03 08:27:51 -07002120TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002121 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
2122 const int kWidth = 1280;
2123 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02002124 video_stream_encoder_->OnBitrateUpdated(
2125 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002126
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002127 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002128 AdaptingFrameForwarder source;
2129 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002130 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002131 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002132
Åsa Persson8c1bf952018-09-13 10:42:19 +02002133 int64_t timestamp_ms = kFrameIntervalMs;
2134 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002135 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002136 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002137 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2138 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2139 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2140 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2141
2142 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002143 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002144 timestamp_ms += kFrameIntervalMs;
2145 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2146 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002147 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002148 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2149 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2150 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2151 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2152
2153 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07002154 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002155 timestamp_ms += kFrameIntervalMs;
2156 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2157 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002158 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002159 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2160 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2161 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2162 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2163
Jonathan Yubc771b72017-12-08 17:04:29 -08002164 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002165 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002166 timestamp_ms += kFrameIntervalMs;
2167 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2168 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002169 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002170 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2171 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002172 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002173 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2174
Jonathan Yubc771b72017-12-08 17:04:29 -08002175 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07002176 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002177 timestamp_ms += kFrameIntervalMs;
2178 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2179 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002180 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002181 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07002182 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2183 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2184 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2185 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2186
Jonathan Yubc771b72017-12-08 17:04:29 -08002187 // Trigger quality adapt down, expect no change (min resolution reached).
2188 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002189 timestamp_ms += kFrameIntervalMs;
2190 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2191 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002192 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
2193 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2194 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2195 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2196 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2197
2198 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002199 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002200 timestamp_ms += kFrameIntervalMs;
2201 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2202 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002203 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002204 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2205 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2206 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2207 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2208
2209 // Trigger cpu adapt up, expect upscaled resolution (640x360).
2210 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002211 timestamp_ms += kFrameIntervalMs;
2212 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2213 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002214 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2215 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2216 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2217 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2218 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2219
2220 // Trigger cpu adapt up, expect upscaled resolution (960x540).
2221 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002222 timestamp_ms += kFrameIntervalMs;
2223 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2224 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002225 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002226 last_wants = source.sink_wants();
2227 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2228 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002229 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002230 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2231
2232 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002233 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002234 timestamp_ms += kFrameIntervalMs;
2235 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2236 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002237 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002238 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2239 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002240 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002241 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2242
2243 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002244 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002245 timestamp_ms += kFrameIntervalMs;
2246 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002247 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002248 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002249 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002250 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2251 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002252 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002253 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002254
mflodmancc3d4422017-08-03 08:27:51 -07002255 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002256}
2257
mflodmancc3d4422017-08-03 08:27:51 -07002258TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002259 const int kWidth = 640;
2260 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002261
Erik Språng4c6ca302019-04-08 15:14:01 +02002262 video_stream_encoder_->OnBitrateUpdated(
2263 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002264
perkj803d97f2016-11-01 11:45:46 -07002265 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002266 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002267 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002268 }
2269
mflodmancc3d4422017-08-03 08:27:51 -07002270 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002271 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002272 video_source_.IncomingCapturedFrame(CreateFrame(
2273 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002274 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002275 }
2276
mflodmancc3d4422017-08-03 08:27:51 -07002277 video_stream_encoder_->Stop();
2278 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002279 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002280
perkj803d97f2016-11-01 11:45:46 -07002281 EXPECT_EQ(1,
2282 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2283 EXPECT_EQ(
2284 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2285}
2286
mflodmancc3d4422017-08-03 08:27:51 -07002287TEST_F(VideoStreamEncoderTest,
2288 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
Erik Språng4c6ca302019-04-08 15:14:01 +02002289 video_stream_encoder_->OnBitrateUpdated(
2290 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002291 const int kWidth = 640;
2292 const int kHeight = 360;
2293
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002294 video_stream_encoder_->SetSource(&video_source_,
2295 webrtc::DegradationPreference::DISABLED);
asaperssonf4e44af2017-04-19 02:01:06 -07002296
2297 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2298 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002299 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002300 }
2301
mflodmancc3d4422017-08-03 08:27:51 -07002302 video_stream_encoder_->Stop();
2303 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002304 stats_proxy_.reset();
2305
2306 EXPECT_EQ(0,
2307 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2308}
2309
mflodmancc3d4422017-08-03 08:27:51 -07002310TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002311 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02002312 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002313
2314 const int kDefaultFps = 30;
Erik Språng566124a2018-04-23 12:32:22 +02002315 const VideoBitrateAllocation expected_bitrate =
sprang57c2fff2017-01-16 06:24:02 -08002316 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002317 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002318
sprang57c2fff2017-01-16 06:24:02 -08002319 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
Niels Möller6bb5ab92019-01-11 11:11:10 +01002320 .Times(1);
Erik Språng610c7632019-03-06 15:37:33 +01002321 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kLowTargetBitrateBps),
Erik Språng4c6ca302019-04-08 15:14:01 +02002322 DataRate::bps(kLowTargetBitrateBps),
2323 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002324
sprang57c2fff2017-01-16 06:24:02 -08002325 video_source_.IncomingCapturedFrame(
Erik Språngd7329ca2019-02-21 21:19:53 +01002326 CreateFrame(rtc::TimeMillis(), codec_width_, codec_height_));
2327 WaitForEncodedFrame(rtc::TimeMillis());
2328 absl::optional<VideoBitrateAllocation> bitrate_allocation =
2329 fake_encoder_.GetAndResetLastBitrateAllocation();
2330 // Check that encoder has been updated too, not just allocation observer.
2331 EXPECT_EQ(bitrate_allocation->get_sum_bps(), kLowTargetBitrateBps);
2332 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec / kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002333
2334 // Not called on second frame.
2335 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2336 .Times(0);
2337 video_source_.IncomingCapturedFrame(
Erik Språngd7329ca2019-02-21 21:19:53 +01002338 CreateFrame(rtc::TimeMillis(), codec_width_, codec_height_));
2339 WaitForEncodedFrame(rtc::TimeMillis());
2340 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec / kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002341
2342 // Called after a process interval.
2343 const int64_t kProcessIntervalMs =
2344 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang57c2fff2017-01-16 06:24:02 -08002345 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2346 .Times(1);
Erik Språngd7329ca2019-02-21 21:19:53 +01002347 const int64_t start_time_ms = rtc::TimeMillis();
2348 while (rtc::TimeMillis() - start_time_ms < kProcessIntervalMs) {
2349 video_source_.IncomingCapturedFrame(
2350 CreateFrame(rtc::TimeMillis(), codec_width_, codec_height_));
2351 WaitForEncodedFrame(rtc::TimeMillis());
2352 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec / kDefaultFps);
2353 }
2354
2355 // Since rates are unchanged, encoder should not be reconfigured.
2356 EXPECT_FALSE(fake_encoder_.GetAndResetLastBitrateAllocation().has_value());
sprang57c2fff2017-01-16 06:24:02 -08002357
mflodmancc3d4422017-08-03 08:27:51 -07002358 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002359}
2360
Åsa Perssonc29cb2c2019-03-25 12:06:59 +01002361TEST_F(VideoStreamEncoderTest, TemporalLayersNotDisabledIfSupported) {
2362 // 2 TLs configured, temporal layers supported by encoder.
2363 const int kNumTemporalLayers = 2;
2364 ResetEncoder("VP8", 1, kNumTemporalLayers, 1, /*screenshare*/ false);
2365 fake_encoder_.SetTemporalLayersSupported(0, true);
2366
2367 // Bitrate allocated across temporal layers.
2368 const int kTl0Bps = kTargetBitrateBps *
2369 webrtc::SimulcastRateAllocator::GetTemporalRateAllocation(
2370 kNumTemporalLayers, /*temporal_id*/ 0);
2371 const int kTl1Bps = kTargetBitrateBps *
2372 webrtc::SimulcastRateAllocator::GetTemporalRateAllocation(
2373 kNumTemporalLayers, /*temporal_id*/ 1);
2374 VideoBitrateAllocation expected_bitrate;
2375 expected_bitrate.SetBitrate(/*si*/ 0, /*ti*/ 0, kTl0Bps);
2376 expected_bitrate.SetBitrate(/*si*/ 0, /*ti*/ 1, kTl1Bps - kTl0Bps);
2377
2378 VerifyAllocatedBitrate(expected_bitrate);
2379 video_stream_encoder_->Stop();
2380}
2381
2382TEST_F(VideoStreamEncoderTest, TemporalLayersDisabledIfNotSupported) {
2383 // 2 TLs configured, temporal layers not supported by encoder.
2384 ResetEncoder("VP8", 1, /*num_temporal_layers*/ 2, 1, /*screenshare*/ false);
2385 fake_encoder_.SetTemporalLayersSupported(0, false);
2386
2387 // Temporal layers not supported by the encoder.
2388 // Total bitrate should be at ti:0.
2389 VideoBitrateAllocation expected_bitrate;
2390 expected_bitrate.SetBitrate(/*si*/ 0, /*ti*/ 0, kTargetBitrateBps);
2391
2392 VerifyAllocatedBitrate(expected_bitrate);
2393 video_stream_encoder_->Stop();
2394}
2395
2396TEST_F(VideoStreamEncoderTest, VerifyBitrateAllocationForTwoStreams) {
2397 // 2 TLs configured, temporal layers only supported for first stream.
2398 ResetEncoder("VP8", 2, /*num_temporal_layers*/ 2, 1, /*screenshare*/ false);
2399 fake_encoder_.SetTemporalLayersSupported(0, true);
2400 fake_encoder_.SetTemporalLayersSupported(1, false);
2401
2402 const int kS0Bps = 150000;
2403 const int kS0Tl0Bps =
2404 kS0Bps * webrtc::SimulcastRateAllocator::GetTemporalRateAllocation(
2405 /*num_layers*/ 2, /*temporal_id*/ 0);
2406 const int kS0Tl1Bps =
2407 kS0Bps * webrtc::SimulcastRateAllocator::GetTemporalRateAllocation(
2408 /*num_layers*/ 2, /*temporal_id*/ 1);
2409 const int kS1Bps = kTargetBitrateBps - kS0Tl1Bps;
2410 // Temporal layers not supported by si:1.
2411 VideoBitrateAllocation expected_bitrate;
2412 expected_bitrate.SetBitrate(/*si*/ 0, /*ti*/ 0, kS0Tl0Bps);
2413 expected_bitrate.SetBitrate(/*si*/ 0, /*ti*/ 1, kS0Tl1Bps - kS0Tl0Bps);
2414 expected_bitrate.SetBitrate(/*si*/ 1, /*ti*/ 0, kS1Bps);
2415
2416 VerifyAllocatedBitrate(expected_bitrate);
2417 video_stream_encoder_->Stop();
2418}
2419
Niels Möller7dc26b72017-12-06 10:27:48 +01002420TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2421 const int kFrameWidth = 1280;
2422 const int kFrameHeight = 720;
2423 const int kFramerate = 24;
2424
Erik Språng4c6ca302019-04-08 15:14:01 +02002425 video_stream_encoder_->OnBitrateUpdated(
2426 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möller7dc26b72017-12-06 10:27:48 +01002427 test::FrameForwarder source;
2428 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002429 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002430
2431 // Insert a single frame, triggering initial configuration.
2432 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2433 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2434
2435 EXPECT_EQ(
2436 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2437 kDefaultFramerate);
2438
2439 // Trigger reconfigure encoder (without resetting the entire instance).
2440 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002441 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002442 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2443 video_encoder_config.number_of_streams = 1;
2444 video_encoder_config.video_stream_factory =
2445 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2446 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002447 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002448 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2449
2450 // Detector should be updated with fps limit from codec config.
2451 EXPECT_EQ(
2452 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2453 kFramerate);
2454
2455 // Trigger overuse, max framerate should be reduced.
2456 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2457 stats.input_frame_rate = kFramerate;
2458 stats_proxy_->SetMockStats(stats);
2459 video_stream_encoder_->TriggerCpuOveruse();
2460 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2461 int adapted_framerate =
2462 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2463 EXPECT_LT(adapted_framerate, kFramerate);
2464
2465 // Trigger underuse, max framerate should go back to codec configured fps.
2466 // Set extra low fps, to make sure it's actually reset, not just incremented.
2467 stats = stats_proxy_->GetStats();
2468 stats.input_frame_rate = adapted_framerate / 2;
2469 stats_proxy_->SetMockStats(stats);
2470 video_stream_encoder_->TriggerCpuNormalUsage();
2471 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2472 EXPECT_EQ(
2473 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2474 kFramerate);
2475
2476 video_stream_encoder_->Stop();
2477}
2478
2479TEST_F(VideoStreamEncoderTest,
2480 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2481 const int kFrameWidth = 1280;
2482 const int kFrameHeight = 720;
2483 const int kLowFramerate = 15;
2484 const int kHighFramerate = 25;
2485
Erik Språng4c6ca302019-04-08 15:14:01 +02002486 video_stream_encoder_->OnBitrateUpdated(
2487 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möller7dc26b72017-12-06 10:27:48 +01002488 test::FrameForwarder source;
2489 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002490 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002491
2492 // Trigger initial configuration.
2493 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002494 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002495 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2496 video_encoder_config.number_of_streams = 1;
2497 video_encoder_config.video_stream_factory =
2498 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2499 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2500 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002501 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002502 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2503
2504 EXPECT_EQ(
2505 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2506 kLowFramerate);
2507
2508 // Trigger overuse, max framerate should be reduced.
2509 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2510 stats.input_frame_rate = kLowFramerate;
2511 stats_proxy_->SetMockStats(stats);
2512 video_stream_encoder_->TriggerCpuOveruse();
2513 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2514 int adapted_framerate =
2515 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2516 EXPECT_LT(adapted_framerate, kLowFramerate);
2517
2518 // Reconfigure the encoder with a new (higher max framerate), max fps should
2519 // still respect the adaptation.
2520 video_encoder_config.video_stream_factory =
2521 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2522 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2523 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002524 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002525 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2526
2527 EXPECT_EQ(
2528 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2529 adapted_framerate);
2530
2531 // Trigger underuse, max framerate should go back to codec configured fps.
2532 stats = stats_proxy_->GetStats();
2533 stats.input_frame_rate = adapted_framerate;
2534 stats_proxy_->SetMockStats(stats);
2535 video_stream_encoder_->TriggerCpuNormalUsage();
2536 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2537 EXPECT_EQ(
2538 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2539 kHighFramerate);
2540
2541 video_stream_encoder_->Stop();
2542}
2543
mflodmancc3d4422017-08-03 08:27:51 -07002544TEST_F(VideoStreamEncoderTest,
2545 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002546 const int kFrameWidth = 1280;
2547 const int kFrameHeight = 720;
2548 const int kFramerate = 24;
2549
Erik Språng4c6ca302019-04-08 15:14:01 +02002550 video_stream_encoder_->OnBitrateUpdated(
2551 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002552 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002553 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002554 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangfda496a2017-06-15 04:21:07 -07002555
2556 // Trigger initial configuration.
2557 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002558 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002559 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2560 video_encoder_config.number_of_streams = 1;
2561 video_encoder_config.video_stream_factory =
2562 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2563 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002564 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002565 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002566 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002567
Niels Möller7dc26b72017-12-06 10:27:48 +01002568 EXPECT_EQ(
2569 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2570 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002571
2572 // Trigger overuse, max framerate should be reduced.
2573 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2574 stats.input_frame_rate = kFramerate;
2575 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002576 video_stream_encoder_->TriggerCpuOveruse();
2577 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002578 int adapted_framerate =
2579 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002580 EXPECT_LT(adapted_framerate, kFramerate);
2581
2582 // Change degradation preference to not enable framerate scaling. Target
2583 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002584 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002585 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -07002586 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002587 EXPECT_EQ(
2588 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2589 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002590
mflodmancc3d4422017-08-03 08:27:51 -07002591 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002592}
2593
mflodmancc3d4422017-08-03 08:27:51 -07002594TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002595 const int kTooLowBitrateForFrameSizeBps = 10000;
Erik Språng610c7632019-03-06 15:37:33 +01002596 video_stream_encoder_->OnBitrateUpdated(
Erik Språng4c6ca302019-04-08 15:14:01 +02002597 DataRate::bps(kTooLowBitrateForFrameSizeBps),
2598 DataRate::bps(kTooLowBitrateForFrameSizeBps), 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002599 const int kWidth = 640;
2600 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002601
asaperssonfab67072017-04-04 05:51:49 -07002602 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002603
2604 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002605 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002606
2607 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002608 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002609
sprangc5d62e22017-04-02 23:53:04 -07002610 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002611
asaperssonfab67072017-04-04 05:51:49 -07002612 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002613 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002614 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002615
2616 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002617 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002618
sprangc5d62e22017-04-02 23:53:04 -07002619 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002620
mflodmancc3d4422017-08-03 08:27:51 -07002621 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002622}
2623
mflodmancc3d4422017-08-03 08:27:51 -07002624TEST_F(VideoStreamEncoderTest,
2625 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002626 const int kTooLowBitrateForFrameSizeBps = 10000;
Erik Språng610c7632019-03-06 15:37:33 +01002627 video_stream_encoder_->OnBitrateUpdated(
Erik Språng4c6ca302019-04-08 15:14:01 +02002628 DataRate::bps(kTooLowBitrateForFrameSizeBps),
2629 DataRate::bps(kTooLowBitrateForFrameSizeBps), 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002630 const int kWidth = 640;
2631 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002632
2633 // We expect the n initial frames to get dropped.
2634 int i;
2635 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002636 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002637 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002638 }
2639 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002640 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002641 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002642
2643 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002644 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002645
mflodmancc3d4422017-08-03 08:27:51 -07002646 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002647}
2648
mflodmancc3d4422017-08-03 08:27:51 -07002649TEST_F(VideoStreamEncoderTest,
2650 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002651 const int kWidth = 640;
2652 const int kHeight = 360;
Erik Språng610c7632019-03-06 15:37:33 +01002653 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kLowTargetBitrateBps),
Erik Språng4c6ca302019-04-08 15:14:01 +02002654 DataRate::bps(kLowTargetBitrateBps),
2655 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002656
2657 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002658 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002659 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason2bc68642017-02-07 07:02:22 -08002660
asaperssonfab67072017-04-04 05:51:49 -07002661 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002662 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002663 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002664
mflodmancc3d4422017-08-03 08:27:51 -07002665 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002666}
2667
mflodmancc3d4422017-08-03 08:27:51 -07002668TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002669 const int kWidth = 640;
2670 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002671 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02002672
2673 VideoEncoderConfig video_encoder_config;
2674 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
2675 // Make format different, to force recreation of encoder.
2676 video_encoder_config.video_format.parameters["foo"] = "foo";
2677 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002678 kMaxPayloadLength);
Erik Språng610c7632019-03-06 15:37:33 +01002679 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kLowTargetBitrateBps),
Erik Språng4c6ca302019-04-08 15:14:01 +02002680 DataRate::bps(kLowTargetBitrateBps),
2681 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002682
kthelgasonb83797b2017-02-14 11:57:25 -08002683 // Force quality scaler reconfiguration by resetting the source.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002684 video_stream_encoder_->SetSource(&video_source_,
2685 webrtc::DegradationPreference::BALANCED);
kthelgasonad9010c2017-02-14 00:46:51 -08002686
asaperssonfab67072017-04-04 05:51:49 -07002687 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002688 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002689 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002690
mflodmancc3d4422017-08-03 08:27:51 -07002691 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002692 fake_encoder_.SetQualityScaling(true);
2693}
2694
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002695TEST_F(VideoStreamEncoderTest, InitialFrameDropActivatesWhenBWEstimateReady) {
2696 webrtc::test::ScopedFieldTrials field_trials(
2697 "WebRTC-InitialFramedrop/Enabled/");
2698 // Reset encoder for field trials to take effect.
2699 ConfigureEncoder(video_encoder_config_.Copy());
2700 const int kTooLowBitrateForFrameSizeBps = 10000;
2701 const int kWidth = 640;
2702 const int kHeight = 360;
2703
Erik Språng4c6ca302019-04-08 15:14:01 +02002704 video_stream_encoder_->OnBitrateUpdated(
2705 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002706 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2707 // Frame should not be dropped.
2708 WaitForEncodedFrame(1);
2709
Erik Språng610c7632019-03-06 15:37:33 +01002710 video_stream_encoder_->OnBitrateUpdated(
Erik Språng4c6ca302019-04-08 15:14:01 +02002711 DataRate::bps(kTooLowBitrateForFrameSizeBps),
2712 DataRate::bps(kTooLowBitrateForFrameSizeBps), 0, 0);
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002713 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
2714 // Expect to drop this frame, the wait should time out.
2715 ExpectDroppedFrame();
2716
2717 // Expect the sink_wants to specify a scaled frame.
2718 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
2719 video_stream_encoder_->Stop();
2720}
2721
mflodmancc3d4422017-08-03 08:27:51 -07002722TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002723 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2724 const int kTooSmallWidth = 10;
2725 const int kTooSmallHeight = 10;
Erik Språng4c6ca302019-04-08 15:14:01 +02002726 video_stream_encoder_->OnBitrateUpdated(
2727 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002728
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002729 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002730 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002731 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002732 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002733 VerifyNoLimitation(source.sink_wants());
2734 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2735
2736 // Trigger adapt down, too small frame, expect no change.
2737 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002738 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002739 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002740 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002741 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2742 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2743
mflodmancc3d4422017-08-03 08:27:51 -07002744 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002745}
2746
mflodmancc3d4422017-08-03 08:27:51 -07002747TEST_F(VideoStreamEncoderTest,
2748 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002749 const int kTooSmallWidth = 10;
2750 const int kTooSmallHeight = 10;
2751 const int kFpsLimit = 7;
Erik Språng4c6ca302019-04-08 15:14:01 +02002752 video_stream_encoder_->OnBitrateUpdated(
2753 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002754
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002755 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002756 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002757 video_stream_encoder_->SetSource(&source,
2758 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002759 VerifyNoLimitation(source.sink_wants());
2760 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2761 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2762
2763 // Trigger adapt down, expect limited framerate.
2764 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002765 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002766 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002767 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2768 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2769 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2770 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2771
2772 // Trigger adapt down, too small frame, expect no change.
2773 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002774 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002775 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002776 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2777 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2778 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2779 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2780
mflodmancc3d4422017-08-03 08:27:51 -07002781 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002782}
2783
mflodmancc3d4422017-08-03 08:27:51 -07002784TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002785 fake_encoder_.ForceInitEncodeFailure(true);
Erik Språng4c6ca302019-04-08 15:14:01 +02002786 video_stream_encoder_->OnBitrateUpdated(
2787 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möllerf1338562018-04-26 09:51:47 +02002788 ResetEncoder("VP8", 2, 1, 1, false);
asapersson02465b82017-04-10 01:12:52 -07002789 const int kFrameWidth = 1280;
2790 const int kFrameHeight = 720;
2791 video_source_.IncomingCapturedFrame(
2792 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002793 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002794 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002795}
2796
sprangb1ca0732017-02-01 08:38:12 -08002797// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002798TEST_F(VideoStreamEncoderTest,
2799 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
Erik Språng4c6ca302019-04-08 15:14:01 +02002800 video_stream_encoder_->OnBitrateUpdated(
2801 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002802
2803 const int kFrameWidth = 1280;
2804 const int kFrameHeight = 720;
2805 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002806 // requested by
2807 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002808 video_source_.set_adaptation_enabled(true);
2809
2810 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002811 CreateFrame(1 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002812 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002813
2814 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002815 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002816 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002817 CreateFrame(2 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002818 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002819
asaperssonfab67072017-04-04 05:51:49 -07002820 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002821 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002822 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002823 CreateFrame(3 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002824 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002825
mflodmancc3d4422017-08-03 08:27:51 -07002826 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002827}
sprangfe627f32017-03-29 08:24:59 -07002828
mflodmancc3d4422017-08-03 08:27:51 -07002829TEST_F(VideoStreamEncoderTest,
2830 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002831 const int kFrameWidth = 1280;
2832 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07002833
Erik Språng4c6ca302019-04-08 15:14:01 +02002834 video_stream_encoder_->OnBitrateUpdated(
2835 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -07002836 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002837 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002838 video_source_.set_adaptation_enabled(true);
2839
sprang4847ae62017-06-27 07:06:52 -07002840 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002841
2842 video_source_.IncomingCapturedFrame(
2843 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002844 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002845
2846 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002847 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002848
2849 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002850 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002851 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002852 video_source_.IncomingCapturedFrame(
2853 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002854 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002855 }
2856
2857 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002858 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002859 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002860 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002861 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002862 video_source_.IncomingCapturedFrame(
2863 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002864 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002865 ++num_frames_dropped;
2866 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002867 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002868 }
2869 }
2870
sprang4847ae62017-06-27 07:06:52 -07002871 // Add some slack to account for frames dropped by the frame dropper.
2872 const int kErrorMargin = 1;
2873 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002874 kErrorMargin);
2875
2876 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002877 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002878 num_frames_dropped = 0;
Åsa Persson8c1bf952018-09-13 10:42:19 +02002879 for (int i = 0; i <= max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002880 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002881 video_source_.IncomingCapturedFrame(
2882 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002883 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002884 ++num_frames_dropped;
2885 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002886 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002887 }
2888 }
sprang4847ae62017-06-27 07:06:52 -07002889 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002890 kErrorMargin);
2891
2892 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002893 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002894 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002895 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002896 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002897 video_source_.IncomingCapturedFrame(
2898 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002899 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002900 ++num_frames_dropped;
2901 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002902 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002903 }
2904 }
sprang4847ae62017-06-27 07:06:52 -07002905 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002906 kErrorMargin);
2907
2908 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002909 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002910 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002911 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002912 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002913 video_source_.IncomingCapturedFrame(
2914 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002915 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002916 ++num_frames_dropped;
2917 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002918 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002919 }
2920 }
2921 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2922
mflodmancc3d4422017-08-03 08:27:51 -07002923 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002924}
2925
mflodmancc3d4422017-08-03 08:27:51 -07002926TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002927 const int kFramerateFps = 5;
2928 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002929 const int kFrameWidth = 1280;
2930 const int kFrameHeight = 720;
2931
sprang4847ae62017-06-27 07:06:52 -07002932 // Reconfigure encoder with two temporal layers and screensharing, which will
2933 // disable frame dropping and make testing easier.
Niels Möllerf1338562018-04-26 09:51:47 +02002934 ResetEncoder("VP8", 1, 2, 1, true);
sprang4847ae62017-06-27 07:06:52 -07002935
Erik Språng4c6ca302019-04-08 15:14:01 +02002936 video_stream_encoder_->OnBitrateUpdated(
2937 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -07002938 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002939 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002940 video_source_.set_adaptation_enabled(true);
2941
sprang4847ae62017-06-27 07:06:52 -07002942 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002943
2944 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08002945 rtc::VideoSinkWants last_wants;
2946 do {
2947 last_wants = video_source_.sink_wants();
2948
sprangc5d62e22017-04-02 23:53:04 -07002949 // Insert frames to get a new fps estimate...
2950 for (int j = 0; j < kFramerateFps; ++j) {
2951 video_source_.IncomingCapturedFrame(
2952 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08002953 if (video_source_.last_sent_width()) {
2954 sink_.WaitForEncodedFrame(timestamp_ms);
2955 }
sprangc5d62e22017-04-02 23:53:04 -07002956 timestamp_ms += kFrameIntervalMs;
Yves Gerey665174f2018-06-19 15:03:05 +02002957 fake_clock_.AdvanceTimeMicros(kFrameIntervalMs *
2958 rtc::kNumMicrosecsPerMillisec);
sprangc5d62e22017-04-02 23:53:04 -07002959 }
2960 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002961 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08002962 } while (video_source_.sink_wants().max_framerate_fps <
2963 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07002964
Jonathan Yubc771b72017-12-08 17:04:29 -08002965 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07002966
mflodmancc3d4422017-08-03 08:27:51 -07002967 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002968}
asaperssonf7e294d2017-06-13 23:25:22 -07002969
mflodmancc3d4422017-08-03 08:27:51 -07002970TEST_F(VideoStreamEncoderTest,
2971 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002972 const int kWidth = 1280;
2973 const int kHeight = 720;
2974 const int64_t kFrameIntervalMs = 150;
2975 int64_t timestamp_ms = kFrameIntervalMs;
Erik Språng4c6ca302019-04-08 15:14:01 +02002976 video_stream_encoder_->OnBitrateUpdated(
2977 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002978
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002979 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002980 AdaptingFrameForwarder source;
2981 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002982 video_stream_encoder_->SetSource(&source,
2983 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002984 timestamp_ms += kFrameIntervalMs;
2985 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002986 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002987 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002988 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2989 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2990 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2991
2992 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002993 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002994 timestamp_ms += kFrameIntervalMs;
2995 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002996 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002997 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2998 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2999 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3000 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3001
3002 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003003 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003004 timestamp_ms += kFrameIntervalMs;
3005 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003006 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003007 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
3008 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3009 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3010 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3011
3012 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003013 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003014 timestamp_ms += kFrameIntervalMs;
3015 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003016 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003017 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
3018 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3019 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3020 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3021
3022 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003023 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003024 timestamp_ms += kFrameIntervalMs;
3025 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003026 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003027 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
3028 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3029 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3030 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3031
3032 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07003033 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003034 timestamp_ms += kFrameIntervalMs;
3035 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003036 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003037 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
3038 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3039 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3040 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3041
3042 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07003043 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003044 timestamp_ms += kFrameIntervalMs;
3045 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003046 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003047 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
3048 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3049 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3050 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3051
3052 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07003053 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003054 timestamp_ms += kFrameIntervalMs;
3055 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003056 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003057 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
3058 rtc::VideoSinkWants last_wants = source.sink_wants();
3059 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3060 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3061 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3062
3063 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003064 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003065 timestamp_ms += kFrameIntervalMs;
3066 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003067 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003068 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
3069 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3070 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3071 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3072
3073 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07003074 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003075 timestamp_ms += kFrameIntervalMs;
3076 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003077 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003078 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
3079 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3080 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3081 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3082
3083 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07003084 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003085 timestamp_ms += kFrameIntervalMs;
3086 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003087 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003088 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3089 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3090 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3091 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3092
3093 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003094 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003095 timestamp_ms += kFrameIntervalMs;
3096 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003097 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003098 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
3099 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3100 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3101 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3102
3103 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003104 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003105 timestamp_ms += kFrameIntervalMs;
3106 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003107 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003108 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3109 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3110 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3111 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3112
3113 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003114 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003115 timestamp_ms += kFrameIntervalMs;
3116 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003117 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003118 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
3119 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3120 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3121 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3122
3123 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003124 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003125 timestamp_ms += kFrameIntervalMs;
3126 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003127 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003128 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3129 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3130 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3131 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3132
3133 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003134 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003135 timestamp_ms += kFrameIntervalMs;
3136 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003137 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003138 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02003139 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003140 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3141 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3142 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3143
3144 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003145 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003146 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003147 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3148
mflodmancc3d4422017-08-03 08:27:51 -07003149 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003150}
3151
mflodmancc3d4422017-08-03 08:27:51 -07003152TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07003153 const int kWidth = 1280;
3154 const int kHeight = 720;
3155 const int64_t kFrameIntervalMs = 150;
3156 int64_t timestamp_ms = kFrameIntervalMs;
Erik Språng4c6ca302019-04-08 15:14:01 +02003157 video_stream_encoder_->OnBitrateUpdated(
3158 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07003159
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003160 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07003161 AdaptingFrameForwarder source;
3162 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003163 video_stream_encoder_->SetSource(&source,
3164 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07003165 timestamp_ms += kFrameIntervalMs;
3166 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003167 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003168 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003169 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3170 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3171 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3172 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3173 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3174 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3175
3176 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003177 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003178 timestamp_ms += kFrameIntervalMs;
3179 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003180 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003181 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
3182 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3183 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3184 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3185 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3186 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3187 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3188
3189 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003190 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003191 timestamp_ms += kFrameIntervalMs;
3192 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003193 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003194 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
3195 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3196 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3197 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3198 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3199 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3200 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3201
3202 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003203 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003204 timestamp_ms += kFrameIntervalMs;
3205 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003206 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003207 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
3208 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3209 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3210 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3211 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3212 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3213 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3214
3215 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003216 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003217 timestamp_ms += kFrameIntervalMs;
3218 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003219 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003220 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
3221 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3222 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3223 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3224 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3225 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3226 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3227
3228 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003229 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003230 timestamp_ms += kFrameIntervalMs;
3231 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003232 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003233 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3234 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3235 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3236 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3237 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3238 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3239 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3240
3241 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003242 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003243 timestamp_ms += kFrameIntervalMs;
3244 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003245 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003246 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02003247 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003248 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3249 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3250 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3251 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3252 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3253 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3254
3255 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003256 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003257 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003258 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3259 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3260
mflodmancc3d4422017-08-03 08:27:51 -07003261 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003262}
3263
mflodmancc3d4422017-08-03 08:27:51 -07003264TEST_F(VideoStreamEncoderTest,
3265 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07003266 const int kWidth = 640;
3267 const int kHeight = 360;
3268 const int kFpsLimit = 15;
3269 const int64_t kFrameIntervalMs = 150;
3270 int64_t timestamp_ms = kFrameIntervalMs;
Erik Språng4c6ca302019-04-08 15:14:01 +02003271 video_stream_encoder_->OnBitrateUpdated(
3272 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07003273
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003274 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07003275 AdaptingFrameForwarder source;
3276 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003277 video_stream_encoder_->SetSource(&source,
3278 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07003279 timestamp_ms += kFrameIntervalMs;
3280 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003281 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003282 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003283 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3284 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3285 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3286 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3287 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3288 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3289
3290 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003291 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003292 timestamp_ms += kFrameIntervalMs;
3293 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003294 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003295 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
3296 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3297 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3298 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3299 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3300 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3301 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3302
3303 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003304 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003305 timestamp_ms += kFrameIntervalMs;
3306 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003307 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003308 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
3309 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3310 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3311 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3312 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3313 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3314 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3315
3316 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003317 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003318 timestamp_ms += kFrameIntervalMs;
3319 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003320 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003321 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3322 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3323 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3324 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3325 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3326 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3327 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3328
3329 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003330 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003331 timestamp_ms += kFrameIntervalMs;
3332 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003333 WaitForEncodedFrame(timestamp_ms);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003334 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003335 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3336 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3337 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3338 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3339 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3340 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3341
3342 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003343 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003344 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003345 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3346 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3347
mflodmancc3d4422017-08-03 08:27:51 -07003348 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003349}
3350
mflodmancc3d4422017-08-03 08:27:51 -07003351TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003352 // Simulates simulcast behavior and makes highest stream resolutions divisible
3353 // by 4.
3354 class CroppingVideoStreamFactory
3355 : public VideoEncoderConfig::VideoStreamFactoryInterface {
3356 public:
3357 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
3358 int framerate)
3359 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
3360 EXPECT_GT(num_temporal_layers, 0u);
3361 EXPECT_GT(framerate, 0);
3362 }
3363
3364 private:
3365 std::vector<VideoStream> CreateEncoderStreams(
3366 int width,
3367 int height,
3368 const VideoEncoderConfig& encoder_config) override {
Yves Gerey665174f2018-06-19 15:03:05 +02003369 std::vector<VideoStream> streams = test::CreateVideoStreams(
3370 width - width % 4, height - height % 4, encoder_config);
ilnik6b826ef2017-06-16 06:53:48 -07003371 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +01003372 stream.num_temporal_layers = num_temporal_layers_;
ilnik6b826ef2017-06-16 06:53:48 -07003373 stream.max_framerate = framerate_;
3374 }
3375 return streams;
3376 }
3377
3378 const size_t num_temporal_layers_;
3379 const int framerate_;
3380 };
3381
3382 const int kFrameWidth = 1920;
3383 const int kFrameHeight = 1080;
3384 // 3/4 of 1920.
3385 const int kAdaptedFrameWidth = 1440;
3386 // 3/4 of 1080 rounded down to multiple of 4.
3387 const int kAdaptedFrameHeight = 808;
3388 const int kFramerate = 24;
3389
Erik Språng4c6ca302019-04-08 15:14:01 +02003390 video_stream_encoder_->OnBitrateUpdated(
3391 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003392 // Trigger reconfigure encoder (without resetting the entire instance).
3393 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02003394 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07003395 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3396 video_encoder_config.number_of_streams = 1;
3397 video_encoder_config.video_stream_factory =
3398 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003399 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02003400 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07003401 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003402
3403 video_source_.set_adaptation_enabled(true);
3404
3405 video_source_.IncomingCapturedFrame(
3406 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003407 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003408
3409 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003410 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003411 video_source_.IncomingCapturedFrame(
3412 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003413 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003414
mflodmancc3d4422017-08-03 08:27:51 -07003415 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003416}
3417
mflodmancc3d4422017-08-03 08:27:51 -07003418TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003419 const int kFrameWidth = 1280;
3420 const int kFrameHeight = 720;
3421 const int kLowFps = 2;
3422 const int kHighFps = 30;
3423
Erik Språng4c6ca302019-04-08 15:14:01 +02003424 video_stream_encoder_->OnBitrateUpdated(
3425 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003426
3427 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3428 max_framerate_ = kLowFps;
3429
3430 // Insert 2 seconds of 2fps video.
3431 for (int i = 0; i < kLowFps * 2; ++i) {
3432 video_source_.IncomingCapturedFrame(
3433 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3434 WaitForEncodedFrame(timestamp_ms);
3435 timestamp_ms += 1000 / kLowFps;
3436 }
3437
3438 // Make sure encoder is updated with new target.
Erik Språng4c6ca302019-04-08 15:14:01 +02003439 video_stream_encoder_->OnBitrateUpdated(
3440 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003441 video_source_.IncomingCapturedFrame(
3442 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3443 WaitForEncodedFrame(timestamp_ms);
3444 timestamp_ms += 1000 / kLowFps;
3445
3446 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3447
3448 // Insert 30fps frames for just a little more than the forced update period.
3449 const int kVcmTimerIntervalFrames =
3450 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3451 const int kFrameIntervalMs = 1000 / kHighFps;
3452 max_framerate_ = kHighFps;
3453 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3454 video_source_.IncomingCapturedFrame(
3455 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3456 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3457 // be dropped if the encoder hans't been updated with the new higher target
3458 // framerate yet, causing it to overshoot the target bitrate and then
3459 // suffering the wrath of the media optimizer.
3460 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3461 timestamp_ms += kFrameIntervalMs;
3462 }
3463
3464 // Don expect correct measurement just yet, but it should be higher than
3465 // before.
3466 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3467
mflodmancc3d4422017-08-03 08:27:51 -07003468 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003469}
3470
mflodmancc3d4422017-08-03 08:27:51 -07003471TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003472 const int kFrameWidth = 1280;
3473 const int kFrameHeight = 720;
3474 const int kTargetBitrateBps = 1000000;
3475
3476 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02003477 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
Erik Språng4c6ca302019-04-08 15:14:01 +02003478 video_stream_encoder_->OnBitrateUpdated(
3479 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -07003480 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003481
3482 // Insert a first video frame, causes another bitrate update.
3483 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3484 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3485 video_source_.IncomingCapturedFrame(
3486 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3487 WaitForEncodedFrame(timestamp_ms);
3488
3489 // Next, simulate video suspension due to pacer queue overrun.
Erik Språng4c6ca302019-04-08 15:14:01 +02003490 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(0), DataRate::bps(0), 0,
Erik Språng610c7632019-03-06 15:37:33 +01003491 1);
sprang4847ae62017-06-27 07:06:52 -07003492
3493 // Skip ahead until a new periodic parameter update should have occured.
3494 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3495 fake_clock_.AdvanceTimeMicros(
3496 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3497 rtc::kNumMicrosecsPerMillisec);
3498
3499 // Bitrate observer should not be called.
3500 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3501 video_source_.IncomingCapturedFrame(
3502 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3503 ExpectDroppedFrame();
3504
mflodmancc3d4422017-08-03 08:27:51 -07003505 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003506}
ilnik6b826ef2017-06-16 06:53:48 -07003507
Niels Möller4db138e2018-04-19 09:04:13 +02003508TEST_F(VideoStreamEncoderTest,
3509 DefaultCpuAdaptationThresholdsForSoftwareEncoder) {
3510 const int kFrameWidth = 1280;
3511 const int kFrameHeight = 720;
3512 const CpuOveruseOptions default_options;
Erik Språng4c6ca302019-04-08 15:14:01 +02003513 video_stream_encoder_->OnBitrateUpdated(
3514 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möller4db138e2018-04-19 09:04:13 +02003515 video_source_.IncomingCapturedFrame(
3516 CreateFrame(1, kFrameWidth, kFrameHeight));
3517 WaitForEncodedFrame(1);
3518 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3519 .low_encode_usage_threshold_percent,
3520 default_options.low_encode_usage_threshold_percent);
3521 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3522 .high_encode_usage_threshold_percent,
3523 default_options.high_encode_usage_threshold_percent);
3524 video_stream_encoder_->Stop();
3525}
3526
3527TEST_F(VideoStreamEncoderTest,
3528 HigherCpuAdaptationThresholdsForHardwareEncoder) {
3529 const int kFrameWidth = 1280;
3530 const int kFrameHeight = 720;
3531 CpuOveruseOptions hardware_options;
3532 hardware_options.low_encode_usage_threshold_percent = 150;
3533 hardware_options.high_encode_usage_threshold_percent = 200;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +01003534 fake_encoder_.SetIsHardwareAccelerated(true);
Niels Möller4db138e2018-04-19 09:04:13 +02003535
Erik Språng4c6ca302019-04-08 15:14:01 +02003536 video_stream_encoder_->OnBitrateUpdated(
3537 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möller4db138e2018-04-19 09:04:13 +02003538 video_source_.IncomingCapturedFrame(
3539 CreateFrame(1, kFrameWidth, kFrameHeight));
3540 WaitForEncodedFrame(1);
3541 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3542 .low_encode_usage_threshold_percent,
3543 hardware_options.low_encode_usage_threshold_percent);
3544 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3545 .high_encode_usage_threshold_percent,
3546 hardware_options.high_encode_usage_threshold_percent);
3547 video_stream_encoder_->Stop();
3548}
3549
Niels Möller6bb5ab92019-01-11 11:11:10 +01003550TEST_F(VideoStreamEncoderTest, DropsFramesWhenEncoderOvershoots) {
3551 const int kFrameWidth = 320;
3552 const int kFrameHeight = 240;
3553 const int kFps = 30;
3554 const int kTargetBitrateBps = 120000;
3555 const int kNumFramesInRun = kFps * 5; // Runs of five seconds.
3556
Erik Språng4c6ca302019-04-08 15:14:01 +02003557 video_stream_encoder_->OnBitrateUpdated(
3558 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003559
3560 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3561 max_framerate_ = kFps;
3562
3563 // Insert 3 seconds of video, verify number of drops with normal bitrate.
3564 fake_encoder_.SimulateOvershoot(1.0);
3565 int num_dropped = 0;
3566 for (int i = 0; i < kNumFramesInRun; ++i) {
3567 video_source_.IncomingCapturedFrame(
3568 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3569 // Wait up to two frame durations for a frame to arrive.
3570 if (!TimedWaitForEncodedFrame(timestamp_ms, 2 * 1000 / kFps)) {
3571 ++num_dropped;
3572 }
3573 timestamp_ms += 1000 / kFps;
3574 }
3575
Erik Språnga8d48ab2019-02-08 14:17:40 +01003576 // Framerate should be measured to be near the expected target rate.
3577 EXPECT_NEAR(fake_encoder_.GetLastFramerate(), kFps, 1);
3578
3579 // Frame drops should be within 5% of expected 0%.
3580 EXPECT_NEAR(num_dropped, 0, 5 * kNumFramesInRun / 100);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003581
3582 // Make encoder produce frames at double the expected bitrate during 3 seconds
3583 // of video, verify number of drops. Rate needs to be slightly changed in
3584 // order to force the rate to be reconfigured.
Erik Språng7ca375c2019-02-06 16:20:17 +01003585 double overshoot_factor = 2.0;
3586 if (RateControlSettings::ParseFromFieldTrials().UseEncoderBitrateAdjuster()) {
3587 // With bitrate adjuster, when need to overshoot even more to trigger
3588 // frame dropping.
3589 overshoot_factor *= 2;
3590 }
3591 fake_encoder_.SimulateOvershoot(overshoot_factor);
Erik Språng610c7632019-03-06 15:37:33 +01003592 video_stream_encoder_->OnBitrateUpdated(
Erik Språng4c6ca302019-04-08 15:14:01 +02003593 DataRate::bps(kTargetBitrateBps + 1000),
3594 DataRate::bps(kTargetBitrateBps + 1000), 0, 0);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003595 num_dropped = 0;
3596 for (int i = 0; i < kNumFramesInRun; ++i) {
3597 video_source_.IncomingCapturedFrame(
3598 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3599 // Wait up to two frame durations for a frame to arrive.
3600 if (!TimedWaitForEncodedFrame(timestamp_ms, 2 * 1000 / kFps)) {
3601 ++num_dropped;
3602 }
3603 timestamp_ms += 1000 / kFps;
3604 }
3605
Erik Språng4c6ca302019-04-08 15:14:01 +02003606 video_stream_encoder_->OnBitrateUpdated(
3607 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Erik Språnga8d48ab2019-02-08 14:17:40 +01003608
3609 // Target framerate should be still be near the expected target, despite
3610 // the frame drops.
3611 EXPECT_NEAR(fake_encoder_.GetLastFramerate(), kFps, 1);
3612
3613 // Frame drops should be within 5% of expected 50%.
3614 EXPECT_NEAR(num_dropped, kNumFramesInRun / 2, 5 * kNumFramesInRun / 100);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003615
3616 video_stream_encoder_->Stop();
3617}
3618
3619TEST_F(VideoStreamEncoderTest, ConfiguresCorrectFrameRate) {
3620 const int kFrameWidth = 320;
3621 const int kFrameHeight = 240;
3622 const int kActualInputFps = 24;
3623 const int kTargetBitrateBps = 120000;
3624
3625 ASSERT_GT(max_framerate_, kActualInputFps);
3626
3627 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3628 max_framerate_ = kActualInputFps;
Erik Språng4c6ca302019-04-08 15:14:01 +02003629 video_stream_encoder_->OnBitrateUpdated(
3630 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003631
3632 // Insert 3 seconds of video, with an input fps lower than configured max.
3633 for (int i = 0; i < kActualInputFps * 3; ++i) {
3634 video_source_.IncomingCapturedFrame(
3635 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3636 // Wait up to two frame durations for a frame to arrive.
3637 WaitForEncodedFrame(timestamp_ms);
3638 timestamp_ms += 1000 / kActualInputFps;
3639 }
3640
3641 EXPECT_NEAR(kActualInputFps, fake_encoder_.GetLastFramerate(), 1);
3642
3643 video_stream_encoder_->Stop();
3644}
3645
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01003646TEST_F(VideoStreamEncoderTest, AccumulatesUpdateRectOnDroppedFrames) {
3647 VideoFrame::UpdateRect rect;
Erik Språng4c6ca302019-04-08 15:14:01 +02003648 video_stream_encoder_->OnBitrateUpdated(
3649 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01003650
3651 fake_encoder_.BlockNextEncode();
3652 video_source_.IncomingCapturedFrame(
3653 CreateFrameWithUpdatedPixel(1, nullptr, 0));
3654 WaitForEncodedFrame(1);
3655 // On the very first frame full update should be forced.
3656 rect = fake_encoder_.GetLastUpdateRect();
3657 EXPECT_EQ(rect.offset_x, 0);
3658 EXPECT_EQ(rect.offset_y, 0);
3659 EXPECT_EQ(rect.height, codec_height_);
3660 EXPECT_EQ(rect.width, codec_width_);
3661 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
3662 // call to ContinueEncode.
3663 video_source_.IncomingCapturedFrame(
3664 CreateFrameWithUpdatedPixel(2, nullptr, 1));
3665 ExpectDroppedFrame();
3666 video_source_.IncomingCapturedFrame(
3667 CreateFrameWithUpdatedPixel(3, nullptr, 10));
3668 ExpectDroppedFrame();
3669 fake_encoder_.ContinueEncode();
3670 WaitForEncodedFrame(3);
3671 // Updates to pixels 1 and 10 should be accumulated to one 10x1 rect.
3672 rect = fake_encoder_.GetLastUpdateRect();
3673 EXPECT_EQ(rect.offset_x, 1);
3674 EXPECT_EQ(rect.offset_y, 0);
3675 EXPECT_EQ(rect.width, 10);
3676 EXPECT_EQ(rect.height, 1);
3677
3678 video_source_.IncomingCapturedFrame(
3679 CreateFrameWithUpdatedPixel(4, nullptr, 0));
3680 WaitForEncodedFrame(4);
3681 // Previous frame was encoded, so no accumulation should happen.
3682 rect = fake_encoder_.GetLastUpdateRect();
3683 EXPECT_EQ(rect.offset_x, 0);
3684 EXPECT_EQ(rect.offset_y, 0);
3685 EXPECT_EQ(rect.width, 1);
3686 EXPECT_EQ(rect.height, 1);
3687
3688 video_stream_encoder_->Stop();
3689}
3690
Erik Språngd7329ca2019-02-21 21:19:53 +01003691TEST_F(VideoStreamEncoderTest, SetsFrameTypes) {
Erik Språng4c6ca302019-04-08 15:14:01 +02003692 video_stream_encoder_->OnBitrateUpdated(
3693 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Erik Språngd7329ca2019-02-21 21:19:53 +01003694
3695 // First frame is always keyframe.
3696 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
3697 WaitForEncodedFrame(1);
Niels Möller8f7ce222019-03-21 15:43:58 +01003698 EXPECT_THAT(
3699 fake_encoder_.LastFrameTypes(),
3700 testing::ElementsAre(VideoFrameType{VideoFrameType::kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003701
3702 // Insert delta frame.
3703 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
3704 WaitForEncodedFrame(2);
Niels Möller8f7ce222019-03-21 15:43:58 +01003705 EXPECT_THAT(
3706 fake_encoder_.LastFrameTypes(),
3707 testing::ElementsAre(VideoFrameType{VideoFrameType::kVideoFrameDelta}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003708
3709 // Request next frame be a key-frame.
3710 video_stream_encoder_->SendKeyFrame();
3711 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
3712 WaitForEncodedFrame(3);
Niels Möller8f7ce222019-03-21 15:43:58 +01003713 EXPECT_THAT(
3714 fake_encoder_.LastFrameTypes(),
3715 testing::ElementsAre(VideoFrameType{VideoFrameType::kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003716
3717 video_stream_encoder_->Stop();
3718}
3719
3720TEST_F(VideoStreamEncoderTest, SetsFrameTypesSimulcast) {
3721 // Setup simulcast with three streams.
3722 ResetEncoder("VP8", 3, 1, 1, false);
Erik Språng610c7632019-03-06 15:37:33 +01003723 video_stream_encoder_->OnBitrateUpdated(
Erik Språng4c6ca302019-04-08 15:14:01 +02003724 DataRate::bps(kSimulcastTargetBitrateBps),
3725 DataRate::bps(kSimulcastTargetBitrateBps), 0, 0);
Erik Språngd7329ca2019-02-21 21:19:53 +01003726 // Wait for all three layers before triggering event.
3727 sink_.SetNumExpectedLayers(3);
3728
3729 // First frame is always keyframe.
3730 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
3731 WaitForEncodedFrame(1);
3732 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
Niels Möller8f7ce222019-03-21 15:43:58 +01003733 testing::ElementsAreArray({VideoFrameType::kVideoFrameKey,
3734 VideoFrameType::kVideoFrameKey,
3735 VideoFrameType::kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003736
3737 // Insert delta frame.
3738 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
3739 WaitForEncodedFrame(2);
3740 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
Niels Möller8f7ce222019-03-21 15:43:58 +01003741 testing::ElementsAreArray({VideoFrameType::kVideoFrameDelta,
3742 VideoFrameType::kVideoFrameDelta,
3743 VideoFrameType::kVideoFrameDelta}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003744
3745 // Request next frame be a key-frame.
3746 // Only first stream is configured to produce key-frame.
3747 video_stream_encoder_->SendKeyFrame();
3748 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
3749 WaitForEncodedFrame(3);
3750 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
Niels Möller8f7ce222019-03-21 15:43:58 +01003751 testing::ElementsAreArray({VideoFrameType::kVideoFrameKey,
3752 VideoFrameType::kVideoFrameDelta,
3753 VideoFrameType::kVideoFrameDelta}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003754
3755 video_stream_encoder_->Stop();
3756}
3757
3758TEST_F(VideoStreamEncoderTest, RequestKeyframeInternalSource) {
3759 // Configure internal source factory and setup test again.
3760 encoder_factory_.SetHasInternalSource(true);
3761 ResetEncoder("VP8", 1, 1, 1, false);
Erik Språng4c6ca302019-04-08 15:14:01 +02003762 video_stream_encoder_->OnBitrateUpdated(
3763 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Erik Språngd7329ca2019-02-21 21:19:53 +01003764
3765 // Call encoder directly, simulating internal source where encoded frame
3766 // callback in VideoStreamEncoder is called despite no OnFrame().
3767 fake_encoder_.InjectFrame(CreateFrame(1, nullptr), true);
3768 EXPECT_TRUE(WaitForFrame(kDefaultTimeoutMs));
Niels Möller8f7ce222019-03-21 15:43:58 +01003769 EXPECT_THAT(
3770 fake_encoder_.LastFrameTypes(),
3771 testing::ElementsAre(VideoFrameType{VideoFrameType::kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003772
Niels Möller8f7ce222019-03-21 15:43:58 +01003773 const std::vector<VideoFrameType> kDeltaFrame = {
3774 VideoFrameType::kVideoFrameDelta};
Erik Språngd7329ca2019-02-21 21:19:53 +01003775 // Need to set timestamp manually since manually for injected frame.
3776 VideoFrame frame = CreateFrame(101, nullptr);
3777 frame.set_timestamp(101);
3778 fake_encoder_.InjectFrame(frame, false);
3779 EXPECT_TRUE(WaitForFrame(kDefaultTimeoutMs));
Niels Möller8f7ce222019-03-21 15:43:58 +01003780 EXPECT_THAT(
3781 fake_encoder_.LastFrameTypes(),
3782 testing::ElementsAre(VideoFrameType{VideoFrameType::kVideoFrameDelta}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003783
3784 // Request key-frame. The forces a dummy frame down into the encoder.
3785 fake_encoder_.ExpectNullFrame();
3786 video_stream_encoder_->SendKeyFrame();
3787 EXPECT_TRUE(WaitForFrame(kDefaultTimeoutMs));
Niels Möller8f7ce222019-03-21 15:43:58 +01003788 EXPECT_THAT(
3789 fake_encoder_.LastFrameTypes(),
3790 testing::ElementsAre(VideoFrameType{VideoFrameType::kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003791
3792 video_stream_encoder_->Stop();
3793}
Erik Språngb7cb7b52019-02-26 15:52:33 +01003794
3795TEST_F(VideoStreamEncoderTest, AdjustsTimestampInternalSource) {
3796 // Configure internal source factory and setup test again.
3797 encoder_factory_.SetHasInternalSource(true);
3798 ResetEncoder("VP8", 1, 1, 1, false);
Erik Språng4c6ca302019-04-08 15:14:01 +02003799 video_stream_encoder_->OnBitrateUpdated(
3800 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Erik Språngb7cb7b52019-02-26 15:52:33 +01003801
3802 int64_t timestamp = 1;
3803 EncodedImage image;
3804 image.Allocate(kTargetBitrateBps / kDefaultFramerate / 8);
3805 image.capture_time_ms_ = ++timestamp;
3806 image.SetTimestamp(static_cast<uint32_t>(timestamp * 90));
3807 const int64_t kEncodeFinishDelayMs = 10;
3808 image.timing_.encode_start_ms = timestamp;
3809 image.timing_.encode_finish_ms = timestamp + kEncodeFinishDelayMs;
3810 fake_encoder_.InjectEncodedImage(image);
3811 // Wait for frame without incrementing clock.
3812 EXPECT_TRUE(sink_.WaitForFrame(kDefaultTimeoutMs));
3813 // Frame is captured kEncodeFinishDelayMs before it's encoded, so restored
3814 // capture timestamp should be kEncodeFinishDelayMs in the past.
3815 EXPECT_EQ(sink_.GetLastCaptureTimeMs(),
3816 fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec -
3817 kEncodeFinishDelayMs);
3818
3819 video_stream_encoder_->Stop();
3820}
perkj26091b12016-09-01 01:17:40 -07003821} // namespace webrtc