blob: 18ab5b90b063b93386b3fc882b1f20d37f15bdbd [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>
Danil Chapovalovd3ba2362019-04-10 17:01:23 +020015#include <memory>
Per512ecb32016-09-23 15:52:06 +020016#include <utility>
17
Danil Chapovalovd3ba2362019-04-10 17:01:23 +020018#include "api/task_queue/default_task_queue_factory.h"
Jiawei Ouc2ebe212018-11-08 10:02:56 -080019#include "api/video/builtin_video_bitrate_allocator_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "api/video/i420_buffer.h"
Erik Språngf93eda12019-01-16 17:10:57 +010021#include "api/video/video_bitrate_allocation.h"
Erik Språng4529fbc2018-10-12 10:30:31 +020022#include "api/video_codecs/vp8_temporal_layers.h"
Elad Aloncde8ab22019-03-20 11:56:20 +010023#include "api/video_codecs/vp8_temporal_layers_factory.h"
Steve Anton10542f22019-01-11 09:11:00 -080024#include "media/base/video_adapter.h"
Sergey Silkin86684962018-03-28 19:32:37 +020025#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020026#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
Åsa Perssonc29cb2c2019-03-25 12:06:59 +010027#include "modules/video_coding/utility/simulcast_rate_allocator.h"
Steve Anton10542f22019-01-11 09:11:00 -080028#include "rtc_base/fake_clock.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020029#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080030#include "rtc_base/ref_counted_object.h"
Erik Språng7ca375c2019-02-06 16:20:17 +010031#include "system_wrappers/include/field_trial.h"
Mirko Bonadei17f48782018-09-28 08:51:10 +020032#include "system_wrappers/include/metrics.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020033#include "system_wrappers/include/sleep.h"
34#include "test/encoder_settings.h"
35#include "test/fake_encoder.h"
Kári Tristan Helgason639602a2018-08-02 10:51:40 +020036#include "test/field_trial.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020037#include "test/frame_generator.h"
38#include "test/gmock.h"
39#include "test/gtest.h"
Niels Möllercbcbc222018-09-28 09:07:24 +020040#include "test/video_encoder_proxy_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020041#include "video/send_statistics_proxy.h"
perkj26091b12016-09-01 01:17:40 -070042
43namespace webrtc {
44
sprangb1ca0732017-02-01 08:38:12 -080045using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080046using ::testing::_;
kthelgason876222f2016-11-29 01:44:11 -080047
perkj803d97f2016-11-01 11:45:46 -070048namespace {
Åsa Persson8c1bf952018-09-13 10:42:19 +020049const int kMinPixelsPerFrame = 320 * 180;
50const int kMinFramerateFps = 2;
51const int kMinBalancedFramerateFps = 7;
52const int64_t kFrameTimeoutMs = 100;
asapersson5f7226f2016-11-25 04:37:00 -080053const size_t kMaxPayloadLength = 1440;
Erik Språngd7329ca2019-02-21 21:19:53 +010054const uint32_t kTargetBitrateBps = 1000000;
55const uint32_t kSimulcastTargetBitrateBps = 3150000;
56const uint32_t kLowTargetBitrateBps = kTargetBitrateBps / 10;
kthelgason2bc68642017-02-07 07:02:22 -080057const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070058const int kDefaultFramerate = 30;
Åsa Persson8c1bf952018-09-13 10:42:19 +020059const int64_t kFrameIntervalMs = rtc::kNumMillisecsPerSec / kDefaultFramerate;
asapersson5f7226f2016-11-25 04:37:00 -080060
perkj803d97f2016-11-01 11:45:46 -070061class TestBuffer : public webrtc::I420Buffer {
62 public:
63 TestBuffer(rtc::Event* event, int width, int height)
64 : I420Buffer(width, height), event_(event) {}
65
66 private:
67 friend class rtc::RefCountedObject<TestBuffer>;
68 ~TestBuffer() override {
69 if (event_)
70 event_->Set();
71 }
72 rtc::Event* const event_;
73};
74
Niels Möller7dc26b72017-12-06 10:27:48 +010075class CpuOveruseDetectorProxy : public OveruseFrameDetector {
76 public:
Niels Möllerd1f7eb62018-03-28 16:40:58 +020077 explicit CpuOveruseDetectorProxy(CpuOveruseMetricsObserver* metrics_observer)
78 : OveruseFrameDetector(metrics_observer),
Niels Möller7dc26b72017-12-06 10:27:48 +010079 last_target_framerate_fps_(-1) {}
80 virtual ~CpuOveruseDetectorProxy() {}
81
82 void OnTargetFramerateUpdated(int framerate_fps) override {
83 rtc::CritScope cs(&lock_);
84 last_target_framerate_fps_ = framerate_fps;
85 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
86 }
87
88 int GetLastTargetFramerate() {
89 rtc::CritScope cs(&lock_);
90 return last_target_framerate_fps_;
91 }
92
Niels Möller4db138e2018-04-19 09:04:13 +020093 CpuOveruseOptions GetOptions() { return options_; }
94
Niels Möller7dc26b72017-12-06 10:27:48 +010095 private:
96 rtc::CriticalSection lock_;
97 int last_target_framerate_fps_ RTC_GUARDED_BY(lock_);
98};
99
mflodmancc3d4422017-08-03 08:27:51 -0700100class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -0700101 public:
Niels Möller213618e2018-07-24 09:29:58 +0200102 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
Danil Chapovalovd3ba2362019-04-10 17:01:23 +0200103 const VideoStreamEncoderSettings& settings,
104 TaskQueueFactory* task_queue_factory)
Sebastian Jansson572c60f2019-03-04 18:30:41 +0100105 : VideoStreamEncoder(Clock::GetRealTimeClock(),
106 1 /* number_of_cores */,
Yves Gerey665174f2018-06-19 15:03:05 +0200107 stats_proxy,
108 settings,
Yves Gerey665174f2018-06-19 15:03:05 +0200109 std::unique_ptr<OveruseFrameDetector>(
110 overuse_detector_proxy_ =
Sebastian Jansson74682c12019-03-01 11:50:20 +0100111 new CpuOveruseDetectorProxy(stats_proxy)),
Danil Chapovalovd3ba2362019-04-10 17:01:23 +0200112 task_queue_factory) {}
perkj803d97f2016-11-01 11:45:46 -0700113
sprangb1ca0732017-02-01 08:38:12 -0800114 void PostTaskAndWait(bool down, AdaptReason reason) {
Niels Möllerc572ff32018-11-07 08:43:50 +0100115 rtc::Event event;
kthelgason876222f2016-11-29 01:44:11 -0800116 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800117 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700118 event.Set();
119 });
perkj070ba852017-02-16 15:46:27 -0800120 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700121 }
122
kthelgason2fc52542017-03-03 00:24:41 -0800123 // This is used as a synchronisation mechanism, to make sure that the
124 // encoder queue is not blocked before we start sending it frames.
125 void WaitUntilTaskQueueIsIdle() {
Niels Möllerc572ff32018-11-07 08:43:50 +0100126 rtc::Event event;
Yves Gerey665174f2018-06-19 15:03:05 +0200127 encoder_queue()->PostTask([&event] { event.Set(); });
kthelgason2fc52542017-03-03 00:24:41 -0800128 ASSERT_TRUE(event.Wait(5000));
129 }
130
sprangb1ca0732017-02-01 08:38:12 -0800131 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800132
sprangb1ca0732017-02-01 08:38:12 -0800133 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800134
sprangb1ca0732017-02-01 08:38:12 -0800135 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800136
sprangb1ca0732017-02-01 08:38:12 -0800137 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700138
Niels Möller7dc26b72017-12-06 10:27:48 +0100139 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700140};
141
asapersson5f7226f2016-11-25 04:37:00 -0800142class VideoStreamFactory
143 : public VideoEncoderConfig::VideoStreamFactoryInterface {
144 public:
sprangfda496a2017-06-15 04:21:07 -0700145 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
146 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800147 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700148 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800149 }
150
151 private:
152 std::vector<VideoStream> CreateEncoderStreams(
153 int width,
154 int height,
155 const VideoEncoderConfig& encoder_config) override {
156 std::vector<VideoStream> streams =
157 test::CreateVideoStreams(width, height, encoder_config);
158 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +0100159 stream.num_temporal_layers = num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700160 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800161 }
162 return streams;
163 }
sprangfda496a2017-06-15 04:21:07 -0700164
asapersson5f7226f2016-11-25 04:37:00 -0800165 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700166 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800167};
168
sprangb1ca0732017-02-01 08:38:12 -0800169class AdaptingFrameForwarder : public test::FrameForwarder {
170 public:
171 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700172 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800173
174 void set_adaptation_enabled(bool enabled) {
175 rtc::CritScope cs(&crit_);
176 adaptation_enabled_ = enabled;
177 }
178
asaperssonfab67072017-04-04 05:51:49 -0700179 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800180 rtc::CritScope cs(&crit_);
181 return adaptation_enabled_;
182 }
183
asapersson09f05612017-05-15 23:40:18 -0700184 rtc::VideoSinkWants last_wants() const {
185 rtc::CritScope cs(&crit_);
186 return last_wants_;
187 }
188
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200189 absl::optional<int> last_sent_width() const { return last_width_; }
190 absl::optional<int> last_sent_height() const { return last_height_; }
Jonathan Yubc771b72017-12-08 17:04:29 -0800191
sprangb1ca0732017-02-01 08:38:12 -0800192 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
193 int cropped_width = 0;
194 int cropped_height = 0;
195 int out_width = 0;
196 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700197 if (adaption_enabled()) {
198 if (adapter_.AdaptFrameResolution(
199 video_frame.width(), video_frame.height(),
200 video_frame.timestamp_us() * 1000, &cropped_width,
201 &cropped_height, &out_width, &out_height)) {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100202 VideoFrame adapted_frame =
203 VideoFrame::Builder()
204 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
205 nullptr, out_width, out_height))
206 .set_timestamp_rtp(99)
207 .set_timestamp_ms(99)
208 .set_rotation(kVideoRotation_0)
209 .build();
sprangc5d62e22017-04-02 23:53:04 -0700210 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
211 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800212 last_width_.emplace(adapted_frame.width());
213 last_height_.emplace(adapted_frame.height());
214 } else {
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200215 last_width_ = absl::nullopt;
216 last_height_ = absl::nullopt;
sprangc5d62e22017-04-02 23:53:04 -0700217 }
sprangb1ca0732017-02-01 08:38:12 -0800218 } else {
219 test::FrameForwarder::IncomingCapturedFrame(video_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800220 last_width_.emplace(video_frame.width());
221 last_height_.emplace(video_frame.height());
sprangb1ca0732017-02-01 08:38:12 -0800222 }
223 }
224
225 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
226 const rtc::VideoSinkWants& wants) override {
227 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700228 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700229 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
230 wants.max_pixel_count,
231 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800232 test::FrameForwarder::AddOrUpdateSink(sink, wants);
233 }
sprangb1ca0732017-02-01 08:38:12 -0800234 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700235 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
236 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200237 absl::optional<int> last_width_;
238 absl::optional<int> last_height_;
sprangb1ca0732017-02-01 08:38:12 -0800239};
sprangc5d62e22017-04-02 23:53:04 -0700240
Niels Möller213618e2018-07-24 09:29:58 +0200241// TODO(nisse): Mock only VideoStreamEncoderObserver.
sprangc5d62e22017-04-02 23:53:04 -0700242class MockableSendStatisticsProxy : public SendStatisticsProxy {
243 public:
244 MockableSendStatisticsProxy(Clock* clock,
245 const VideoSendStream::Config& config,
246 VideoEncoderConfig::ContentType content_type)
247 : SendStatisticsProxy(clock, config, content_type) {}
248
249 VideoSendStream::Stats GetStats() override {
250 rtc::CritScope cs(&lock_);
251 if (mock_stats_)
252 return *mock_stats_;
253 return SendStatisticsProxy::GetStats();
254 }
255
Niels Möller213618e2018-07-24 09:29:58 +0200256 int GetInputFrameRate() const override {
257 rtc::CritScope cs(&lock_);
258 if (mock_stats_)
259 return mock_stats_->input_frame_rate;
260 return SendStatisticsProxy::GetInputFrameRate();
261 }
sprangc5d62e22017-04-02 23:53:04 -0700262 void SetMockStats(const VideoSendStream::Stats& stats) {
263 rtc::CritScope cs(&lock_);
264 mock_stats_.emplace(stats);
265 }
266
267 void ResetMockStats() {
268 rtc::CritScope cs(&lock_);
269 mock_stats_.reset();
270 }
271
272 private:
273 rtc::CriticalSection lock_;
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200274 absl::optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700275};
276
sprang4847ae62017-06-27 07:06:52 -0700277class MockBitrateObserver : public VideoBitrateAllocationObserver {
278 public:
Erik Språng566124a2018-04-23 12:32:22 +0200279 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const VideoBitrateAllocation&));
sprang4847ae62017-06-27 07:06:52 -0700280};
281
perkj803d97f2016-11-01 11:45:46 -0700282} // namespace
283
mflodmancc3d4422017-08-03 08:27:51 -0700284class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700285 public:
286 static const int kDefaultTimeoutMs = 30 * 1000;
287
mflodmancc3d4422017-08-03 08:27:51 -0700288 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700289 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700290 codec_width_(320),
291 codec_height_(240),
Åsa Persson8c1bf952018-09-13 10:42:19 +0200292 max_framerate_(kDefaultFramerate),
Danil Chapovalovd3ba2362019-04-10 17:01:23 +0200293 task_queue_factory_(CreateDefaultTaskQueueFactory()),
perkj26091b12016-09-01 01:17:40 -0700294 fake_encoder_(),
Niels Möller4db138e2018-04-19 09:04:13 +0200295 encoder_factory_(&fake_encoder_),
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800296 bitrate_allocator_factory_(CreateBuiltinVideoBitrateAllocatorFactory()),
sprangc5d62e22017-04-02 23:53:04 -0700297 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700298 Clock::GetRealTimeClock(),
299 video_send_config_,
300 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700301 sink_(&fake_encoder_) {}
302
303 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700304 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700305 video_send_config_ = VideoSendStream::Config(nullptr);
Niels Möller4db138e2018-04-19 09:04:13 +0200306 video_send_config_.encoder_settings.encoder_factory = &encoder_factory_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800307 video_send_config_.encoder_settings.bitrate_allocator_factory =
308 bitrate_allocator_factory_.get();
Niels Möller259a4972018-04-05 15:36:51 +0200309 video_send_config_.rtp.payload_name = "FAKE";
310 video_send_config_.rtp.payload_type = 125;
perkj26091b12016-09-01 01:17:40 -0700311
Per512ecb32016-09-23 15:52:06 +0200312 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200313 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700314 video_encoder_config.video_stream_factory =
315 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100316 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700317
318 // Framerate limit is specified by the VideoStreamFactory.
319 std::vector<VideoStream> streams =
320 video_encoder_config.video_stream_factory->CreateEncoderStreams(
321 codec_width_, codec_height_, video_encoder_config);
322 max_framerate_ = streams[0].max_framerate;
Sebastian Jansson40889f32019-04-17 12:11:20 +0200323 fake_clock_.SetTime(Timestamp::us(1234));
sprang4847ae62017-06-27 07:06:52 -0700324
Niels Möllerf1338562018-04-26 09:51:47 +0200325 ConfigureEncoder(std::move(video_encoder_config));
asapersson5f7226f2016-11-25 04:37:00 -0800326 }
327
Niels Möllerf1338562018-04-26 09:51:47 +0200328 void ConfigureEncoder(VideoEncoderConfig video_encoder_config) {
mflodmancc3d4422017-08-03 08:27:51 -0700329 if (video_stream_encoder_)
330 video_stream_encoder_->Stop();
331 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
Danil Chapovalovd3ba2362019-04-10 17:01:23 +0200332 stats_proxy_.get(), video_send_config_.encoder_settings,
333 task_queue_factory_.get()));
mflodmancc3d4422017-08-03 08:27:51 -0700334 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
335 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700336 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -0700337 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
338 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200339 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -0700340 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800341 }
342
343 void ResetEncoder(const std::string& payload_name,
344 size_t num_streams,
345 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700346 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700347 bool screenshare) {
Niels Möller259a4972018-04-05 15:36:51 +0200348 video_send_config_.rtp.payload_name = payload_name;
asapersson5f7226f2016-11-25 04:37:00 -0800349
350 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200351 video_encoder_config.codec_type = PayloadStringToCodecType(payload_name);
asapersson5f7226f2016-11-25 04:37:00 -0800352 video_encoder_config.number_of_streams = num_streams;
Erik Språngd7329ca2019-02-21 21:19:53 +0100353 video_encoder_config.max_bitrate_bps =
354 num_streams == 1 ? kTargetBitrateBps : kSimulcastTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800355 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700356 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
357 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700358 video_encoder_config.content_type =
359 screenshare ? VideoEncoderConfig::ContentType::kScreen
360 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700361 if (payload_name == "VP9") {
362 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
363 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
364 video_encoder_config.encoder_specific_settings =
365 new rtc::RefCountedObject<
366 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
367 }
Niels Möllerf1338562018-04-26 09:51:47 +0200368 ConfigureEncoder(std::move(video_encoder_config));
perkj26091b12016-09-01 01:17:40 -0700369 }
370
sprang57c2fff2017-01-16 06:24:02 -0800371 VideoFrame CreateFrame(int64_t ntp_time_ms,
372 rtc::Event* destruction_event) const {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100373 VideoFrame frame =
374 VideoFrame::Builder()
375 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
376 destruction_event, codec_width_, codec_height_))
377 .set_timestamp_rtp(99)
378 .set_timestamp_ms(99)
379 .set_rotation(kVideoRotation_0)
380 .build();
sprang57c2fff2017-01-16 06:24:02 -0800381 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700382 return frame;
383 }
384
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100385 VideoFrame CreateFrameWithUpdatedPixel(int64_t ntp_time_ms,
386 rtc::Event* destruction_event,
387 int offset_x) const {
388 VideoFrame frame =
389 VideoFrame::Builder()
390 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
391 destruction_event, codec_width_, codec_height_))
392 .set_timestamp_rtp(99)
393 .set_timestamp_ms(99)
394 .set_rotation(kVideoRotation_0)
395 .set_update_rect({offset_x, 0, 1, 1})
396 .build();
397 frame.set_ntp_time_ms(ntp_time_ms);
398 return frame;
399 }
400
sprang57c2fff2017-01-16 06:24:02 -0800401 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100402 VideoFrame frame =
403 VideoFrame::Builder()
404 .set_video_frame_buffer(
405 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height))
406 .set_timestamp_rtp(99)
407 .set_timestamp_ms(99)
408 .set_rotation(kVideoRotation_0)
409 .build();
sprang57c2fff2017-01-16 06:24:02 -0800410 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700411 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700412 return frame;
413 }
414
Åsa Perssonc29cb2c2019-03-25 12:06:59 +0100415 void VerifyAllocatedBitrate(const VideoBitrateAllocation& expected_bitrate) {
416 MockBitrateObserver bitrate_observer;
417 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
418
419 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
420 .Times(1);
421 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
Erik Språng4c6ca302019-04-08 15:14:01 +0200422 DataRate::bps(kTargetBitrateBps), 0,
423 0);
Åsa Perssonc29cb2c2019-03-25 12:06:59 +0100424
425 video_source_.IncomingCapturedFrame(
426 CreateFrame(1, codec_width_, codec_height_));
427 WaitForEncodedFrame(1);
428 }
429
asapersson02465b82017-04-10 01:12:52 -0700430 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700431 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700432 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
433 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700434 }
435
asapersson09f05612017-05-15 23:40:18 -0700436 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
437 const rtc::VideoSinkWants& wants2) {
438 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
439 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
440 }
441
Åsa Persson8c1bf952018-09-13 10:42:19 +0200442 void VerifyFpsMaxResolutionMax(const rtc::VideoSinkWants& wants) {
443 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
444 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
445 EXPECT_FALSE(wants.target_pixel_count);
446 }
447
asapersson09f05612017-05-15 23:40:18 -0700448 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
449 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200450 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700451 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
452 EXPECT_GT(wants1.max_pixel_count, 0);
453 }
454
455 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
456 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200457 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700458 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
459 }
460
asaperssonf7e294d2017-06-13 23:25:22 -0700461 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
462 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200463 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700464 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
465 }
466
467 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
468 const rtc::VideoSinkWants& wants2) {
469 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
470 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
471 }
472
473 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
474 const rtc::VideoSinkWants& wants2) {
475 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
476 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
477 }
478
479 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
480 const rtc::VideoSinkWants& wants2) {
481 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
482 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
483 EXPECT_GT(wants1.max_pixel_count, 0);
484 }
485
486 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
487 const rtc::VideoSinkWants& wants2) {
488 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
489 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
490 }
491
asapersson09f05612017-05-15 23:40:18 -0700492 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
493 int pixel_count) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200494 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700495 EXPECT_LT(wants.max_pixel_count, pixel_count);
496 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700497 }
498
499 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
500 EXPECT_LT(wants.max_framerate_fps, fps);
501 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
502 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700503 }
504
asaperssonf7e294d2017-06-13 23:25:22 -0700505 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
506 int expected_fps) {
507 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
508 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
509 EXPECT_FALSE(wants.target_pixel_count);
510 }
511
Jonathan Yubc771b72017-12-08 17:04:29 -0800512 void VerifyBalancedModeFpsRange(const rtc::VideoSinkWants& wants,
513 int last_frame_pixels) {
514 // Balanced mode should always scale FPS to the desired range before
515 // attempting to scale resolution.
516 int fps_limit = wants.max_framerate_fps;
517 if (last_frame_pixels <= 320 * 240) {
518 EXPECT_TRUE(7 <= fps_limit && fps_limit <= 10);
519 } else if (last_frame_pixels <= 480 * 270) {
520 EXPECT_TRUE(10 <= fps_limit && fps_limit <= 15);
521 } else if (last_frame_pixels <= 640 * 480) {
522 EXPECT_LE(15, fps_limit);
523 } else {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200524 EXPECT_EQ(kDefaultFramerate, fps_limit);
Jonathan Yubc771b72017-12-08 17:04:29 -0800525 }
526 }
527
sprang4847ae62017-06-27 07:06:52 -0700528 void WaitForEncodedFrame(int64_t expected_ntp_time) {
529 sink_.WaitForEncodedFrame(expected_ntp_time);
Sebastian Jansson40889f32019-04-17 12:11:20 +0200530 fake_clock_.AdvanceTime(TimeDelta::seconds(1) / max_framerate_);
sprang4847ae62017-06-27 07:06:52 -0700531 }
532
533 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
534 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
Sebastian Jansson40889f32019-04-17 12:11:20 +0200535 fake_clock_.AdvanceTime(TimeDelta::seconds(1) / max_framerate_);
sprang4847ae62017-06-27 07:06:52 -0700536 return ok;
537 }
538
539 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
540 sink_.WaitForEncodedFrame(expected_width, expected_height);
Sebastian Jansson40889f32019-04-17 12:11:20 +0200541 fake_clock_.AdvanceTime(TimeDelta::seconds(1) / max_framerate_);
sprang4847ae62017-06-27 07:06:52 -0700542 }
543
544 void ExpectDroppedFrame() {
545 sink_.ExpectDroppedFrame();
Sebastian Jansson40889f32019-04-17 12:11:20 +0200546 fake_clock_.AdvanceTime(TimeDelta::seconds(1) / max_framerate_);
sprang4847ae62017-06-27 07:06:52 -0700547 }
548
549 bool WaitForFrame(int64_t timeout_ms) {
550 bool ok = sink_.WaitForFrame(timeout_ms);
Sebastian Jansson40889f32019-04-17 12:11:20 +0200551 fake_clock_.AdvanceTime(TimeDelta::seconds(1) / max_framerate_);
sprang4847ae62017-06-27 07:06:52 -0700552 return ok;
553 }
554
perkj26091b12016-09-01 01:17:40 -0700555 class TestEncoder : public test::FakeEncoder {
556 public:
Niels Möllerc572ff32018-11-07 08:43:50 +0100557 TestEncoder() : FakeEncoder(Clock::GetRealTimeClock()) {}
perkj26091b12016-09-01 01:17:40 -0700558
asaperssonfab67072017-04-04 05:51:49 -0700559 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800560 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700561 return config_;
562 }
563
564 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800565 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700566 block_next_encode_ = true;
567 }
568
Erik Språngaed30702018-11-05 12:57:17 +0100569 VideoEncoder::EncoderInfo GetEncoderInfo() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800570 rtc::CritScope lock(&local_crit_sect_);
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100571 EncoderInfo info;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100572 if (initialized_ == EncoderState::kInitialized) {
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100573 if (quality_scaling_) {
574 info.scaling_settings =
575 VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
576 }
577 info.is_hardware_accelerated = is_hardware_accelerated_;
Åsa Perssonc29cb2c2019-03-25 12:06:59 +0100578 for (int i = 0; i < kMaxSpatialLayers; ++i) {
579 if (temporal_layers_supported_[i]) {
580 int num_layers = temporal_layers_supported_[i].value() ? 2 : 1;
581 info.fps_allocation[i].resize(num_layers);
582 }
583 }
Erik Språngaed30702018-11-05 12:57:17 +0100584 }
585 return info;
kthelgason876222f2016-11-29 01:44:11 -0800586 }
587
Erik Språngb7cb7b52019-02-26 15:52:33 +0100588 int32_t RegisterEncodeCompleteCallback(
589 EncodedImageCallback* callback) override {
590 rtc::CritScope lock(&local_crit_sect_);
591 encoded_image_callback_ = callback;
592 return FakeEncoder::RegisterEncodeCompleteCallback(callback);
593 }
594
perkjfa10b552016-10-02 23:45:26 -0700595 void ContinueEncode() { continue_encode_event_.Set(); }
596
597 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
598 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800599 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700600 EXPECT_EQ(timestamp_, timestamp);
601 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
602 }
603
kthelgason2fc52542017-03-03 00:24:41 -0800604 void SetQualityScaling(bool b) {
605 rtc::CritScope lock(&local_crit_sect_);
606 quality_scaling_ = b;
607 }
kthelgasonad9010c2017-02-14 00:46:51 -0800608
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100609 void SetIsHardwareAccelerated(bool is_hardware_accelerated) {
610 rtc::CritScope lock(&local_crit_sect_);
611 is_hardware_accelerated_ = is_hardware_accelerated;
612 }
613
Åsa Perssonc29cb2c2019-03-25 12:06:59 +0100614 void SetTemporalLayersSupported(size_t spatial_idx, bool supported) {
615 RTC_DCHECK_LT(spatial_idx, kMaxSpatialLayers);
616 rtc::CritScope lock(&local_crit_sect_);
617 temporal_layers_supported_[spatial_idx] = supported;
618 }
619
sprangfe627f32017-03-29 08:24:59 -0700620 void ForceInitEncodeFailure(bool force_failure) {
621 rtc::CritScope lock(&local_crit_sect_);
622 force_init_encode_failed_ = force_failure;
623 }
624
Niels Möller6bb5ab92019-01-11 11:11:10 +0100625 void SimulateOvershoot(double rate_factor) {
626 rtc::CritScope lock(&local_crit_sect_);
627 rate_factor_ = rate_factor;
628 }
629
Erik Språngd7329ca2019-02-21 21:19:53 +0100630 uint32_t GetLastFramerate() const {
Niels Möller6bb5ab92019-01-11 11:11:10 +0100631 rtc::CritScope lock(&local_crit_sect_);
632 return last_framerate_;
633 }
634
Erik Språngd7329ca2019-02-21 21:19:53 +0100635 VideoFrame::UpdateRect GetLastUpdateRect() const {
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100636 rtc::CritScope lock(&local_crit_sect_);
637 return last_update_rect_;
638 }
639
Niels Möller87e2d782019-03-07 10:18:23 +0100640 const std::vector<VideoFrameType>& LastFrameTypes() const {
Erik Språngd7329ca2019-02-21 21:19:53 +0100641 rtc::CritScope lock(&local_crit_sect_);
642 return last_frame_types_;
643 }
644
645 void InjectFrame(const VideoFrame& input_image, bool keyframe) {
Niels Möller87e2d782019-03-07 10:18:23 +0100646 const std::vector<VideoFrameType> frame_type = {
Niels Möller8f7ce222019-03-21 15:43:58 +0100647 keyframe ? VideoFrameType::kVideoFrameKey
648 : VideoFrameType::kVideoFrameDelta};
Erik Språngd7329ca2019-02-21 21:19:53 +0100649 {
650 rtc::CritScope lock(&local_crit_sect_);
651 last_frame_types_ = frame_type;
652 }
Niels Möllerb859b322019-03-07 12:40:01 +0100653 FakeEncoder::Encode(input_image, &frame_type);
Erik Språngd7329ca2019-02-21 21:19:53 +0100654 }
655
Erik Språngb7cb7b52019-02-26 15:52:33 +0100656 void InjectEncodedImage(const EncodedImage& image) {
657 rtc::CritScope lock(&local_crit_sect_);
658 encoded_image_callback_->OnEncodedImage(image, nullptr, nullptr);
659 }
660
Erik Språngd7329ca2019-02-21 21:19:53 +0100661 void ExpectNullFrame() {
662 rtc::CritScope lock(&local_crit_sect_);
663 expect_null_frame_ = true;
664 }
665
666 absl::optional<VideoBitrateAllocation> GetAndResetLastBitrateAllocation() {
667 auto allocation = last_bitrate_allocation_;
668 last_bitrate_allocation_.reset();
669 return allocation;
670 }
671
perkjfa10b552016-10-02 23:45:26 -0700672 private:
perkj26091b12016-09-01 01:17:40 -0700673 int32_t Encode(const VideoFrame& input_image,
Niels Möller87e2d782019-03-07 10:18:23 +0100674 const std::vector<VideoFrameType>* frame_types) override {
perkj26091b12016-09-01 01:17:40 -0700675 bool block_encode;
676 {
brandtre78d2662017-01-16 05:57:16 -0800677 rtc::CritScope lock(&local_crit_sect_);
Erik Språngd7329ca2019-02-21 21:19:53 +0100678 if (expect_null_frame_) {
679 EXPECT_EQ(input_image.timestamp(), 0u);
680 EXPECT_EQ(input_image.width(), 1);
681 last_frame_types_ = *frame_types;
682 expect_null_frame_ = false;
683 } else {
684 EXPECT_GT(input_image.timestamp(), timestamp_);
685 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
686 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
687 }
perkj26091b12016-09-01 01:17:40 -0700688
689 timestamp_ = input_image.timestamp();
690 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700691 last_input_width_ = input_image.width();
692 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700693 block_encode = block_next_encode_;
694 block_next_encode_ = false;
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100695 last_update_rect_ = input_image.update_rect();
Erik Språngd7329ca2019-02-21 21:19:53 +0100696 last_frame_types_ = *frame_types;
perkj26091b12016-09-01 01:17:40 -0700697 }
Niels Möllerb859b322019-03-07 12:40:01 +0100698 int32_t result = FakeEncoder::Encode(input_image, frame_types);
perkj26091b12016-09-01 01:17:40 -0700699 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700700 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700701 return result;
702 }
703
sprangfe627f32017-03-29 08:24:59 -0700704 int32_t InitEncode(const VideoCodec* config,
705 int32_t number_of_cores,
706 size_t max_payload_size) override {
707 int res =
708 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
709 rtc::CritScope lock(&local_crit_sect_);
Erik Språngb7cb7b52019-02-26 15:52:33 +0100710 EXPECT_EQ(initialized_, EncoderState::kUninitialized);
Erik Språng82fad3d2018-03-21 09:57:23 +0100711 if (config->codecType == kVideoCodecVP8) {
sprangfe627f32017-03-29 08:24:59 -0700712 // Simulate setting up temporal layers, in order to validate the life
713 // cycle of these objects.
Elad Aloncde8ab22019-03-20 11:56:20 +0100714 Vp8TemporalLayersFactory factory;
715 frame_buffer_controller_ = factory.Create(*config);
sprangfe627f32017-03-29 08:24:59 -0700716 }
Erik Språngb7cb7b52019-02-26 15:52:33 +0100717 if (force_init_encode_failed_) {
718 initialized_ = EncoderState::kInitializationFailed;
sprangfe627f32017-03-29 08:24:59 -0700719 return -1;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100720 }
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100721
Erik Språngb7cb7b52019-02-26 15:52:33 +0100722 initialized_ = EncoderState::kInitialized;
sprangfe627f32017-03-29 08:24:59 -0700723 return res;
724 }
725
Erik Språngb7cb7b52019-02-26 15:52:33 +0100726 int32_t Release() override {
727 rtc::CritScope lock(&local_crit_sect_);
728 EXPECT_NE(initialized_, EncoderState::kUninitialized);
729 initialized_ = EncoderState::kUninitialized;
730 return FakeEncoder::Release();
731 }
732
Erik Språng16cb8f52019-04-12 13:59:09 +0200733 void SetRates(const RateControlParameters& parameters) {
Niels Möller6bb5ab92019-01-11 11:11:10 +0100734 rtc::CritScope lock(&local_crit_sect_);
735 VideoBitrateAllocation adjusted_rate_allocation;
736 for (size_t si = 0; si < kMaxSpatialLayers; ++si) {
737 for (size_t ti = 0; ti < kMaxTemporalStreams; ++ti) {
Erik Språng16cb8f52019-04-12 13:59:09 +0200738 if (parameters.bitrate.HasBitrate(si, ti)) {
Niels Möller6bb5ab92019-01-11 11:11:10 +0100739 adjusted_rate_allocation.SetBitrate(
740 si, ti,
Erik Språng16cb8f52019-04-12 13:59:09 +0200741 static_cast<uint32_t>(parameters.bitrate.GetBitrate(si, ti) *
Niels Möller6bb5ab92019-01-11 11:11:10 +0100742 rate_factor_));
743 }
744 }
745 }
Erik Språng16cb8f52019-04-12 13:59:09 +0200746 last_framerate_ = static_cast<uint32_t>(parameters.framerate_fps + 0.5);
747 last_bitrate_allocation_ = parameters.bitrate;
748 RateControlParameters adjusted_paramters = parameters;
749 adjusted_paramters.bitrate = adjusted_rate_allocation;
750 FakeEncoder::SetRates(adjusted_paramters);
Niels Möller6bb5ab92019-01-11 11:11:10 +0100751 }
752
brandtre78d2662017-01-16 05:57:16 -0800753 rtc::CriticalSection local_crit_sect_;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100754 enum class EncoderState {
755 kUninitialized,
756 kInitializationFailed,
757 kInitialized
758 } initialized_ RTC_GUARDED_BY(local_crit_sect_) =
759 EncoderState::kUninitialized;
danilchapa37de392017-09-09 04:17:22 -0700760 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700761 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700762 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
763 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
764 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
765 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
766 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100767 bool is_hardware_accelerated_ RTC_GUARDED_BY(local_crit_sect_) = false;
Elad Aloncde8ab22019-03-20 11:56:20 +0100768 std::unique_ptr<Vp8FrameBufferController> frame_buffer_controller_
danilchapa37de392017-09-09 04:17:22 -0700769 RTC_GUARDED_BY(local_crit_sect_);
Åsa Perssonc29cb2c2019-03-25 12:06:59 +0100770 absl::optional<bool>
771 temporal_layers_supported_[kMaxSpatialLayers] RTC_GUARDED_BY(
772 local_crit_sect_);
danilchapa37de392017-09-09 04:17:22 -0700773 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
Niels Möller6bb5ab92019-01-11 11:11:10 +0100774 double rate_factor_ RTC_GUARDED_BY(local_crit_sect_) = 1.0;
775 uint32_t last_framerate_ RTC_GUARDED_BY(local_crit_sect_) = 0;
Erik Språngd7329ca2019-02-21 21:19:53 +0100776 absl::optional<VideoBitrateAllocation> last_bitrate_allocation_;
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100777 VideoFrame::UpdateRect last_update_rect_
778 RTC_GUARDED_BY(local_crit_sect_) = {0, 0, 0, 0};
Niels Möller87e2d782019-03-07 10:18:23 +0100779 std::vector<VideoFrameType> last_frame_types_;
Erik Språngd7329ca2019-02-21 21:19:53 +0100780 bool expect_null_frame_ = false;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100781 EncodedImageCallback* encoded_image_callback_
782 RTC_GUARDED_BY(local_crit_sect_) = nullptr;
perkj26091b12016-09-01 01:17:40 -0700783 };
784
mflodmancc3d4422017-08-03 08:27:51 -0700785 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700786 public:
787 explicit TestSink(TestEncoder* test_encoder)
Niels Möllerc572ff32018-11-07 08:43:50 +0100788 : test_encoder_(test_encoder) {}
perkj26091b12016-09-01 01:17:40 -0700789
perkj26091b12016-09-01 01:17:40 -0700790 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700791 EXPECT_TRUE(
792 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
793 }
794
795 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
796 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700797 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700798 if (!encoded_frame_event_.Wait(timeout_ms))
799 return false;
perkj26091b12016-09-01 01:17:40 -0700800 {
801 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800802 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700803 }
804 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700805 return true;
perkj26091b12016-09-01 01:17:40 -0700806 }
807
sprangb1ca0732017-02-01 08:38:12 -0800808 void WaitForEncodedFrame(uint32_t expected_width,
809 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700810 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100811 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700812 }
813
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100814 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700815 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800816 uint32_t width = 0;
817 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800818 {
819 rtc::CritScope lock(&crit_);
820 width = last_width_;
821 height = last_height_;
822 }
823 EXPECT_EQ(expected_height, height);
824 EXPECT_EQ(expected_width, width);
825 }
826
kthelgason2fc52542017-03-03 00:24:41 -0800827 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800828
sprangc5d62e22017-04-02 23:53:04 -0700829 bool WaitForFrame(int64_t timeout_ms) {
830 return encoded_frame_event_.Wait(timeout_ms);
831 }
832
perkj26091b12016-09-01 01:17:40 -0700833 void SetExpectNoFrames() {
834 rtc::CritScope lock(&crit_);
835 expect_frames_ = false;
836 }
837
asaperssonfab67072017-04-04 05:51:49 -0700838 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200839 rtc::CritScope lock(&crit_);
840 return number_of_reconfigurations_;
841 }
842
asaperssonfab67072017-04-04 05:51:49 -0700843 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200844 rtc::CritScope lock(&crit_);
845 return min_transmit_bitrate_bps_;
846 }
847
Erik Språngd7329ca2019-02-21 21:19:53 +0100848 void SetNumExpectedLayers(size_t num_layers) {
849 rtc::CritScope lock(&crit_);
850 num_expected_layers_ = num_layers;
851 }
852
Erik Språngb7cb7b52019-02-26 15:52:33 +0100853 int64_t GetLastCaptureTimeMs() const {
854 rtc::CritScope lock(&crit_);
855 return last_capture_time_ms_;
856 }
857
perkj26091b12016-09-01 01:17:40 -0700858 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700859 Result OnEncodedImage(
860 const EncodedImage& encoded_image,
861 const CodecSpecificInfo* codec_specific_info,
862 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200863 rtc::CritScope lock(&crit_);
864 EXPECT_TRUE(expect_frames_);
Erik Språngd7329ca2019-02-21 21:19:53 +0100865 uint32_t timestamp = encoded_image.Timestamp();
866 if (last_timestamp_ != timestamp) {
867 num_received_layers_ = 1;
868 } else {
869 ++num_received_layers_;
870 }
871 last_timestamp_ = timestamp;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100872 last_capture_time_ms_ = encoded_image.capture_time_ms_;
sprangb1ca0732017-02-01 08:38:12 -0800873 last_width_ = encoded_image._encodedWidth;
874 last_height_ = encoded_image._encodedHeight;
Erik Språngd7329ca2019-02-21 21:19:53 +0100875 if (num_received_layers_ == num_expected_layers_) {
876 encoded_frame_event_.Set();
877 }
sprangb1ca0732017-02-01 08:38:12 -0800878 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200879 }
880
Rasmus Brandtc402dbe2019-02-04 11:09:46 +0100881 void OnEncoderConfigurationChanged(
882 std::vector<VideoStream> streams,
883 VideoEncoderConfig::ContentType content_type,
884 int min_transmit_bitrate_bps) override {
Per512ecb32016-09-23 15:52:06 +0200885 rtc::CriticalSection crit_;
886 ++number_of_reconfigurations_;
887 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
888 }
889
perkj26091b12016-09-01 01:17:40 -0700890 rtc::CriticalSection crit_;
891 TestEncoder* test_encoder_;
892 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800893 uint32_t last_timestamp_ = 0;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100894 int64_t last_capture_time_ms_ = 0;
sprangb1ca0732017-02-01 08:38:12 -0800895 uint32_t last_height_ = 0;
896 uint32_t last_width_ = 0;
Erik Språngd7329ca2019-02-21 21:19:53 +0100897 size_t num_expected_layers_ = 1;
898 size_t num_received_layers_ = 0;
perkj26091b12016-09-01 01:17:40 -0700899 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200900 int number_of_reconfigurations_ = 0;
901 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700902 };
903
904 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100905 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200906 int codec_width_;
907 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700908 int max_framerate_;
Danil Chapovalovd3ba2362019-04-10 17:01:23 +0200909 const std::unique_ptr<TaskQueueFactory> task_queue_factory_;
perkj26091b12016-09-01 01:17:40 -0700910 TestEncoder fake_encoder_;
Niels Möllercbcbc222018-09-28 09:07:24 +0200911 test::VideoEncoderProxyFactory encoder_factory_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800912 std::unique_ptr<VideoBitrateAllocatorFactory> bitrate_allocator_factory_;
sprangc5d62e22017-04-02 23:53:04 -0700913 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700914 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800915 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700916 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700917 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700918};
919
mflodmancc3d4422017-08-03 08:27:51 -0700920TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
Erik Språng4c6ca302019-04-08 15:14:01 +0200921 video_stream_encoder_->OnBitrateUpdated(
922 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möllerc572ff32018-11-07 08:43:50 +0100923 rtc::Event frame_destroyed_event;
perkja49cbd32016-09-16 07:53:41 -0700924 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700925 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700926 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700927 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700928}
929
mflodmancc3d4422017-08-03 08:27:51 -0700930TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700931 // Dropped since no target bitrate has been set.
Niels Möllerc572ff32018-11-07 08:43:50 +0100932 rtc::Event frame_destroyed_event;
Sebastian Janssona3177052018-04-10 13:05:49 +0200933 // The encoder will cache up to one frame for a short duration. Adding two
934 // frames means that the first frame will be dropped and the second frame will
935 // be sent when the encoder is enabled.
perkja49cbd32016-09-16 07:53:41 -0700936 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
Sebastian Janssona3177052018-04-10 13:05:49 +0200937 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkja49cbd32016-09-16 07:53:41 -0700938 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700939
Erik Språng4c6ca302019-04-08 15:14:01 +0200940 video_stream_encoder_->OnBitrateUpdated(
941 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkj26091b12016-09-01 01:17:40 -0700942
Sebastian Janssona3177052018-04-10 13:05:49 +0200943 // The pending frame should be received.
sprang4847ae62017-06-27 07:06:52 -0700944 WaitForEncodedFrame(2);
Sebastian Janssona3177052018-04-10 13:05:49 +0200945 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
946
947 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700948 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700949}
950
mflodmancc3d4422017-08-03 08:27:51 -0700951TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
Erik Språng4c6ca302019-04-08 15:14:01 +0200952 video_stream_encoder_->OnBitrateUpdated(
953 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700954 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700955 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700956
Erik Språng4c6ca302019-04-08 15:14:01 +0200957 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(0), DataRate::bps(0), 0,
Erik Språng610c7632019-03-06 15:37:33 +0100958 0);
Sebastian Janssona3177052018-04-10 13:05:49 +0200959 // The encoder will cache up to one frame for a short duration. Adding two
960 // frames means that the first frame will be dropped and the second frame will
961 // be sent when the encoder is resumed.
perkja49cbd32016-09-16 07:53:41 -0700962 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Sebastian Janssona3177052018-04-10 13:05:49 +0200963 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700964
Erik Språng4c6ca302019-04-08 15:14:01 +0200965 video_stream_encoder_->OnBitrateUpdated(
966 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
sprang4847ae62017-06-27 07:06:52 -0700967 WaitForEncodedFrame(3);
Sebastian Janssona3177052018-04-10 13:05:49 +0200968 video_source_.IncomingCapturedFrame(CreateFrame(4, nullptr));
969 WaitForEncodedFrame(4);
mflodmancc3d4422017-08-03 08:27:51 -0700970 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700971}
972
mflodmancc3d4422017-08-03 08:27:51 -0700973TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
Erik Språng4c6ca302019-04-08 15:14:01 +0200974 video_stream_encoder_->OnBitrateUpdated(
975 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700976 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700977 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700978
979 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700980 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700981
perkja49cbd32016-09-16 07:53:41 -0700982 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700983 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700984 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700985}
986
mflodmancc3d4422017-08-03 08:27:51 -0700987TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
Erik Språng4c6ca302019-04-08 15:14:01 +0200988 video_stream_encoder_->OnBitrateUpdated(
989 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkj26091b12016-09-01 01:17:40 -0700990
perkja49cbd32016-09-16 07:53:41 -0700991 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700992 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700993
mflodmancc3d4422017-08-03 08:27:51 -0700994 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700995 sink_.SetExpectNoFrames();
Niels Möllerc572ff32018-11-07 08:43:50 +0100996 rtc::Event frame_destroyed_event;
perkja49cbd32016-09-16 07:53:41 -0700997 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
998 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700999}
1000
mflodmancc3d4422017-08-03 08:27:51 -07001001TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001002 video_stream_encoder_->OnBitrateUpdated(
1003 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkj26091b12016-09-01 01:17:40 -07001004
1005 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -07001006 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001007 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -07001008 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
1009 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -07001010 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
1011 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -07001012 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -07001013 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -07001014
mflodmancc3d4422017-08-03 08:27:51 -07001015 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -07001016}
1017
mflodmancc3d4422017-08-03 08:27:51 -07001018TEST_F(VideoStreamEncoderTest,
1019 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001020 video_stream_encoder_->OnBitrateUpdated(
1021 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Per21d45d22016-10-30 21:37:57 +01001022 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +02001023
1024 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +02001025 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001026 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +01001027 // The encoder will have been configured once when the first frame is
1028 // received.
1029 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +02001030
1031 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02001032 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +02001033 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -07001034 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001035 kMaxPayloadLength);
Per512ecb32016-09-23 15:52:06 +02001036
1037 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +02001038 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001039 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +01001040 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -07001041 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -07001042
mflodmancc3d4422017-08-03 08:27:51 -07001043 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -07001044}
1045
mflodmancc3d4422017-08-03 08:27:51 -07001046TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001047 video_stream_encoder_->OnBitrateUpdated(
1048 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkjfa10b552016-10-02 23:45:26 -07001049
1050 // Capture a frame and wait for it to synchronize with the encoder thread.
1051 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001052 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +01001053 // The encoder will have been configured once.
1054 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -07001055 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
1056 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
1057
1058 codec_width_ *= 2;
1059 codec_height_ *= 2;
1060 // Capture a frame with a higher resolution and wait for it to synchronize
1061 // with the encoder thread.
1062 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001063 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -07001064 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
1065 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +01001066 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -07001067
mflodmancc3d4422017-08-03 08:27:51 -07001068 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -07001069}
1070
mflodmancc3d4422017-08-03 08:27:51 -07001071TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -07001072 EXPECT_TRUE(video_source_.has_sinks());
1073 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001074 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001075 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001076 EXPECT_FALSE(video_source_.has_sinks());
1077 EXPECT_TRUE(new_video_source.has_sinks());
1078
mflodmancc3d4422017-08-03 08:27:51 -07001079 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001080}
1081
mflodmancc3d4422017-08-03 08:27:51 -07001082TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -07001083 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -07001084 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -07001085 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -07001086 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001087}
1088
Jonathan Yubc771b72017-12-08 17:04:29 -08001089TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
1090 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -07001091 const int kWidth = 1280;
1092 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -08001093
1094 // We rely on the automatic resolution adaptation, but we handle framerate
1095 // adaptation manually by mocking the stats proxy.
1096 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -07001097
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001098 // Enable BALANCED preference, no initial limitation.
Erik Språng4c6ca302019-04-08 15:14:01 +02001099 video_stream_encoder_->OnBitrateUpdated(
1100 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001101 video_stream_encoder_->SetSource(&video_source_,
1102 webrtc::DegradationPreference::BALANCED);
Jonathan Yubc771b72017-12-08 17:04:29 -08001103 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001104 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001105 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -07001106 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1107
Jonathan Yubc771b72017-12-08 17:04:29 -08001108 // Adapt down as far as possible.
1109 rtc::VideoSinkWants last_wants;
1110 int64_t t = 1;
1111 int loop_count = 0;
1112 do {
1113 ++loop_count;
1114 last_wants = video_source_.sink_wants();
1115
1116 // Simulate the framerate we've been asked to adapt to.
1117 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
1118 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
1119 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1120 mock_stats.input_frame_rate = fps;
1121 stats_proxy_->SetMockStats(mock_stats);
1122
1123 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1124 sink_.WaitForEncodedFrame(t);
1125 t += frame_interval_ms;
1126
mflodmancc3d4422017-08-03 08:27:51 -07001127 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08001128 VerifyBalancedModeFpsRange(
1129 video_source_.sink_wants(),
1130 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1131 } while (video_source_.sink_wants().max_pixel_count <
1132 last_wants.max_pixel_count ||
1133 video_source_.sink_wants().max_framerate_fps <
1134 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001135
Jonathan Yubc771b72017-12-08 17:04:29 -08001136 // Verify that we've adapted all the way down.
1137 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001138 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001139 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
1140 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -07001141 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -08001142 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
1143 *video_source_.last_sent_height());
1144 EXPECT_EQ(kMinBalancedFramerateFps,
1145 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001146
Jonathan Yubc771b72017-12-08 17:04:29 -08001147 // Adapt back up the same number of times we adapted down.
1148 for (int i = 0; i < loop_count - 1; ++i) {
1149 last_wants = video_source_.sink_wants();
1150
1151 // Simulate the framerate we've been asked to adapt to.
1152 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
1153 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
1154 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1155 mock_stats.input_frame_rate = fps;
1156 stats_proxy_->SetMockStats(mock_stats);
1157
1158 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1159 sink_.WaitForEncodedFrame(t);
1160 t += frame_interval_ms;
1161
mflodmancc3d4422017-08-03 08:27:51 -07001162 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -08001163 VerifyBalancedModeFpsRange(
1164 video_source_.sink_wants(),
1165 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1166 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
1167 last_wants.max_pixel_count ||
1168 video_source_.sink_wants().max_framerate_fps >
1169 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001170 }
1171
Åsa Persson8c1bf952018-09-13 10:42:19 +02001172 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001173 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001174 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001175 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1176 EXPECT_EQ((loop_count - 1) * 2,
1177 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -07001178
mflodmancc3d4422017-08-03 08:27:51 -07001179 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001180}
mflodmancc3d4422017-08-03 08:27:51 -07001181TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001182 video_stream_encoder_->OnBitrateUpdated(
1183 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001184 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001185
sprangc5d62e22017-04-02 23:53:04 -07001186 const int kFrameWidth = 1280;
1187 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07001188
Åsa Persson8c1bf952018-09-13 10:42:19 +02001189 int64_t frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -07001190
kthelgason5e13d412016-12-01 03:59:51 -08001191 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001192 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001193 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001194 frame_timestamp += kFrameIntervalMs;
1195
perkj803d97f2016-11-01 11:45:46 -07001196 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001197 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001198 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001199 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001200 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001201 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -07001202
asapersson0944a802017-04-07 00:57:58 -07001203 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -07001204 // wanted resolution.
1205 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
1206 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
1207 kFrameWidth * kFrameHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001208 EXPECT_EQ(kDefaultFramerate, video_source_.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001209
1210 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -07001211 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001212 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001213 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001214
sprangc5d62e22017-04-02 23:53:04 -07001215 // Initially no degradation registered.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001216 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001217
sprangc5d62e22017-04-02 23:53:04 -07001218 // Force an input frame rate to be available, or the adaptation call won't
1219 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -07001220 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -07001221 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -07001222 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -07001223 stats_proxy_->SetMockStats(stats);
1224
mflodmancc3d4422017-08-03 08:27:51 -07001225 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001226 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001227 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001228 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001229 frame_timestamp += kFrameIntervalMs;
1230
1231 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001232 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001233 EXPECT_EQ(std::numeric_limits<int>::max(),
1234 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001235 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001236
asapersson02465b82017-04-10 01:12:52 -07001237 // Turn off degradation completely.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001238 video_stream_encoder_->SetSource(&new_video_source,
1239 webrtc::DegradationPreference::DISABLED);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001240 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001241
mflodmancc3d4422017-08-03 08:27:51 -07001242 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001243 new_video_source.IncomingCapturedFrame(
1244 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001245 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001246 frame_timestamp += kFrameIntervalMs;
1247
1248 // Still no degradation.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001249 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001250
1251 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001252 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001253 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
sprangc5d62e22017-04-02 23:53:04 -07001254 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1255 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001256 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001257 EXPECT_EQ(kDefaultFramerate, new_video_source.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001258
1259 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001260 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001261 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001262 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1263 EXPECT_EQ(std::numeric_limits<int>::max(),
1264 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001265 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001266
mflodmancc3d4422017-08-03 08:27:51 -07001267 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001268}
1269
mflodmancc3d4422017-08-03 08:27:51 -07001270TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001271 video_stream_encoder_->OnBitrateUpdated(
1272 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001273
asaperssonfab67072017-04-04 05:51:49 -07001274 const int kWidth = 1280;
1275 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001276 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001277 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001278 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1279 EXPECT_FALSE(stats.bw_limited_resolution);
1280 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1281
1282 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001283 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001284 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001285 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001286
1287 stats = stats_proxy_->GetStats();
1288 EXPECT_TRUE(stats.bw_limited_resolution);
1289 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1290
1291 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001292 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001293 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001294 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001295
1296 stats = stats_proxy_->GetStats();
1297 EXPECT_FALSE(stats.bw_limited_resolution);
1298 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1299 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1300
mflodmancc3d4422017-08-03 08:27:51 -07001301 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001302}
1303
mflodmancc3d4422017-08-03 08:27:51 -07001304TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001305 video_stream_encoder_->OnBitrateUpdated(
1306 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001307
1308 const int kWidth = 1280;
1309 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001310 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001311 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001312 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1313 EXPECT_FALSE(stats.cpu_limited_resolution);
1314 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1315
1316 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001317 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001318 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001319 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001320
1321 stats = stats_proxy_->GetStats();
1322 EXPECT_TRUE(stats.cpu_limited_resolution);
1323 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1324
1325 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001326 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001327 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001328 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001329
1330 stats = stats_proxy_->GetStats();
1331 EXPECT_FALSE(stats.cpu_limited_resolution);
1332 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001333 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001334
mflodmancc3d4422017-08-03 08:27:51 -07001335 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001336}
1337
mflodmancc3d4422017-08-03 08:27:51 -07001338TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001339 video_stream_encoder_->OnBitrateUpdated(
1340 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001341
asaperssonfab67072017-04-04 05:51:49 -07001342 const int kWidth = 1280;
1343 const int kHeight = 720;
1344 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001345 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001346 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001347 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001348 EXPECT_FALSE(stats.cpu_limited_resolution);
1349 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1350
asaperssonfab67072017-04-04 05:51:49 -07001351 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001352 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001353 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001354 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001355 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001356 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001357 EXPECT_TRUE(stats.cpu_limited_resolution);
1358 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1359
1360 // Set new source with adaptation still enabled.
1361 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001362 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001363 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001364
asaperssonfab67072017-04-04 05:51:49 -07001365 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001366 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001367 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001368 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001369 EXPECT_TRUE(stats.cpu_limited_resolution);
1370 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1371
1372 // Set adaptation disabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001373 video_stream_encoder_->SetSource(&new_video_source,
1374 webrtc::DegradationPreference::DISABLED);
kthelgason876222f2016-11-29 01:44:11 -08001375
asaperssonfab67072017-04-04 05:51:49 -07001376 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001377 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001378 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001379 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001380 EXPECT_FALSE(stats.cpu_limited_resolution);
1381 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1382
1383 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001384 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001385 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001386
asaperssonfab67072017-04-04 05:51:49 -07001387 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001388 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001389 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001390 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001391 EXPECT_TRUE(stats.cpu_limited_resolution);
1392 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1393
asaperssonfab67072017-04-04 05:51:49 -07001394 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001395 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001396 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001397 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001398 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001399 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001400 EXPECT_FALSE(stats.cpu_limited_resolution);
1401 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001402 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001403
mflodmancc3d4422017-08-03 08:27:51 -07001404 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001405}
1406
mflodmancc3d4422017-08-03 08:27:51 -07001407TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001408 video_stream_encoder_->OnBitrateUpdated(
1409 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001410
asaperssonfab67072017-04-04 05:51:49 -07001411 const int kWidth = 1280;
1412 const int kHeight = 720;
1413 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001414 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001415 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001416 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001417 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001418 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001419
1420 // Set new source with adaptation still enabled.
1421 test::FrameForwarder new_video_source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001422 video_stream_encoder_->SetSource(&new_video_source,
1423 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001424
asaperssonfab67072017-04-04 05:51:49 -07001425 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001426 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001427 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001428 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001429 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001430 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001431
asaperssonfab67072017-04-04 05:51:49 -07001432 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001433 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001434 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001435 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001436 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001437 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001438 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001439 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001440
asaperssonfab67072017-04-04 05:51:49 -07001441 // Set new source with adaptation still enabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001442 video_stream_encoder_->SetSource(&new_video_source,
1443 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001444
asaperssonfab67072017-04-04 05:51:49 -07001445 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001446 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001447 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001448 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001449 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001450 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001451
asapersson02465b82017-04-10 01:12:52 -07001452 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001453 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001454 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001455
asaperssonfab67072017-04-04 05:51:49 -07001456 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001457 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001458 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001459 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001460 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001461 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1462 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001463
mflodmancc3d4422017-08-03 08:27:51 -07001464 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001465}
1466
mflodmancc3d4422017-08-03 08:27:51 -07001467TEST_F(VideoStreamEncoderTest,
1468 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001469 video_stream_encoder_->OnBitrateUpdated(
1470 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001471
1472 const int kWidth = 1280;
1473 const int kHeight = 720;
Åsa Persson8c1bf952018-09-13 10:42:19 +02001474 int64_t timestamp_ms = kFrameIntervalMs;
asapersson36e9eb42017-03-31 05:29:12 -07001475 video_source_.set_adaptation_enabled(true);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001476 video_source_.IncomingCapturedFrame(
1477 CreateFrame(timestamp_ms, kWidth, kHeight));
1478 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001479 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1480 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1481 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1482
1483 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001484 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001485 timestamp_ms += kFrameIntervalMs;
1486 video_source_.IncomingCapturedFrame(
1487 CreateFrame(timestamp_ms, kWidth, kHeight));
1488 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001489 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1490 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1491 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1492
1493 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001494 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001495 timestamp_ms += kFrameIntervalMs;
1496 video_source_.IncomingCapturedFrame(
1497 CreateFrame(timestamp_ms, kWidth, kHeight));
1498 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001499 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1500 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1501 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1502
Niels Möller4db138e2018-04-19 09:04:13 +02001503 // Leave source unchanged, but disable quality scaler.
asapersson36e9eb42017-03-31 05:29:12 -07001504 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02001505
1506 VideoEncoderConfig video_encoder_config;
1507 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
1508 // Make format different, to force recreation of encoder.
1509 video_encoder_config.video_format.parameters["foo"] = "foo";
1510 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001511 kMaxPayloadLength);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001512 timestamp_ms += kFrameIntervalMs;
1513 video_source_.IncomingCapturedFrame(
1514 CreateFrame(timestamp_ms, kWidth, kHeight));
1515 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001516 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1517 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1518 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1519
mflodmancc3d4422017-08-03 08:27:51 -07001520 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001521}
1522
mflodmancc3d4422017-08-03 08:27:51 -07001523TEST_F(VideoStreamEncoderTest,
1524 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001525 video_stream_encoder_->OnBitrateUpdated(
1526 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001527
asapersson0944a802017-04-07 00:57:58 -07001528 const int kWidth = 1280;
1529 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001530 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001531
asaperssonfab67072017-04-04 05:51:49 -07001532 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001533 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001534 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001535 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001536 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001537 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1538
asapersson02465b82017-04-10 01:12:52 -07001539 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001540 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001541 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001542 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001543 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001544 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001545 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001546 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1547
1548 // Set new source with adaptation still enabled.
1549 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001550 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001551 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001552
1553 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001554 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001555 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001556 stats = stats_proxy_->GetStats();
1557 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001558 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001559 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1560
sprangc5d62e22017-04-02 23:53:04 -07001561 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001562 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001563 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001564 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001565 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001566 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001567 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001568 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001569 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001570 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001571 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1572
sprangc5d62e22017-04-02 23:53:04 -07001573 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001574 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001575 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1576 mock_stats.input_frame_rate = 30;
1577 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001578 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001579 stats_proxy_->ResetMockStats();
1580
1581 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001582 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001583 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001584
1585 // Framerate now adapted.
1586 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001587 EXPECT_FALSE(stats.cpu_limited_resolution);
1588 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001589 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1590
1591 // Disable CPU adaptation.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001592 video_stream_encoder_->SetSource(&new_video_source,
1593 webrtc::DegradationPreference::DISABLED);
sprangc5d62e22017-04-02 23:53:04 -07001594 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001595 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001596 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001597
1598 stats = stats_proxy_->GetStats();
1599 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001600 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001601 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1602
1603 // Try to trigger overuse. Should not succeed.
1604 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001605 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001606 stats_proxy_->ResetMockStats();
1607
1608 stats = stats_proxy_->GetStats();
1609 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001610 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001611 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1612
1613 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001614 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001615 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssonfab67072017-04-04 05:51:49 -07001616 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001617 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001618 stats = stats_proxy_->GetStats();
1619 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001620 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001621 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001622
1623 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001624 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001625 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001626 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001627 stats = stats_proxy_->GetStats();
1628 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001629 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001630 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1631
1632 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001633 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001634 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001635 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001636 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001637 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001638 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001639 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001640 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001641 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001642 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1643
1644 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001645 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001646 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001647 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001648 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001649 stats = stats_proxy_->GetStats();
1650 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001651 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001652 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001653 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001654
mflodmancc3d4422017-08-03 08:27:51 -07001655 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001656}
1657
mflodmancc3d4422017-08-03 08:27:51 -07001658TEST_F(VideoStreamEncoderTest,
1659 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001660 const int kWidth = 1280;
1661 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02001662 video_stream_encoder_->OnBitrateUpdated(
1663 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001664
asaperssonfab67072017-04-04 05:51:49 -07001665 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001666 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001667
asaperssonfab67072017-04-04 05:51:49 -07001668 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001669 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001670
asaperssonfab67072017-04-04 05:51:49 -07001671 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001672 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001673
asaperssonfab67072017-04-04 05:51:49 -07001674 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001675 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001676
kthelgason876222f2016-11-29 01:44:11 -08001677 // Expect a scale down.
1678 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001679 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001680
asapersson02465b82017-04-10 01:12:52 -07001681 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001682 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001683 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001684 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001685
asaperssonfab67072017-04-04 05:51:49 -07001686 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001687 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001688 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001689 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001690
asaperssonfab67072017-04-04 05:51:49 -07001691 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001692 EXPECT_EQ(std::numeric_limits<int>::max(),
1693 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001694
asaperssonfab67072017-04-04 05:51:49 -07001695 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001696 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001697 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001698 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001699
asapersson02465b82017-04-10 01:12:52 -07001700 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001701 EXPECT_EQ(std::numeric_limits<int>::max(),
1702 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001703
mflodmancc3d4422017-08-03 08:27:51 -07001704 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001705}
1706
mflodmancc3d4422017-08-03 08:27:51 -07001707TEST_F(VideoStreamEncoderTest,
1708 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001709 const int kWidth = 1280;
1710 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02001711 video_stream_encoder_->OnBitrateUpdated(
1712 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001713
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001714 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001715 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001716 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001717 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001718
1719 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001720 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001721 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001722 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1723 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1724
1725 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001726 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001727 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001728 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1729 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1730 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1731
1732 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001733 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001734 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1735 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1736 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1737
mflodmancc3d4422017-08-03 08:27:51 -07001738 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001739}
1740
mflodmancc3d4422017-08-03 08:27:51 -07001741TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001742 const int kWidth = 1280;
1743 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02001744 video_stream_encoder_->OnBitrateUpdated(
1745 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001746
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001747 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001748 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001749 video_stream_encoder_->SetSource(&source,
1750 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001751 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1752 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001753 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001754
1755 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001756 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001757 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1758 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1759 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1760 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1761
1762 // Trigger adapt down for same input resolution, expect no change.
1763 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1764 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001765 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001766 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1767 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1768 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1769
1770 // Trigger adapt down for larger input resolution, expect no change.
1771 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1772 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001773 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001774 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1775 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1776 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1777
mflodmancc3d4422017-08-03 08:27:51 -07001778 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001779}
1780
mflodmancc3d4422017-08-03 08:27:51 -07001781TEST_F(VideoStreamEncoderTest,
1782 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001783 const int kWidth = 1280;
1784 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02001785 video_stream_encoder_->OnBitrateUpdated(
1786 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001787
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001788 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001789 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001790 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001791 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001792
1793 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001794 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001795 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001796 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1797 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1798
1799 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001800 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001801 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001802 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1803 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1804
mflodmancc3d4422017-08-03 08:27:51 -07001805 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001806}
1807
mflodmancc3d4422017-08-03 08:27:51 -07001808TEST_F(VideoStreamEncoderTest,
1809 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001810 const int kWidth = 1280;
1811 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02001812 video_stream_encoder_->OnBitrateUpdated(
1813 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001814
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001815 // Enable MAINTAIN_RESOLUTION preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001816 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001817 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001818 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
asapersson02465b82017-04-10 01:12:52 -07001819
1820 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001821 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001822 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001823 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001824 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1825
1826 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001827 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001828 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001829 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001830 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1831
mflodmancc3d4422017-08-03 08:27:51 -07001832 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001833}
1834
mflodmancc3d4422017-08-03 08:27:51 -07001835TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001836 const int kWidth = 1280;
1837 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02001838 video_stream_encoder_->OnBitrateUpdated(
1839 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001840
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001841 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001842 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001843 video_stream_encoder_->SetSource(&source,
1844 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001845
1846 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1847 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001848 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001849 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1850 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1851 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1852
1853 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001854 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001855 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001856 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1857 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1858 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1859
mflodmancc3d4422017-08-03 08:27:51 -07001860 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001861}
1862
mflodmancc3d4422017-08-03 08:27:51 -07001863TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001864 const int kWidth = 1280;
1865 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02001866 video_stream_encoder_->OnBitrateUpdated(
1867 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001868
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001869 // Enable DISABLED preference, no initial limitation.
asapersson09f05612017-05-15 23:40:18 -07001870 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001871 video_stream_encoder_->SetSource(&source,
1872 webrtc::DegradationPreference::DISABLED);
asapersson09f05612017-05-15 23:40:18 -07001873
1874 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1875 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001876 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001877 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1878 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1879 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1880
1881 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001882 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001883 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001884 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1885 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1886 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1887
mflodmancc3d4422017-08-03 08:27:51 -07001888 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001889}
1890
mflodmancc3d4422017-08-03 08:27:51 -07001891TEST_F(VideoStreamEncoderTest,
1892 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001893 const int kWidth = 1280;
1894 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02001895 video_stream_encoder_->OnBitrateUpdated(
1896 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001897
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001898 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001899 AdaptingFrameForwarder source;
1900 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001901 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001902 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001903
1904 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001905 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001906 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001907 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1908 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1909
1910 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001911 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001912 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001913 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001914 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001915 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1916 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1917
1918 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001919 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001920 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001921 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1922 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1923 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1924
mflodmancc3d4422017-08-03 08:27:51 -07001925 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001926}
1927
mflodmancc3d4422017-08-03 08:27:51 -07001928TEST_F(VideoStreamEncoderTest,
1929 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001930 const int kWidth = 1280;
1931 const int kHeight = 720;
1932 const int kInputFps = 30;
Erik Språng4c6ca302019-04-08 15:14:01 +02001933 video_stream_encoder_->OnBitrateUpdated(
1934 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001935
1936 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1937 stats.input_frame_rate = kInputFps;
1938 stats_proxy_->SetMockStats(stats);
1939
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001940 // Expect no scaling to begin with (preference: MAINTAIN_FRAMERATE).
asapersson09f05612017-05-15 23:40:18 -07001941 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1942 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001943 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001944
1945 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001946 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001947 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1948 sink_.WaitForEncodedFrame(2);
1949 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1950
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001951 // Enable MAINTAIN_RESOLUTION preference.
asapersson09f05612017-05-15 23:40:18 -07001952 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001953 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001954 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001955 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001956
1957 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001958 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001959 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1960 sink_.WaitForEncodedFrame(3);
1961 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1962
1963 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001964 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001965 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001966
mflodmancc3d4422017-08-03 08:27:51 -07001967 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001968}
1969
mflodmancc3d4422017-08-03 08:27:51 -07001970TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001971 const int kWidth = 1280;
1972 const int kHeight = 720;
1973 const size_t kNumFrames = 10;
1974
Erik Språng4c6ca302019-04-08 15:14:01 +02001975 video_stream_encoder_->OnBitrateUpdated(
1976 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001977
asaperssond0de2952017-04-21 01:47:31 -07001978 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001979 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001980 video_source_.set_adaptation_enabled(true);
1981
1982 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1983 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1984
1985 int downscales = 0;
1986 for (size_t i = 1; i <= kNumFrames; i++) {
Åsa Persson8c1bf952018-09-13 10:42:19 +02001987 video_source_.IncomingCapturedFrame(
1988 CreateFrame(i * kFrameIntervalMs, kWidth, kHeight));
1989 WaitForEncodedFrame(i * kFrameIntervalMs);
asaperssond0de2952017-04-21 01:47:31 -07001990
asaperssonfab67072017-04-04 05:51:49 -07001991 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001992 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001993 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001994 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001995
1996 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1997 ++downscales;
1998
1999 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2000 EXPECT_EQ(downscales,
2001 stats_proxy_->GetStats().number_of_quality_adapt_changes);
2002 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08002003 }
mflodmancc3d4422017-08-03 08:27:51 -07002004 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002005}
2006
mflodmancc3d4422017-08-03 08:27:51 -07002007TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002008 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
2009 const int kWidth = 1280;
2010 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02002011 video_stream_encoder_->OnBitrateUpdated(
2012 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002013
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002014 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002015 AdaptingFrameForwarder source;
2016 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002017 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002018 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002019
Åsa Persson8c1bf952018-09-13 10:42:19 +02002020 int64_t timestamp_ms = kFrameIntervalMs;
2021 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002022 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002023 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002024 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2025 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2026
2027 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002028 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002029 timestamp_ms += kFrameIntervalMs;
2030 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2031 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002032 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002033 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2034 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2035
2036 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002037 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002038 timestamp_ms += kFrameIntervalMs;
2039 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002040 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002041 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002042 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2043 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2044
2045 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002046 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002047 timestamp_ms += kFrameIntervalMs;
2048 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2049 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002050 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002051 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2052 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2053
2054 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002055 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002056 timestamp_ms += kFrameIntervalMs;
2057 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asapersson09f05612017-05-15 23:40:18 -07002058 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002059 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002060 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2061 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2062
mflodmancc3d4422017-08-03 08:27:51 -07002063 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002064}
2065
mflodmancc3d4422017-08-03 08:27:51 -07002066TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07002067 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
2068 const int kWidth = 1280;
2069 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02002070 video_stream_encoder_->OnBitrateUpdated(
2071 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002072
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002073 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002074 AdaptingFrameForwarder source;
2075 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002076 video_stream_encoder_->SetSource(&source,
2077 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002078
Åsa Persson8c1bf952018-09-13 10:42:19 +02002079 int64_t timestamp_ms = kFrameIntervalMs;
2080 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07002081 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002082 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002083 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2084 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2085
2086 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002087 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002088 timestamp_ms += kFrameIntervalMs;
2089 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2090 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002091 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2092 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2093 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2094
2095 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002096 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002097 timestamp_ms += kFrameIntervalMs;
2098 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07002099 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002100 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002101 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2102 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2103
2104 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002105 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002106 timestamp_ms += kFrameIntervalMs;
2107 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2108 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002109 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2110 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2111 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2112
2113 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002114 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002115 timestamp_ms += kFrameIntervalMs;
2116 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07002117 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002118 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002119 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2120 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2121
mflodmancc3d4422017-08-03 08:27:51 -07002122 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002123}
2124
mflodmancc3d4422017-08-03 08:27:51 -07002125TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002126 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
2127 const int kWidth = 1280;
2128 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02002129 video_stream_encoder_->OnBitrateUpdated(
2130 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002131
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002132 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002133 AdaptingFrameForwarder source;
2134 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002135 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002136 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002137
Åsa Persson8c1bf952018-09-13 10:42:19 +02002138 int64_t timestamp_ms = kFrameIntervalMs;
2139 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002140 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002141 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002142 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2143 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2144 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2145 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2146
2147 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002148 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002149 timestamp_ms += kFrameIntervalMs;
2150 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2151 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002152 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002153 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2154 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2155 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2156 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2157
2158 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07002159 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002160 timestamp_ms += kFrameIntervalMs;
2161 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2162 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002163 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002164 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2165 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2166 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2167 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2168
Jonathan Yubc771b72017-12-08 17:04:29 -08002169 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002170 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002171 timestamp_ms += kFrameIntervalMs;
2172 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2173 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002174 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002175 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2176 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002177 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002178 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2179
Jonathan Yubc771b72017-12-08 17:04:29 -08002180 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07002181 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002182 timestamp_ms += kFrameIntervalMs;
2183 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2184 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002185 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002186 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07002187 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2188 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2189 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2190 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2191
Jonathan Yubc771b72017-12-08 17:04:29 -08002192 // Trigger quality adapt down, expect no change (min resolution reached).
2193 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002194 timestamp_ms += kFrameIntervalMs;
2195 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2196 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002197 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
2198 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2199 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2200 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2201 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2202
2203 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002204 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002205 timestamp_ms += kFrameIntervalMs;
2206 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2207 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002208 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002209 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2210 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2211 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2212 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2213
2214 // Trigger cpu adapt up, expect upscaled resolution (640x360).
2215 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002216 timestamp_ms += kFrameIntervalMs;
2217 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2218 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002219 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2220 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2221 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2222 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2223 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2224
2225 // Trigger cpu adapt up, expect upscaled resolution (960x540).
2226 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002227 timestamp_ms += kFrameIntervalMs;
2228 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2229 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002230 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002231 last_wants = source.sink_wants();
2232 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2233 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002234 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002235 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2236
2237 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002238 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002239 timestamp_ms += kFrameIntervalMs;
2240 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2241 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002242 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002243 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2244 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002245 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002246 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2247
2248 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002249 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002250 timestamp_ms += kFrameIntervalMs;
2251 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002252 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002253 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002254 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002255 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2256 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002257 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002258 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002259
mflodmancc3d4422017-08-03 08:27:51 -07002260 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002261}
2262
mflodmancc3d4422017-08-03 08:27:51 -07002263TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002264 const int kWidth = 640;
2265 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002266
Erik Språng4c6ca302019-04-08 15:14:01 +02002267 video_stream_encoder_->OnBitrateUpdated(
2268 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002269
perkj803d97f2016-11-01 11:45:46 -07002270 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002271 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002272 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002273 }
2274
mflodmancc3d4422017-08-03 08:27:51 -07002275 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002276 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002277 video_source_.IncomingCapturedFrame(CreateFrame(
2278 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002279 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002280 }
2281
mflodmancc3d4422017-08-03 08:27:51 -07002282 video_stream_encoder_->Stop();
2283 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002284 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002285
perkj803d97f2016-11-01 11:45:46 -07002286 EXPECT_EQ(1,
2287 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2288 EXPECT_EQ(
2289 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2290}
2291
mflodmancc3d4422017-08-03 08:27:51 -07002292TEST_F(VideoStreamEncoderTest,
2293 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
Erik Språng4c6ca302019-04-08 15:14:01 +02002294 video_stream_encoder_->OnBitrateUpdated(
2295 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002296 const int kWidth = 640;
2297 const int kHeight = 360;
2298
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002299 video_stream_encoder_->SetSource(&video_source_,
2300 webrtc::DegradationPreference::DISABLED);
asaperssonf4e44af2017-04-19 02:01:06 -07002301
2302 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2303 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002304 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002305 }
2306
mflodmancc3d4422017-08-03 08:27:51 -07002307 video_stream_encoder_->Stop();
2308 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002309 stats_proxy_.reset();
2310
2311 EXPECT_EQ(0,
2312 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2313}
2314
mflodmancc3d4422017-08-03 08:27:51 -07002315TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002316 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02002317 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002318
2319 const int kDefaultFps = 30;
Erik Språng566124a2018-04-23 12:32:22 +02002320 const VideoBitrateAllocation expected_bitrate =
sprang57c2fff2017-01-16 06:24:02 -08002321 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002322 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002323
sprang57c2fff2017-01-16 06:24:02 -08002324 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
Niels Möller6bb5ab92019-01-11 11:11:10 +01002325 .Times(1);
Erik Språng610c7632019-03-06 15:37:33 +01002326 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kLowTargetBitrateBps),
Erik Språng4c6ca302019-04-08 15:14:01 +02002327 DataRate::bps(kLowTargetBitrateBps),
2328 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002329
sprang57c2fff2017-01-16 06:24:02 -08002330 video_source_.IncomingCapturedFrame(
Erik Språngd7329ca2019-02-21 21:19:53 +01002331 CreateFrame(rtc::TimeMillis(), codec_width_, codec_height_));
2332 WaitForEncodedFrame(rtc::TimeMillis());
2333 absl::optional<VideoBitrateAllocation> bitrate_allocation =
2334 fake_encoder_.GetAndResetLastBitrateAllocation();
2335 // Check that encoder has been updated too, not just allocation observer.
2336 EXPECT_EQ(bitrate_allocation->get_sum_bps(), kLowTargetBitrateBps);
Sebastian Jansson40889f32019-04-17 12:11:20 +02002337 // TODO(srte): The use of millisecs here looks like an error, but the tests
2338 // fails using seconds, this should be investigated.
2339 fake_clock_.AdvanceTime(TimeDelta::ms(1) / kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002340
2341 // Not called on second frame.
2342 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2343 .Times(0);
2344 video_source_.IncomingCapturedFrame(
Erik Språngd7329ca2019-02-21 21:19:53 +01002345 CreateFrame(rtc::TimeMillis(), codec_width_, codec_height_));
2346 WaitForEncodedFrame(rtc::TimeMillis());
Sebastian Jansson40889f32019-04-17 12:11:20 +02002347 fake_clock_.AdvanceTime(TimeDelta::ms(1) / kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002348
2349 // Called after a process interval.
2350 const int64_t kProcessIntervalMs =
2351 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang57c2fff2017-01-16 06:24:02 -08002352 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2353 .Times(1);
Erik Språngd7329ca2019-02-21 21:19:53 +01002354 const int64_t start_time_ms = rtc::TimeMillis();
2355 while (rtc::TimeMillis() - start_time_ms < kProcessIntervalMs) {
2356 video_source_.IncomingCapturedFrame(
2357 CreateFrame(rtc::TimeMillis(), codec_width_, codec_height_));
2358 WaitForEncodedFrame(rtc::TimeMillis());
Sebastian Jansson40889f32019-04-17 12:11:20 +02002359 fake_clock_.AdvanceTime(TimeDelta::ms(1) / kDefaultFps);
Erik Språngd7329ca2019-02-21 21:19:53 +01002360 }
2361
2362 // Since rates are unchanged, encoder should not be reconfigured.
2363 EXPECT_FALSE(fake_encoder_.GetAndResetLastBitrateAllocation().has_value());
sprang57c2fff2017-01-16 06:24:02 -08002364
mflodmancc3d4422017-08-03 08:27:51 -07002365 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002366}
2367
Åsa Perssonc29cb2c2019-03-25 12:06:59 +01002368TEST_F(VideoStreamEncoderTest, TemporalLayersNotDisabledIfSupported) {
2369 // 2 TLs configured, temporal layers supported by encoder.
2370 const int kNumTemporalLayers = 2;
2371 ResetEncoder("VP8", 1, kNumTemporalLayers, 1, /*screenshare*/ false);
2372 fake_encoder_.SetTemporalLayersSupported(0, true);
2373
2374 // Bitrate allocated across temporal layers.
2375 const int kTl0Bps = kTargetBitrateBps *
2376 webrtc::SimulcastRateAllocator::GetTemporalRateAllocation(
2377 kNumTemporalLayers, /*temporal_id*/ 0);
2378 const int kTl1Bps = kTargetBitrateBps *
2379 webrtc::SimulcastRateAllocator::GetTemporalRateAllocation(
2380 kNumTemporalLayers, /*temporal_id*/ 1);
2381 VideoBitrateAllocation expected_bitrate;
2382 expected_bitrate.SetBitrate(/*si*/ 0, /*ti*/ 0, kTl0Bps);
2383 expected_bitrate.SetBitrate(/*si*/ 0, /*ti*/ 1, kTl1Bps - kTl0Bps);
2384
2385 VerifyAllocatedBitrate(expected_bitrate);
2386 video_stream_encoder_->Stop();
2387}
2388
2389TEST_F(VideoStreamEncoderTest, TemporalLayersDisabledIfNotSupported) {
2390 // 2 TLs configured, temporal layers not supported by encoder.
2391 ResetEncoder("VP8", 1, /*num_temporal_layers*/ 2, 1, /*screenshare*/ false);
2392 fake_encoder_.SetTemporalLayersSupported(0, false);
2393
2394 // Temporal layers not supported by the encoder.
2395 // Total bitrate should be at ti:0.
2396 VideoBitrateAllocation expected_bitrate;
2397 expected_bitrate.SetBitrate(/*si*/ 0, /*ti*/ 0, kTargetBitrateBps);
2398
2399 VerifyAllocatedBitrate(expected_bitrate);
2400 video_stream_encoder_->Stop();
2401}
2402
2403TEST_F(VideoStreamEncoderTest, VerifyBitrateAllocationForTwoStreams) {
2404 // 2 TLs configured, temporal layers only supported for first stream.
2405 ResetEncoder("VP8", 2, /*num_temporal_layers*/ 2, 1, /*screenshare*/ false);
2406 fake_encoder_.SetTemporalLayersSupported(0, true);
2407 fake_encoder_.SetTemporalLayersSupported(1, false);
2408
2409 const int kS0Bps = 150000;
2410 const int kS0Tl0Bps =
2411 kS0Bps * webrtc::SimulcastRateAllocator::GetTemporalRateAllocation(
2412 /*num_layers*/ 2, /*temporal_id*/ 0);
2413 const int kS0Tl1Bps =
2414 kS0Bps * webrtc::SimulcastRateAllocator::GetTemporalRateAllocation(
2415 /*num_layers*/ 2, /*temporal_id*/ 1);
2416 const int kS1Bps = kTargetBitrateBps - kS0Tl1Bps;
2417 // Temporal layers not supported by si:1.
2418 VideoBitrateAllocation expected_bitrate;
2419 expected_bitrate.SetBitrate(/*si*/ 0, /*ti*/ 0, kS0Tl0Bps);
2420 expected_bitrate.SetBitrate(/*si*/ 0, /*ti*/ 1, kS0Tl1Bps - kS0Tl0Bps);
2421 expected_bitrate.SetBitrate(/*si*/ 1, /*ti*/ 0, kS1Bps);
2422
2423 VerifyAllocatedBitrate(expected_bitrate);
2424 video_stream_encoder_->Stop();
2425}
2426
Niels Möller7dc26b72017-12-06 10:27:48 +01002427TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2428 const int kFrameWidth = 1280;
2429 const int kFrameHeight = 720;
2430 const int kFramerate = 24;
2431
Erik Språng4c6ca302019-04-08 15:14:01 +02002432 video_stream_encoder_->OnBitrateUpdated(
2433 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möller7dc26b72017-12-06 10:27:48 +01002434 test::FrameForwarder source;
2435 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002436 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002437
2438 // Insert a single frame, triggering initial configuration.
2439 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2440 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2441
2442 EXPECT_EQ(
2443 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2444 kDefaultFramerate);
2445
2446 // Trigger reconfigure encoder (without resetting the entire instance).
2447 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002448 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002449 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2450 video_encoder_config.number_of_streams = 1;
2451 video_encoder_config.video_stream_factory =
2452 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2453 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002454 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002455 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2456
2457 // Detector should be updated with fps limit from codec config.
2458 EXPECT_EQ(
2459 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2460 kFramerate);
2461
2462 // Trigger overuse, max framerate should be reduced.
2463 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2464 stats.input_frame_rate = kFramerate;
2465 stats_proxy_->SetMockStats(stats);
2466 video_stream_encoder_->TriggerCpuOveruse();
2467 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2468 int adapted_framerate =
2469 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2470 EXPECT_LT(adapted_framerate, kFramerate);
2471
2472 // Trigger underuse, max framerate should go back to codec configured fps.
2473 // Set extra low fps, to make sure it's actually reset, not just incremented.
2474 stats = stats_proxy_->GetStats();
2475 stats.input_frame_rate = adapted_framerate / 2;
2476 stats_proxy_->SetMockStats(stats);
2477 video_stream_encoder_->TriggerCpuNormalUsage();
2478 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2479 EXPECT_EQ(
2480 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2481 kFramerate);
2482
2483 video_stream_encoder_->Stop();
2484}
2485
2486TEST_F(VideoStreamEncoderTest,
2487 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2488 const int kFrameWidth = 1280;
2489 const int kFrameHeight = 720;
2490 const int kLowFramerate = 15;
2491 const int kHighFramerate = 25;
2492
Erik Språng4c6ca302019-04-08 15:14:01 +02002493 video_stream_encoder_->OnBitrateUpdated(
2494 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möller7dc26b72017-12-06 10:27:48 +01002495 test::FrameForwarder source;
2496 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002497 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002498
2499 // Trigger initial configuration.
2500 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002501 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002502 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2503 video_encoder_config.number_of_streams = 1;
2504 video_encoder_config.video_stream_factory =
2505 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2506 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2507 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002508 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002509 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2510
2511 EXPECT_EQ(
2512 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2513 kLowFramerate);
2514
2515 // Trigger overuse, max framerate should be reduced.
2516 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2517 stats.input_frame_rate = kLowFramerate;
2518 stats_proxy_->SetMockStats(stats);
2519 video_stream_encoder_->TriggerCpuOveruse();
2520 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2521 int adapted_framerate =
2522 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2523 EXPECT_LT(adapted_framerate, kLowFramerate);
2524
2525 // Reconfigure the encoder with a new (higher max framerate), max fps should
2526 // still respect the adaptation.
2527 video_encoder_config.video_stream_factory =
2528 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2529 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2530 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002531 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002532 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2533
2534 EXPECT_EQ(
2535 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2536 adapted_framerate);
2537
2538 // Trigger underuse, max framerate should go back to codec configured fps.
2539 stats = stats_proxy_->GetStats();
2540 stats.input_frame_rate = adapted_framerate;
2541 stats_proxy_->SetMockStats(stats);
2542 video_stream_encoder_->TriggerCpuNormalUsage();
2543 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2544 EXPECT_EQ(
2545 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2546 kHighFramerate);
2547
2548 video_stream_encoder_->Stop();
2549}
2550
mflodmancc3d4422017-08-03 08:27:51 -07002551TEST_F(VideoStreamEncoderTest,
2552 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002553 const int kFrameWidth = 1280;
2554 const int kFrameHeight = 720;
2555 const int kFramerate = 24;
2556
Erik Språng4c6ca302019-04-08 15:14:01 +02002557 video_stream_encoder_->OnBitrateUpdated(
2558 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002559 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002560 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002561 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangfda496a2017-06-15 04:21:07 -07002562
2563 // Trigger initial configuration.
2564 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002565 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002566 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2567 video_encoder_config.number_of_streams = 1;
2568 video_encoder_config.video_stream_factory =
2569 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2570 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002571 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002572 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002573 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002574
Niels Möller7dc26b72017-12-06 10:27:48 +01002575 EXPECT_EQ(
2576 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2577 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002578
2579 // Trigger overuse, max framerate should be reduced.
2580 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2581 stats.input_frame_rate = kFramerate;
2582 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002583 video_stream_encoder_->TriggerCpuOveruse();
2584 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002585 int adapted_framerate =
2586 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002587 EXPECT_LT(adapted_framerate, kFramerate);
2588
2589 // Change degradation preference to not enable framerate scaling. Target
2590 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002591 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002592 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -07002593 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002594 EXPECT_EQ(
2595 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2596 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002597
mflodmancc3d4422017-08-03 08:27:51 -07002598 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002599}
2600
mflodmancc3d4422017-08-03 08:27:51 -07002601TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002602 const int kTooLowBitrateForFrameSizeBps = 10000;
Erik Språng610c7632019-03-06 15:37:33 +01002603 video_stream_encoder_->OnBitrateUpdated(
Erik Språng4c6ca302019-04-08 15:14:01 +02002604 DataRate::bps(kTooLowBitrateForFrameSizeBps),
2605 DataRate::bps(kTooLowBitrateForFrameSizeBps), 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002606 const int kWidth = 640;
2607 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002608
asaperssonfab67072017-04-04 05:51:49 -07002609 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002610
2611 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002612 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002613
2614 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002615 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002616
sprangc5d62e22017-04-02 23:53:04 -07002617 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002618
asaperssonfab67072017-04-04 05:51:49 -07002619 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002620 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002621 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002622
2623 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002624 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002625
sprangc5d62e22017-04-02 23:53:04 -07002626 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002627
mflodmancc3d4422017-08-03 08:27:51 -07002628 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002629}
2630
mflodmancc3d4422017-08-03 08:27:51 -07002631TEST_F(VideoStreamEncoderTest,
2632 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002633 const int kTooLowBitrateForFrameSizeBps = 10000;
Erik Språng610c7632019-03-06 15:37:33 +01002634 video_stream_encoder_->OnBitrateUpdated(
Erik Språng4c6ca302019-04-08 15:14:01 +02002635 DataRate::bps(kTooLowBitrateForFrameSizeBps),
2636 DataRate::bps(kTooLowBitrateForFrameSizeBps), 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002637 const int kWidth = 640;
2638 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002639
2640 // We expect the n initial frames to get dropped.
2641 int i;
2642 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002643 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002644 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002645 }
2646 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002647 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002648 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002649
2650 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002651 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002652
mflodmancc3d4422017-08-03 08:27:51 -07002653 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002654}
2655
mflodmancc3d4422017-08-03 08:27:51 -07002656TEST_F(VideoStreamEncoderTest,
2657 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002658 const int kWidth = 640;
2659 const int kHeight = 360;
Erik Språng610c7632019-03-06 15:37:33 +01002660 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kLowTargetBitrateBps),
Erik Språng4c6ca302019-04-08 15:14:01 +02002661 DataRate::bps(kLowTargetBitrateBps),
2662 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002663
2664 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002665 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002666 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason2bc68642017-02-07 07:02:22 -08002667
asaperssonfab67072017-04-04 05:51:49 -07002668 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002669 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002670 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002671
mflodmancc3d4422017-08-03 08:27:51 -07002672 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002673}
2674
mflodmancc3d4422017-08-03 08:27:51 -07002675TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002676 const int kWidth = 640;
2677 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002678 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02002679
2680 VideoEncoderConfig video_encoder_config;
2681 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
2682 // Make format different, to force recreation of encoder.
2683 video_encoder_config.video_format.parameters["foo"] = "foo";
2684 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002685 kMaxPayloadLength);
Erik Språng610c7632019-03-06 15:37:33 +01002686 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kLowTargetBitrateBps),
Erik Språng4c6ca302019-04-08 15:14:01 +02002687 DataRate::bps(kLowTargetBitrateBps),
2688 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002689
kthelgasonb83797b2017-02-14 11:57:25 -08002690 // Force quality scaler reconfiguration by resetting the source.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002691 video_stream_encoder_->SetSource(&video_source_,
2692 webrtc::DegradationPreference::BALANCED);
kthelgasonad9010c2017-02-14 00:46:51 -08002693
asaperssonfab67072017-04-04 05:51:49 -07002694 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002695 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002696 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002697
mflodmancc3d4422017-08-03 08:27:51 -07002698 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002699 fake_encoder_.SetQualityScaling(true);
2700}
2701
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002702TEST_F(VideoStreamEncoderTest, InitialFrameDropActivatesWhenBWEstimateReady) {
2703 webrtc::test::ScopedFieldTrials field_trials(
2704 "WebRTC-InitialFramedrop/Enabled/");
2705 // Reset encoder for field trials to take effect.
2706 ConfigureEncoder(video_encoder_config_.Copy());
2707 const int kTooLowBitrateForFrameSizeBps = 10000;
2708 const int kWidth = 640;
2709 const int kHeight = 360;
2710
Erik Språng4c6ca302019-04-08 15:14:01 +02002711 video_stream_encoder_->OnBitrateUpdated(
2712 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002713 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2714 // Frame should not be dropped.
2715 WaitForEncodedFrame(1);
2716
Erik Språng610c7632019-03-06 15:37:33 +01002717 video_stream_encoder_->OnBitrateUpdated(
Erik Språng4c6ca302019-04-08 15:14:01 +02002718 DataRate::bps(kTooLowBitrateForFrameSizeBps),
2719 DataRate::bps(kTooLowBitrateForFrameSizeBps), 0, 0);
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002720 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
2721 // Expect to drop this frame, the wait should time out.
2722 ExpectDroppedFrame();
2723
2724 // Expect the sink_wants to specify a scaled frame.
2725 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
2726 video_stream_encoder_->Stop();
2727}
2728
mflodmancc3d4422017-08-03 08:27:51 -07002729TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002730 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2731 const int kTooSmallWidth = 10;
2732 const int kTooSmallHeight = 10;
Erik Språng4c6ca302019-04-08 15:14:01 +02002733 video_stream_encoder_->OnBitrateUpdated(
2734 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002735
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002736 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002737 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002738 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002739 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002740 VerifyNoLimitation(source.sink_wants());
2741 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2742
2743 // Trigger adapt down, too small frame, expect no change.
2744 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002745 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002746 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002747 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002748 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2749 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2750
mflodmancc3d4422017-08-03 08:27:51 -07002751 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002752}
2753
mflodmancc3d4422017-08-03 08:27:51 -07002754TEST_F(VideoStreamEncoderTest,
2755 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002756 const int kTooSmallWidth = 10;
2757 const int kTooSmallHeight = 10;
2758 const int kFpsLimit = 7;
Erik Språng4c6ca302019-04-08 15:14:01 +02002759 video_stream_encoder_->OnBitrateUpdated(
2760 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002761
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002762 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002763 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002764 video_stream_encoder_->SetSource(&source,
2765 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002766 VerifyNoLimitation(source.sink_wants());
2767 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2768 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2769
2770 // Trigger adapt down, expect limited framerate.
2771 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002772 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002773 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002774 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2775 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2776 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2777 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2778
2779 // Trigger adapt down, too small frame, expect no change.
2780 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002781 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002782 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002783 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2784 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2785 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2786 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2787
mflodmancc3d4422017-08-03 08:27:51 -07002788 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002789}
2790
mflodmancc3d4422017-08-03 08:27:51 -07002791TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002792 fake_encoder_.ForceInitEncodeFailure(true);
Erik Språng4c6ca302019-04-08 15:14:01 +02002793 video_stream_encoder_->OnBitrateUpdated(
2794 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möllerf1338562018-04-26 09:51:47 +02002795 ResetEncoder("VP8", 2, 1, 1, false);
asapersson02465b82017-04-10 01:12:52 -07002796 const int kFrameWidth = 1280;
2797 const int kFrameHeight = 720;
2798 video_source_.IncomingCapturedFrame(
2799 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002800 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002801 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002802}
2803
sprangb1ca0732017-02-01 08:38:12 -08002804// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002805TEST_F(VideoStreamEncoderTest,
2806 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
Erik Språng4c6ca302019-04-08 15:14:01 +02002807 video_stream_encoder_->OnBitrateUpdated(
2808 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002809
2810 const int kFrameWidth = 1280;
2811 const int kFrameHeight = 720;
2812 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002813 // requested by
2814 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002815 video_source_.set_adaptation_enabled(true);
2816
2817 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002818 CreateFrame(1 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002819 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002820
2821 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002822 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002823 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002824 CreateFrame(2 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002825 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002826
asaperssonfab67072017-04-04 05:51:49 -07002827 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002828 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002829 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002830 CreateFrame(3 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002831 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002832
mflodmancc3d4422017-08-03 08:27:51 -07002833 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002834}
sprangfe627f32017-03-29 08:24:59 -07002835
mflodmancc3d4422017-08-03 08:27:51 -07002836TEST_F(VideoStreamEncoderTest,
2837 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002838 const int kFrameWidth = 1280;
2839 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07002840
Erik Språng4c6ca302019-04-08 15:14:01 +02002841 video_stream_encoder_->OnBitrateUpdated(
2842 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -07002843 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002844 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002845 video_source_.set_adaptation_enabled(true);
2846
sprang4847ae62017-06-27 07:06:52 -07002847 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002848
2849 video_source_.IncomingCapturedFrame(
2850 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002851 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002852
2853 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002854 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002855
2856 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002857 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002858 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002859 video_source_.IncomingCapturedFrame(
2860 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002861 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002862 }
2863
2864 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002865 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002866 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002867 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002868 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002869 video_source_.IncomingCapturedFrame(
2870 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002871 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002872 ++num_frames_dropped;
2873 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002874 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002875 }
2876 }
2877
sprang4847ae62017-06-27 07:06:52 -07002878 // Add some slack to account for frames dropped by the frame dropper.
2879 const int kErrorMargin = 1;
2880 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002881 kErrorMargin);
2882
2883 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002884 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002885 num_frames_dropped = 0;
Åsa Persson8c1bf952018-09-13 10:42:19 +02002886 for (int i = 0; i <= max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002887 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002888 video_source_.IncomingCapturedFrame(
2889 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002890 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002891 ++num_frames_dropped;
2892 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002893 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002894 }
2895 }
sprang4847ae62017-06-27 07:06:52 -07002896 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002897 kErrorMargin);
2898
2899 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002900 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002901 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002902 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002903 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002904 video_source_.IncomingCapturedFrame(
2905 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002906 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002907 ++num_frames_dropped;
2908 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002909 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002910 }
2911 }
sprang4847ae62017-06-27 07:06:52 -07002912 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002913 kErrorMargin);
2914
2915 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002916 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002917 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002918 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002919 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002920 video_source_.IncomingCapturedFrame(
2921 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002922 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002923 ++num_frames_dropped;
2924 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002925 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002926 }
2927 }
2928 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2929
mflodmancc3d4422017-08-03 08:27:51 -07002930 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002931}
2932
mflodmancc3d4422017-08-03 08:27:51 -07002933TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002934 const int kFramerateFps = 5;
2935 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002936 const int kFrameWidth = 1280;
2937 const int kFrameHeight = 720;
2938
sprang4847ae62017-06-27 07:06:52 -07002939 // Reconfigure encoder with two temporal layers and screensharing, which will
2940 // disable frame dropping and make testing easier.
Niels Möllerf1338562018-04-26 09:51:47 +02002941 ResetEncoder("VP8", 1, 2, 1, true);
sprang4847ae62017-06-27 07:06:52 -07002942
Erik Språng4c6ca302019-04-08 15:14:01 +02002943 video_stream_encoder_->OnBitrateUpdated(
2944 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -07002945 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002946 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002947 video_source_.set_adaptation_enabled(true);
2948
sprang4847ae62017-06-27 07:06:52 -07002949 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002950
2951 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08002952 rtc::VideoSinkWants last_wants;
2953 do {
2954 last_wants = video_source_.sink_wants();
2955
sprangc5d62e22017-04-02 23:53:04 -07002956 // Insert frames to get a new fps estimate...
2957 for (int j = 0; j < kFramerateFps; ++j) {
2958 video_source_.IncomingCapturedFrame(
2959 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08002960 if (video_source_.last_sent_width()) {
2961 sink_.WaitForEncodedFrame(timestamp_ms);
2962 }
sprangc5d62e22017-04-02 23:53:04 -07002963 timestamp_ms += kFrameIntervalMs;
Sebastian Jansson40889f32019-04-17 12:11:20 +02002964 fake_clock_.AdvanceTime(TimeDelta::ms(kFrameIntervalMs));
sprangc5d62e22017-04-02 23:53:04 -07002965 }
2966 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002967 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08002968 } while (video_source_.sink_wants().max_framerate_fps <
2969 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07002970
Jonathan Yubc771b72017-12-08 17:04:29 -08002971 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07002972
mflodmancc3d4422017-08-03 08:27:51 -07002973 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002974}
asaperssonf7e294d2017-06-13 23:25:22 -07002975
mflodmancc3d4422017-08-03 08:27:51 -07002976TEST_F(VideoStreamEncoderTest,
2977 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002978 const int kWidth = 1280;
2979 const int kHeight = 720;
2980 const int64_t kFrameIntervalMs = 150;
2981 int64_t timestamp_ms = kFrameIntervalMs;
Erik Språng4c6ca302019-04-08 15:14:01 +02002982 video_stream_encoder_->OnBitrateUpdated(
2983 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002984
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002985 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002986 AdaptingFrameForwarder source;
2987 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002988 video_stream_encoder_->SetSource(&source,
2989 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002990 timestamp_ms += kFrameIntervalMs;
2991 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002992 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002993 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002994 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2995 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2996 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2997
2998 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002999 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003000 timestamp_ms += kFrameIntervalMs;
3001 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003002 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003003 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
3004 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3005 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3006 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3007
3008 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003009 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003010 timestamp_ms += kFrameIntervalMs;
3011 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003012 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003013 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
3014 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3015 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3016 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3017
3018 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003019 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003020 timestamp_ms += kFrameIntervalMs;
3021 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003022 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003023 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
3024 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3025 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3026 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3027
3028 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003029 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003030 timestamp_ms += kFrameIntervalMs;
3031 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003032 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003033 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
3034 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3035 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3036 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3037
3038 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07003039 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003040 timestamp_ms += kFrameIntervalMs;
3041 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003042 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003043 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
3044 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3045 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3046 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3047
3048 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07003049 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003050 timestamp_ms += kFrameIntervalMs;
3051 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003052 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003053 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
3054 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3055 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3056 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3057
3058 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07003059 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003060 timestamp_ms += kFrameIntervalMs;
3061 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003062 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003063 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
3064 rtc::VideoSinkWants last_wants = source.sink_wants();
3065 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3066 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3067 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3068
3069 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003070 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003071 timestamp_ms += kFrameIntervalMs;
3072 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003073 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003074 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
3075 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3076 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3077 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3078
3079 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07003080 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003081 timestamp_ms += kFrameIntervalMs;
3082 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003083 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003084 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
3085 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3086 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3087 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3088
3089 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07003090 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003091 timestamp_ms += kFrameIntervalMs;
3092 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003093 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003094 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3095 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3096 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3097 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3098
3099 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003100 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003101 timestamp_ms += kFrameIntervalMs;
3102 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003103 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003104 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
3105 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3106 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3107 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3108
3109 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003110 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003111 timestamp_ms += kFrameIntervalMs;
3112 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003113 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003114 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3115 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3116 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3117 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3118
3119 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003120 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003121 timestamp_ms += kFrameIntervalMs;
3122 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003123 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003124 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
3125 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3126 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3127 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3128
3129 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003130 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003131 timestamp_ms += kFrameIntervalMs;
3132 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003133 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003134 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3135 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3136 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3137 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3138
3139 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003140 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003141 timestamp_ms += kFrameIntervalMs;
3142 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003143 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003144 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02003145 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003146 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3147 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3148 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3149
3150 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003151 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003152 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003153 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3154
mflodmancc3d4422017-08-03 08:27:51 -07003155 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003156}
3157
mflodmancc3d4422017-08-03 08:27:51 -07003158TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07003159 const int kWidth = 1280;
3160 const int kHeight = 720;
3161 const int64_t kFrameIntervalMs = 150;
3162 int64_t timestamp_ms = kFrameIntervalMs;
Erik Språng4c6ca302019-04-08 15:14:01 +02003163 video_stream_encoder_->OnBitrateUpdated(
3164 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07003165
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003166 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07003167 AdaptingFrameForwarder source;
3168 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003169 video_stream_encoder_->SetSource(&source,
3170 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07003171 timestamp_ms += kFrameIntervalMs;
3172 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003173 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003174 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003175 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3176 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3177 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3178 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3179 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3180 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3181
3182 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003183 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003184 timestamp_ms += kFrameIntervalMs;
3185 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003186 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003187 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
3188 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3189 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3190 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3191 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3192 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3193 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3194
3195 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003196 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003197 timestamp_ms += kFrameIntervalMs;
3198 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003199 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003200 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
3201 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3202 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3203 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3204 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3205 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3206 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3207
3208 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003209 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003210 timestamp_ms += kFrameIntervalMs;
3211 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003212 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003213 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
3214 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3215 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3216 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3217 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3218 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3219 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3220
3221 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003222 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003223 timestamp_ms += kFrameIntervalMs;
3224 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003225 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003226 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
3227 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3228 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3229 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3230 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3231 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3232 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3233
3234 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003235 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003236 timestamp_ms += kFrameIntervalMs;
3237 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003238 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003239 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3240 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3241 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3242 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3243 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3244 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3245 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3246
3247 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003248 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003249 timestamp_ms += kFrameIntervalMs;
3250 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003251 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003252 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02003253 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003254 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3255 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3256 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3257 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3258 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3259 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3260
3261 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003262 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003263 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003264 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3265 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3266
mflodmancc3d4422017-08-03 08:27:51 -07003267 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003268}
3269
mflodmancc3d4422017-08-03 08:27:51 -07003270TEST_F(VideoStreamEncoderTest,
3271 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07003272 const int kWidth = 640;
3273 const int kHeight = 360;
3274 const int kFpsLimit = 15;
3275 const int64_t kFrameIntervalMs = 150;
3276 int64_t timestamp_ms = kFrameIntervalMs;
Erik Språng4c6ca302019-04-08 15:14:01 +02003277 video_stream_encoder_->OnBitrateUpdated(
3278 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07003279
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003280 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07003281 AdaptingFrameForwarder source;
3282 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003283 video_stream_encoder_->SetSource(&source,
3284 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07003285 timestamp_ms += kFrameIntervalMs;
3286 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003287 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003288 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003289 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3290 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3291 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3292 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3293 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3294 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3295
3296 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003297 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003298 timestamp_ms += kFrameIntervalMs;
3299 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003300 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003301 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
3302 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3303 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3304 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3305 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3306 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3307 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3308
3309 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003310 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003311 timestamp_ms += kFrameIntervalMs;
3312 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003313 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003314 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
3315 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3316 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3317 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3318 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3319 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3320 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3321
3322 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003323 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003324 timestamp_ms += kFrameIntervalMs;
3325 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003326 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003327 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3328 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3329 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3330 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3331 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3332 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3333 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3334
3335 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003336 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003337 timestamp_ms += kFrameIntervalMs;
3338 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003339 WaitForEncodedFrame(timestamp_ms);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003340 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003341 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3342 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3343 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3344 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3345 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3346 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3347
3348 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003349 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003350 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003351 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3352 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3353
mflodmancc3d4422017-08-03 08:27:51 -07003354 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003355}
3356
mflodmancc3d4422017-08-03 08:27:51 -07003357TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003358 // Simulates simulcast behavior and makes highest stream resolutions divisible
3359 // by 4.
3360 class CroppingVideoStreamFactory
3361 : public VideoEncoderConfig::VideoStreamFactoryInterface {
3362 public:
3363 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
3364 int framerate)
3365 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
3366 EXPECT_GT(num_temporal_layers, 0u);
3367 EXPECT_GT(framerate, 0);
3368 }
3369
3370 private:
3371 std::vector<VideoStream> CreateEncoderStreams(
3372 int width,
3373 int height,
3374 const VideoEncoderConfig& encoder_config) override {
Yves Gerey665174f2018-06-19 15:03:05 +02003375 std::vector<VideoStream> streams = test::CreateVideoStreams(
3376 width - width % 4, height - height % 4, encoder_config);
ilnik6b826ef2017-06-16 06:53:48 -07003377 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +01003378 stream.num_temporal_layers = num_temporal_layers_;
ilnik6b826ef2017-06-16 06:53:48 -07003379 stream.max_framerate = framerate_;
3380 }
3381 return streams;
3382 }
3383
3384 const size_t num_temporal_layers_;
3385 const int framerate_;
3386 };
3387
3388 const int kFrameWidth = 1920;
3389 const int kFrameHeight = 1080;
3390 // 3/4 of 1920.
3391 const int kAdaptedFrameWidth = 1440;
3392 // 3/4 of 1080 rounded down to multiple of 4.
3393 const int kAdaptedFrameHeight = 808;
3394 const int kFramerate = 24;
3395
Erik Språng4c6ca302019-04-08 15:14:01 +02003396 video_stream_encoder_->OnBitrateUpdated(
3397 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003398 // Trigger reconfigure encoder (without resetting the entire instance).
3399 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02003400 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07003401 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3402 video_encoder_config.number_of_streams = 1;
3403 video_encoder_config.video_stream_factory =
3404 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003405 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02003406 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07003407 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003408
3409 video_source_.set_adaptation_enabled(true);
3410
3411 video_source_.IncomingCapturedFrame(
3412 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003413 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003414
3415 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003416 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003417 video_source_.IncomingCapturedFrame(
3418 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003419 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003420
mflodmancc3d4422017-08-03 08:27:51 -07003421 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003422}
3423
mflodmancc3d4422017-08-03 08:27:51 -07003424TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003425 const int kFrameWidth = 1280;
3426 const int kFrameHeight = 720;
3427 const int kLowFps = 2;
3428 const int kHighFps = 30;
3429
Erik Språng4c6ca302019-04-08 15:14:01 +02003430 video_stream_encoder_->OnBitrateUpdated(
3431 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003432
3433 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3434 max_framerate_ = kLowFps;
3435
3436 // Insert 2 seconds of 2fps video.
3437 for (int i = 0; i < kLowFps * 2; ++i) {
3438 video_source_.IncomingCapturedFrame(
3439 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3440 WaitForEncodedFrame(timestamp_ms);
3441 timestamp_ms += 1000 / kLowFps;
3442 }
3443
3444 // Make sure encoder is updated with new target.
Erik Språng4c6ca302019-04-08 15:14:01 +02003445 video_stream_encoder_->OnBitrateUpdated(
3446 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003447 video_source_.IncomingCapturedFrame(
3448 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3449 WaitForEncodedFrame(timestamp_ms);
3450 timestamp_ms += 1000 / kLowFps;
3451
3452 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3453
3454 // Insert 30fps frames for just a little more than the forced update period.
3455 const int kVcmTimerIntervalFrames =
3456 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3457 const int kFrameIntervalMs = 1000 / kHighFps;
3458 max_framerate_ = kHighFps;
3459 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3460 video_source_.IncomingCapturedFrame(
3461 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3462 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3463 // be dropped if the encoder hans't been updated with the new higher target
3464 // framerate yet, causing it to overshoot the target bitrate and then
3465 // suffering the wrath of the media optimizer.
3466 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3467 timestamp_ms += kFrameIntervalMs;
3468 }
3469
3470 // Don expect correct measurement just yet, but it should be higher than
3471 // before.
3472 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3473
mflodmancc3d4422017-08-03 08:27:51 -07003474 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003475}
3476
mflodmancc3d4422017-08-03 08:27:51 -07003477TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003478 const int kFrameWidth = 1280;
3479 const int kFrameHeight = 720;
3480 const int kTargetBitrateBps = 1000000;
3481
3482 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02003483 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
Erik Språng4c6ca302019-04-08 15:14:01 +02003484 video_stream_encoder_->OnBitrateUpdated(
3485 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -07003486 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003487
3488 // Insert a first video frame, causes another bitrate update.
3489 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3490 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3491 video_source_.IncomingCapturedFrame(
3492 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3493 WaitForEncodedFrame(timestamp_ms);
3494
3495 // Next, simulate video suspension due to pacer queue overrun.
Erik Språng4c6ca302019-04-08 15:14:01 +02003496 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(0), DataRate::bps(0), 0,
Erik Språng610c7632019-03-06 15:37:33 +01003497 1);
sprang4847ae62017-06-27 07:06:52 -07003498
3499 // Skip ahead until a new periodic parameter update should have occured.
3500 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
Sebastian Jansson40889f32019-04-17 12:11:20 +02003501 fake_clock_.AdvanceTime(
3502 TimeDelta::ms(vcm::VCMProcessTimer::kDefaultProcessIntervalMs));
sprang4847ae62017-06-27 07:06:52 -07003503
3504 // Bitrate observer should not be called.
3505 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3506 video_source_.IncomingCapturedFrame(
3507 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3508 ExpectDroppedFrame();
3509
mflodmancc3d4422017-08-03 08:27:51 -07003510 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003511}
ilnik6b826ef2017-06-16 06:53:48 -07003512
Niels Möller4db138e2018-04-19 09:04:13 +02003513TEST_F(VideoStreamEncoderTest,
3514 DefaultCpuAdaptationThresholdsForSoftwareEncoder) {
3515 const int kFrameWidth = 1280;
3516 const int kFrameHeight = 720;
3517 const CpuOveruseOptions default_options;
Erik Språng4c6ca302019-04-08 15:14:01 +02003518 video_stream_encoder_->OnBitrateUpdated(
3519 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möller4db138e2018-04-19 09:04:13 +02003520 video_source_.IncomingCapturedFrame(
3521 CreateFrame(1, kFrameWidth, kFrameHeight));
3522 WaitForEncodedFrame(1);
3523 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3524 .low_encode_usage_threshold_percent,
3525 default_options.low_encode_usage_threshold_percent);
3526 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3527 .high_encode_usage_threshold_percent,
3528 default_options.high_encode_usage_threshold_percent);
3529 video_stream_encoder_->Stop();
3530}
3531
3532TEST_F(VideoStreamEncoderTest,
3533 HigherCpuAdaptationThresholdsForHardwareEncoder) {
3534 const int kFrameWidth = 1280;
3535 const int kFrameHeight = 720;
3536 CpuOveruseOptions hardware_options;
3537 hardware_options.low_encode_usage_threshold_percent = 150;
3538 hardware_options.high_encode_usage_threshold_percent = 200;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +01003539 fake_encoder_.SetIsHardwareAccelerated(true);
Niels Möller4db138e2018-04-19 09:04:13 +02003540
Erik Språng4c6ca302019-04-08 15:14:01 +02003541 video_stream_encoder_->OnBitrateUpdated(
3542 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möller4db138e2018-04-19 09:04:13 +02003543 video_source_.IncomingCapturedFrame(
3544 CreateFrame(1, kFrameWidth, kFrameHeight));
3545 WaitForEncodedFrame(1);
3546 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3547 .low_encode_usage_threshold_percent,
3548 hardware_options.low_encode_usage_threshold_percent);
3549 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3550 .high_encode_usage_threshold_percent,
3551 hardware_options.high_encode_usage_threshold_percent);
3552 video_stream_encoder_->Stop();
3553}
3554
Niels Möller6bb5ab92019-01-11 11:11:10 +01003555TEST_F(VideoStreamEncoderTest, DropsFramesWhenEncoderOvershoots) {
3556 const int kFrameWidth = 320;
3557 const int kFrameHeight = 240;
3558 const int kFps = 30;
3559 const int kTargetBitrateBps = 120000;
3560 const int kNumFramesInRun = kFps * 5; // Runs of five seconds.
3561
Erik Språng4c6ca302019-04-08 15:14:01 +02003562 video_stream_encoder_->OnBitrateUpdated(
3563 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003564
3565 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3566 max_framerate_ = kFps;
3567
3568 // Insert 3 seconds of video, verify number of drops with normal bitrate.
3569 fake_encoder_.SimulateOvershoot(1.0);
3570 int num_dropped = 0;
3571 for (int i = 0; i < kNumFramesInRun; ++i) {
3572 video_source_.IncomingCapturedFrame(
3573 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3574 // Wait up to two frame durations for a frame to arrive.
3575 if (!TimedWaitForEncodedFrame(timestamp_ms, 2 * 1000 / kFps)) {
3576 ++num_dropped;
3577 }
3578 timestamp_ms += 1000 / kFps;
3579 }
3580
Erik Språnga8d48ab2019-02-08 14:17:40 +01003581 // Framerate should be measured to be near the expected target rate.
3582 EXPECT_NEAR(fake_encoder_.GetLastFramerate(), kFps, 1);
3583
3584 // Frame drops should be within 5% of expected 0%.
3585 EXPECT_NEAR(num_dropped, 0, 5 * kNumFramesInRun / 100);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003586
3587 // Make encoder produce frames at double the expected bitrate during 3 seconds
3588 // of video, verify number of drops. Rate needs to be slightly changed in
3589 // order to force the rate to be reconfigured.
Erik Språng7ca375c2019-02-06 16:20:17 +01003590 double overshoot_factor = 2.0;
3591 if (RateControlSettings::ParseFromFieldTrials().UseEncoderBitrateAdjuster()) {
3592 // With bitrate adjuster, when need to overshoot even more to trigger
3593 // frame dropping.
3594 overshoot_factor *= 2;
3595 }
3596 fake_encoder_.SimulateOvershoot(overshoot_factor);
Erik Språng610c7632019-03-06 15:37:33 +01003597 video_stream_encoder_->OnBitrateUpdated(
Erik Språng4c6ca302019-04-08 15:14:01 +02003598 DataRate::bps(kTargetBitrateBps + 1000),
3599 DataRate::bps(kTargetBitrateBps + 1000), 0, 0);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003600 num_dropped = 0;
3601 for (int i = 0; i < kNumFramesInRun; ++i) {
3602 video_source_.IncomingCapturedFrame(
3603 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3604 // Wait up to two frame durations for a frame to arrive.
3605 if (!TimedWaitForEncodedFrame(timestamp_ms, 2 * 1000 / kFps)) {
3606 ++num_dropped;
3607 }
3608 timestamp_ms += 1000 / kFps;
3609 }
3610
Erik Språng4c6ca302019-04-08 15:14:01 +02003611 video_stream_encoder_->OnBitrateUpdated(
3612 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Erik Språnga8d48ab2019-02-08 14:17:40 +01003613
3614 // Target framerate should be still be near the expected target, despite
3615 // the frame drops.
3616 EXPECT_NEAR(fake_encoder_.GetLastFramerate(), kFps, 1);
3617
3618 // Frame drops should be within 5% of expected 50%.
3619 EXPECT_NEAR(num_dropped, kNumFramesInRun / 2, 5 * kNumFramesInRun / 100);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003620
3621 video_stream_encoder_->Stop();
3622}
3623
3624TEST_F(VideoStreamEncoderTest, ConfiguresCorrectFrameRate) {
3625 const int kFrameWidth = 320;
3626 const int kFrameHeight = 240;
3627 const int kActualInputFps = 24;
3628 const int kTargetBitrateBps = 120000;
3629
3630 ASSERT_GT(max_framerate_, kActualInputFps);
3631
3632 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3633 max_framerate_ = kActualInputFps;
Erik Språng4c6ca302019-04-08 15:14:01 +02003634 video_stream_encoder_->OnBitrateUpdated(
3635 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003636
3637 // Insert 3 seconds of video, with an input fps lower than configured max.
3638 for (int i = 0; i < kActualInputFps * 3; ++i) {
3639 video_source_.IncomingCapturedFrame(
3640 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3641 // Wait up to two frame durations for a frame to arrive.
3642 WaitForEncodedFrame(timestamp_ms);
3643 timestamp_ms += 1000 / kActualInputFps;
3644 }
3645
3646 EXPECT_NEAR(kActualInputFps, fake_encoder_.GetLastFramerate(), 1);
3647
3648 video_stream_encoder_->Stop();
3649}
3650
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01003651TEST_F(VideoStreamEncoderTest, AccumulatesUpdateRectOnDroppedFrames) {
3652 VideoFrame::UpdateRect rect;
Erik Språng4c6ca302019-04-08 15:14:01 +02003653 video_stream_encoder_->OnBitrateUpdated(
3654 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01003655
3656 fake_encoder_.BlockNextEncode();
3657 video_source_.IncomingCapturedFrame(
3658 CreateFrameWithUpdatedPixel(1, nullptr, 0));
3659 WaitForEncodedFrame(1);
3660 // On the very first frame full update should be forced.
3661 rect = fake_encoder_.GetLastUpdateRect();
3662 EXPECT_EQ(rect.offset_x, 0);
3663 EXPECT_EQ(rect.offset_y, 0);
3664 EXPECT_EQ(rect.height, codec_height_);
3665 EXPECT_EQ(rect.width, codec_width_);
3666 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
3667 // call to ContinueEncode.
3668 video_source_.IncomingCapturedFrame(
3669 CreateFrameWithUpdatedPixel(2, nullptr, 1));
3670 ExpectDroppedFrame();
3671 video_source_.IncomingCapturedFrame(
3672 CreateFrameWithUpdatedPixel(3, nullptr, 10));
3673 ExpectDroppedFrame();
3674 fake_encoder_.ContinueEncode();
3675 WaitForEncodedFrame(3);
3676 // Updates to pixels 1 and 10 should be accumulated to one 10x1 rect.
3677 rect = fake_encoder_.GetLastUpdateRect();
3678 EXPECT_EQ(rect.offset_x, 1);
3679 EXPECT_EQ(rect.offset_y, 0);
3680 EXPECT_EQ(rect.width, 10);
3681 EXPECT_EQ(rect.height, 1);
3682
3683 video_source_.IncomingCapturedFrame(
3684 CreateFrameWithUpdatedPixel(4, nullptr, 0));
3685 WaitForEncodedFrame(4);
3686 // Previous frame was encoded, so no accumulation should happen.
3687 rect = fake_encoder_.GetLastUpdateRect();
3688 EXPECT_EQ(rect.offset_x, 0);
3689 EXPECT_EQ(rect.offset_y, 0);
3690 EXPECT_EQ(rect.width, 1);
3691 EXPECT_EQ(rect.height, 1);
3692
3693 video_stream_encoder_->Stop();
3694}
3695
Erik Språngd7329ca2019-02-21 21:19:53 +01003696TEST_F(VideoStreamEncoderTest, SetsFrameTypes) {
Erik Språng4c6ca302019-04-08 15:14:01 +02003697 video_stream_encoder_->OnBitrateUpdated(
3698 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Erik Språngd7329ca2019-02-21 21:19:53 +01003699
3700 // First frame is always keyframe.
3701 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
3702 WaitForEncodedFrame(1);
Niels Möller8f7ce222019-03-21 15:43:58 +01003703 EXPECT_THAT(
3704 fake_encoder_.LastFrameTypes(),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02003705 ::testing::ElementsAre(VideoFrameType{VideoFrameType::kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003706
3707 // Insert delta frame.
3708 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
3709 WaitForEncodedFrame(2);
Niels Möller8f7ce222019-03-21 15:43:58 +01003710 EXPECT_THAT(
3711 fake_encoder_.LastFrameTypes(),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02003712 ::testing::ElementsAre(VideoFrameType{VideoFrameType::kVideoFrameDelta}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003713
3714 // Request next frame be a key-frame.
3715 video_stream_encoder_->SendKeyFrame();
3716 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
3717 WaitForEncodedFrame(3);
Niels Möller8f7ce222019-03-21 15:43:58 +01003718 EXPECT_THAT(
3719 fake_encoder_.LastFrameTypes(),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02003720 ::testing::ElementsAre(VideoFrameType{VideoFrameType::kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003721
3722 video_stream_encoder_->Stop();
3723}
3724
3725TEST_F(VideoStreamEncoderTest, SetsFrameTypesSimulcast) {
3726 // Setup simulcast with three streams.
3727 ResetEncoder("VP8", 3, 1, 1, false);
Erik Språng610c7632019-03-06 15:37:33 +01003728 video_stream_encoder_->OnBitrateUpdated(
Erik Språng4c6ca302019-04-08 15:14:01 +02003729 DataRate::bps(kSimulcastTargetBitrateBps),
3730 DataRate::bps(kSimulcastTargetBitrateBps), 0, 0);
Erik Språngd7329ca2019-02-21 21:19:53 +01003731 // Wait for all three layers before triggering event.
3732 sink_.SetNumExpectedLayers(3);
3733
3734 // First frame is always keyframe.
3735 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
3736 WaitForEncodedFrame(1);
3737 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02003738 ::testing::ElementsAreArray({VideoFrameType::kVideoFrameKey,
3739 VideoFrameType::kVideoFrameKey,
3740 VideoFrameType::kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003741
3742 // Insert delta frame.
3743 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
3744 WaitForEncodedFrame(2);
3745 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02003746 ::testing::ElementsAreArray({VideoFrameType::kVideoFrameDelta,
3747 VideoFrameType::kVideoFrameDelta,
3748 VideoFrameType::kVideoFrameDelta}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003749
3750 // Request next frame be a key-frame.
3751 // Only first stream is configured to produce key-frame.
3752 video_stream_encoder_->SendKeyFrame();
3753 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
3754 WaitForEncodedFrame(3);
3755 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02003756 ::testing::ElementsAreArray({VideoFrameType::kVideoFrameKey,
3757 VideoFrameType::kVideoFrameDelta,
3758 VideoFrameType::kVideoFrameDelta}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003759
3760 video_stream_encoder_->Stop();
3761}
3762
3763TEST_F(VideoStreamEncoderTest, RequestKeyframeInternalSource) {
3764 // Configure internal source factory and setup test again.
3765 encoder_factory_.SetHasInternalSource(true);
3766 ResetEncoder("VP8", 1, 1, 1, false);
Erik Språng4c6ca302019-04-08 15:14:01 +02003767 video_stream_encoder_->OnBitrateUpdated(
3768 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Erik Språngd7329ca2019-02-21 21:19:53 +01003769
3770 // Call encoder directly, simulating internal source where encoded frame
3771 // callback in VideoStreamEncoder is called despite no OnFrame().
3772 fake_encoder_.InjectFrame(CreateFrame(1, nullptr), true);
3773 EXPECT_TRUE(WaitForFrame(kDefaultTimeoutMs));
Niels Möller8f7ce222019-03-21 15:43:58 +01003774 EXPECT_THAT(
3775 fake_encoder_.LastFrameTypes(),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02003776 ::testing::ElementsAre(VideoFrameType{VideoFrameType::kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003777
Niels Möller8f7ce222019-03-21 15:43:58 +01003778 const std::vector<VideoFrameType> kDeltaFrame = {
3779 VideoFrameType::kVideoFrameDelta};
Erik Språngd7329ca2019-02-21 21:19:53 +01003780 // Need to set timestamp manually since manually for injected frame.
3781 VideoFrame frame = CreateFrame(101, nullptr);
3782 frame.set_timestamp(101);
3783 fake_encoder_.InjectFrame(frame, false);
3784 EXPECT_TRUE(WaitForFrame(kDefaultTimeoutMs));
Niels Möller8f7ce222019-03-21 15:43:58 +01003785 EXPECT_THAT(
3786 fake_encoder_.LastFrameTypes(),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02003787 ::testing::ElementsAre(VideoFrameType{VideoFrameType::kVideoFrameDelta}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003788
3789 // Request key-frame. The forces a dummy frame down into the encoder.
3790 fake_encoder_.ExpectNullFrame();
3791 video_stream_encoder_->SendKeyFrame();
3792 EXPECT_TRUE(WaitForFrame(kDefaultTimeoutMs));
Niels Möller8f7ce222019-03-21 15:43:58 +01003793 EXPECT_THAT(
3794 fake_encoder_.LastFrameTypes(),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02003795 ::testing::ElementsAre(VideoFrameType{VideoFrameType::kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003796
3797 video_stream_encoder_->Stop();
3798}
Erik Språngb7cb7b52019-02-26 15:52:33 +01003799
3800TEST_F(VideoStreamEncoderTest, AdjustsTimestampInternalSource) {
3801 // Configure internal source factory and setup test again.
3802 encoder_factory_.SetHasInternalSource(true);
3803 ResetEncoder("VP8", 1, 1, 1, false);
Erik Språng4c6ca302019-04-08 15:14:01 +02003804 video_stream_encoder_->OnBitrateUpdated(
3805 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Erik Språngb7cb7b52019-02-26 15:52:33 +01003806
3807 int64_t timestamp = 1;
3808 EncodedImage image;
3809 image.Allocate(kTargetBitrateBps / kDefaultFramerate / 8);
3810 image.capture_time_ms_ = ++timestamp;
3811 image.SetTimestamp(static_cast<uint32_t>(timestamp * 90));
3812 const int64_t kEncodeFinishDelayMs = 10;
3813 image.timing_.encode_start_ms = timestamp;
3814 image.timing_.encode_finish_ms = timestamp + kEncodeFinishDelayMs;
3815 fake_encoder_.InjectEncodedImage(image);
3816 // Wait for frame without incrementing clock.
3817 EXPECT_TRUE(sink_.WaitForFrame(kDefaultTimeoutMs));
3818 // Frame is captured kEncodeFinishDelayMs before it's encoded, so restored
3819 // capture timestamp should be kEncodeFinishDelayMs in the past.
3820 EXPECT_EQ(sink_.GetLastCaptureTimeMs(),
3821 fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec -
3822 kEncodeFinishDelayMs);
3823
3824 video_stream_encoder_->Stop();
3825}
perkj26091b12016-09-01 01:17:40 -07003826} // namespace webrtc