blob: 9bf9cfd6977a38bdf4b01fe156fd52e23070819b [file] [log] [blame]
perkj26091b12016-09-01 01:17:40 -07001/*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Erik Språng4529fbc2018-10-12 10:30:31 +020011#include "video/video_stream_encoder.h"
12
sprangfe627f32017-03-29 08:24:59 -070013#include <algorithm>
perkj803d97f2016-11-01 11:45:46 -070014#include <limits>
Per512ecb32016-09-23 15:52:06 +020015#include <utility>
16
Jiawei Ouc2ebe212018-11-08 10:02:56 -080017#include "api/video/builtin_video_bitrate_allocator_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "api/video/i420_buffer.h"
Erik Språngf93eda12019-01-16 17:10:57 +010019#include "api/video/video_bitrate_allocation.h"
Erik Språng4529fbc2018-10-12 10:30:31 +020020#include "api/video_codecs/create_vp8_temporal_layers.h"
21#include "api/video_codecs/vp8_temporal_layers.h"
Steve Anton10542f22019-01-11 09:11:00 -080022#include "media/base/video_adapter.h"
Sergey Silkin86684962018-03-28 19:32:37 +020023#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
Steve Anton10542f22019-01-11 09:11:00 -080025#include "rtc_base/fake_clock.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020026#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080027#include "rtc_base/ref_counted_object.h"
Erik Språng7ca375c2019-02-06 16:20:17 +010028#include "system_wrappers/include/field_trial.h"
Mirko Bonadei17f48782018-09-28 08:51:10 +020029#include "system_wrappers/include/metrics.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020030#include "system_wrappers/include/sleep.h"
31#include "test/encoder_settings.h"
32#include "test/fake_encoder.h"
Kári Tristan Helgason639602a2018-08-02 10:51:40 +020033#include "test/field_trial.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020034#include "test/frame_generator.h"
35#include "test/gmock.h"
36#include "test/gtest.h"
Niels Möllercbcbc222018-09-28 09:07:24 +020037#include "test/video_encoder_proxy_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020038#include "video/send_statistics_proxy.h"
perkj26091b12016-09-01 01:17:40 -070039
40namespace webrtc {
41
sprangb1ca0732017-02-01 08:38:12 -080042using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080043using ::testing::_;
44using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080045
perkj803d97f2016-11-01 11:45:46 -070046namespace {
Åsa Persson8c1bf952018-09-13 10:42:19 +020047const int kMinPixelsPerFrame = 320 * 180;
48const int kMinFramerateFps = 2;
49const int kMinBalancedFramerateFps = 7;
50const int64_t kFrameTimeoutMs = 100;
asapersson5f7226f2016-11-25 04:37:00 -080051const size_t kMaxPayloadLength = 1440;
Erik Språngd7329ca2019-02-21 21:19:53 +010052const uint32_t kTargetBitrateBps = 1000000;
53const uint32_t kSimulcastTargetBitrateBps = 3150000;
54const uint32_t kLowTargetBitrateBps = kTargetBitrateBps / 10;
kthelgason2bc68642017-02-07 07:02:22 -080055const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070056const int kDefaultFramerate = 30;
Åsa Persson8c1bf952018-09-13 10:42:19 +020057const int64_t kFrameIntervalMs = rtc::kNumMillisecsPerSec / kDefaultFramerate;
asapersson5f7226f2016-11-25 04:37:00 -080058
perkj803d97f2016-11-01 11:45:46 -070059class TestBuffer : public webrtc::I420Buffer {
60 public:
61 TestBuffer(rtc::Event* event, int width, int height)
62 : I420Buffer(width, height), event_(event) {}
63
64 private:
65 friend class rtc::RefCountedObject<TestBuffer>;
66 ~TestBuffer() override {
67 if (event_)
68 event_->Set();
69 }
70 rtc::Event* const event_;
71};
72
Niels Möller7dc26b72017-12-06 10:27:48 +010073class CpuOveruseDetectorProxy : public OveruseFrameDetector {
74 public:
Niels Möllerd1f7eb62018-03-28 16:40:58 +020075 explicit CpuOveruseDetectorProxy(CpuOveruseMetricsObserver* metrics_observer)
76 : OveruseFrameDetector(metrics_observer),
Niels Möller7dc26b72017-12-06 10:27:48 +010077 last_target_framerate_fps_(-1) {}
78 virtual ~CpuOveruseDetectorProxy() {}
79
80 void OnTargetFramerateUpdated(int framerate_fps) override {
81 rtc::CritScope cs(&lock_);
82 last_target_framerate_fps_ = framerate_fps;
83 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
84 }
85
86 int GetLastTargetFramerate() {
87 rtc::CritScope cs(&lock_);
88 return last_target_framerate_fps_;
89 }
90
Niels Möller4db138e2018-04-19 09:04:13 +020091 CpuOveruseOptions GetOptions() { return options_; }
92
Niels Möller7dc26b72017-12-06 10:27:48 +010093 private:
94 rtc::CriticalSection lock_;
95 int last_target_framerate_fps_ RTC_GUARDED_BY(lock_);
96};
97
mflodmancc3d4422017-08-03 08:27:51 -070098class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -070099 public:
Niels Möller213618e2018-07-24 09:29:58 +0200100 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
101 const VideoStreamEncoderSettings& settings)
Yves Gerey665174f2018-06-19 15:03:05 +0200102 : VideoStreamEncoder(1 /* number_of_cores */,
103 stats_proxy,
104 settings,
Yves Gerey665174f2018-06-19 15:03:05 +0200105 std::unique_ptr<OveruseFrameDetector>(
106 overuse_detector_proxy_ =
107 new CpuOveruseDetectorProxy(stats_proxy))) {}
perkj803d97f2016-11-01 11:45:46 -0700108
sprangb1ca0732017-02-01 08:38:12 -0800109 void PostTaskAndWait(bool down, AdaptReason reason) {
Niels Möllerc572ff32018-11-07 08:43:50 +0100110 rtc::Event event;
kthelgason876222f2016-11-29 01:44:11 -0800111 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800112 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700113 event.Set();
114 });
perkj070ba852017-02-16 15:46:27 -0800115 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700116 }
117
kthelgason2fc52542017-03-03 00:24:41 -0800118 // This is used as a synchronisation mechanism, to make sure that the
119 // encoder queue is not blocked before we start sending it frames.
120 void WaitUntilTaskQueueIsIdle() {
Niels Möllerc572ff32018-11-07 08:43:50 +0100121 rtc::Event event;
Yves Gerey665174f2018-06-19 15:03:05 +0200122 encoder_queue()->PostTask([&event] { event.Set(); });
kthelgason2fc52542017-03-03 00:24:41 -0800123 ASSERT_TRUE(event.Wait(5000));
124 }
125
sprangb1ca0732017-02-01 08:38:12 -0800126 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800127
sprangb1ca0732017-02-01 08:38:12 -0800128 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800129
sprangb1ca0732017-02-01 08:38:12 -0800130 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800131
sprangb1ca0732017-02-01 08:38:12 -0800132 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700133
Niels Möller7dc26b72017-12-06 10:27:48 +0100134 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700135};
136
asapersson5f7226f2016-11-25 04:37:00 -0800137class VideoStreamFactory
138 : public VideoEncoderConfig::VideoStreamFactoryInterface {
139 public:
sprangfda496a2017-06-15 04:21:07 -0700140 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
141 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800142 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700143 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800144 }
145
146 private:
147 std::vector<VideoStream> CreateEncoderStreams(
148 int width,
149 int height,
150 const VideoEncoderConfig& encoder_config) override {
151 std::vector<VideoStream> streams =
152 test::CreateVideoStreams(width, height, encoder_config);
153 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +0100154 stream.num_temporal_layers = num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700155 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800156 }
157 return streams;
158 }
sprangfda496a2017-06-15 04:21:07 -0700159
asapersson5f7226f2016-11-25 04:37:00 -0800160 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700161 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800162};
163
sprangb1ca0732017-02-01 08:38:12 -0800164class AdaptingFrameForwarder : public test::FrameForwarder {
165 public:
166 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700167 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800168
169 void set_adaptation_enabled(bool enabled) {
170 rtc::CritScope cs(&crit_);
171 adaptation_enabled_ = enabled;
172 }
173
asaperssonfab67072017-04-04 05:51:49 -0700174 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800175 rtc::CritScope cs(&crit_);
176 return adaptation_enabled_;
177 }
178
asapersson09f05612017-05-15 23:40:18 -0700179 rtc::VideoSinkWants last_wants() const {
180 rtc::CritScope cs(&crit_);
181 return last_wants_;
182 }
183
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200184 absl::optional<int> last_sent_width() const { return last_width_; }
185 absl::optional<int> last_sent_height() const { return last_height_; }
Jonathan Yubc771b72017-12-08 17:04:29 -0800186
sprangb1ca0732017-02-01 08:38:12 -0800187 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
188 int cropped_width = 0;
189 int cropped_height = 0;
190 int out_width = 0;
191 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700192 if (adaption_enabled()) {
193 if (adapter_.AdaptFrameResolution(
194 video_frame.width(), video_frame.height(),
195 video_frame.timestamp_us() * 1000, &cropped_width,
196 &cropped_height, &out_width, &out_height)) {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100197 VideoFrame adapted_frame =
198 VideoFrame::Builder()
199 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
200 nullptr, out_width, out_height))
201 .set_timestamp_rtp(99)
202 .set_timestamp_ms(99)
203 .set_rotation(kVideoRotation_0)
204 .build();
sprangc5d62e22017-04-02 23:53:04 -0700205 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
206 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800207 last_width_.emplace(adapted_frame.width());
208 last_height_.emplace(adapted_frame.height());
209 } else {
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200210 last_width_ = absl::nullopt;
211 last_height_ = absl::nullopt;
sprangc5d62e22017-04-02 23:53:04 -0700212 }
sprangb1ca0732017-02-01 08:38:12 -0800213 } else {
214 test::FrameForwarder::IncomingCapturedFrame(video_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800215 last_width_.emplace(video_frame.width());
216 last_height_.emplace(video_frame.height());
sprangb1ca0732017-02-01 08:38:12 -0800217 }
218 }
219
220 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
221 const rtc::VideoSinkWants& wants) override {
222 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700223 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700224 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
225 wants.max_pixel_count,
226 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800227 test::FrameForwarder::AddOrUpdateSink(sink, wants);
228 }
sprangb1ca0732017-02-01 08:38:12 -0800229 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700230 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
231 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200232 absl::optional<int> last_width_;
233 absl::optional<int> last_height_;
sprangb1ca0732017-02-01 08:38:12 -0800234};
sprangc5d62e22017-04-02 23:53:04 -0700235
Niels Möller213618e2018-07-24 09:29:58 +0200236// TODO(nisse): Mock only VideoStreamEncoderObserver.
sprangc5d62e22017-04-02 23:53:04 -0700237class MockableSendStatisticsProxy : public SendStatisticsProxy {
238 public:
239 MockableSendStatisticsProxy(Clock* clock,
240 const VideoSendStream::Config& config,
241 VideoEncoderConfig::ContentType content_type)
242 : SendStatisticsProxy(clock, config, content_type) {}
243
244 VideoSendStream::Stats GetStats() override {
245 rtc::CritScope cs(&lock_);
246 if (mock_stats_)
247 return *mock_stats_;
248 return SendStatisticsProxy::GetStats();
249 }
250
Niels Möller213618e2018-07-24 09:29:58 +0200251 int GetInputFrameRate() const override {
252 rtc::CritScope cs(&lock_);
253 if (mock_stats_)
254 return mock_stats_->input_frame_rate;
255 return SendStatisticsProxy::GetInputFrameRate();
256 }
sprangc5d62e22017-04-02 23:53:04 -0700257 void SetMockStats(const VideoSendStream::Stats& stats) {
258 rtc::CritScope cs(&lock_);
259 mock_stats_.emplace(stats);
260 }
261
262 void ResetMockStats() {
263 rtc::CritScope cs(&lock_);
264 mock_stats_.reset();
265 }
266
267 private:
268 rtc::CriticalSection lock_;
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200269 absl::optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700270};
271
sprang4847ae62017-06-27 07:06:52 -0700272class MockBitrateObserver : public VideoBitrateAllocationObserver {
273 public:
Erik Språng566124a2018-04-23 12:32:22 +0200274 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const VideoBitrateAllocation&));
sprang4847ae62017-06-27 07:06:52 -0700275};
276
perkj803d97f2016-11-01 11:45:46 -0700277} // namespace
278
mflodmancc3d4422017-08-03 08:27:51 -0700279class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700280 public:
281 static const int kDefaultTimeoutMs = 30 * 1000;
282
mflodmancc3d4422017-08-03 08:27:51 -0700283 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700284 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700285 codec_width_(320),
286 codec_height_(240),
Åsa Persson8c1bf952018-09-13 10:42:19 +0200287 max_framerate_(kDefaultFramerate),
perkj26091b12016-09-01 01:17:40 -0700288 fake_encoder_(),
Niels Möller4db138e2018-04-19 09:04:13 +0200289 encoder_factory_(&fake_encoder_),
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800290 bitrate_allocator_factory_(CreateBuiltinVideoBitrateAllocatorFactory()),
sprangc5d62e22017-04-02 23:53:04 -0700291 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700292 Clock::GetRealTimeClock(),
293 video_send_config_,
294 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700295 sink_(&fake_encoder_) {}
296
297 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700298 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700299 video_send_config_ = VideoSendStream::Config(nullptr);
Niels Möller4db138e2018-04-19 09:04:13 +0200300 video_send_config_.encoder_settings.encoder_factory = &encoder_factory_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800301 video_send_config_.encoder_settings.bitrate_allocator_factory =
302 bitrate_allocator_factory_.get();
Niels Möller259a4972018-04-05 15:36:51 +0200303 video_send_config_.rtp.payload_name = "FAKE";
304 video_send_config_.rtp.payload_type = 125;
perkj26091b12016-09-01 01:17:40 -0700305
Per512ecb32016-09-23 15:52:06 +0200306 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200307 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700308 video_encoder_config.video_stream_factory =
309 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100310 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700311
312 // Framerate limit is specified by the VideoStreamFactory.
313 std::vector<VideoStream> streams =
314 video_encoder_config.video_stream_factory->CreateEncoderStreams(
315 codec_width_, codec_height_, video_encoder_config);
316 max_framerate_ = streams[0].max_framerate;
317 fake_clock_.SetTimeMicros(1234);
318
Niels Möllerf1338562018-04-26 09:51:47 +0200319 ConfigureEncoder(std::move(video_encoder_config));
asapersson5f7226f2016-11-25 04:37:00 -0800320 }
321
Niels Möllerf1338562018-04-26 09:51:47 +0200322 void ConfigureEncoder(VideoEncoderConfig video_encoder_config) {
mflodmancc3d4422017-08-03 08:27:51 -0700323 if (video_stream_encoder_)
324 video_stream_encoder_->Stop();
325 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700326 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700327 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
328 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700329 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -0700330 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
331 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200332 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -0700333 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800334 }
335
336 void ResetEncoder(const std::string& payload_name,
337 size_t num_streams,
338 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700339 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700340 bool screenshare) {
Niels Möller259a4972018-04-05 15:36:51 +0200341 video_send_config_.rtp.payload_name = payload_name;
asapersson5f7226f2016-11-25 04:37:00 -0800342
343 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200344 video_encoder_config.codec_type = PayloadStringToCodecType(payload_name);
asapersson5f7226f2016-11-25 04:37:00 -0800345 video_encoder_config.number_of_streams = num_streams;
Erik Språngd7329ca2019-02-21 21:19:53 +0100346 video_encoder_config.max_bitrate_bps =
347 num_streams == 1 ? kTargetBitrateBps : kSimulcastTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800348 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700349 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
350 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700351 video_encoder_config.content_type =
352 screenshare ? VideoEncoderConfig::ContentType::kScreen
353 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700354 if (payload_name == "VP9") {
355 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
356 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
357 video_encoder_config.encoder_specific_settings =
358 new rtc::RefCountedObject<
359 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
360 }
Niels Möllerf1338562018-04-26 09:51:47 +0200361 ConfigureEncoder(std::move(video_encoder_config));
perkj26091b12016-09-01 01:17:40 -0700362 }
363
sprang57c2fff2017-01-16 06:24:02 -0800364 VideoFrame CreateFrame(int64_t ntp_time_ms,
365 rtc::Event* destruction_event) const {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100366 VideoFrame frame =
367 VideoFrame::Builder()
368 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
369 destruction_event, codec_width_, codec_height_))
370 .set_timestamp_rtp(99)
371 .set_timestamp_ms(99)
372 .set_rotation(kVideoRotation_0)
373 .build();
sprang57c2fff2017-01-16 06:24:02 -0800374 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700375 return frame;
376 }
377
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100378 VideoFrame CreateFrameWithUpdatedPixel(int64_t ntp_time_ms,
379 rtc::Event* destruction_event,
380 int offset_x) const {
381 VideoFrame frame =
382 VideoFrame::Builder()
383 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
384 destruction_event, codec_width_, codec_height_))
385 .set_timestamp_rtp(99)
386 .set_timestamp_ms(99)
387 .set_rotation(kVideoRotation_0)
388 .set_update_rect({offset_x, 0, 1, 1})
389 .build();
390 frame.set_ntp_time_ms(ntp_time_ms);
391 return frame;
392 }
393
sprang57c2fff2017-01-16 06:24:02 -0800394 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100395 VideoFrame frame =
396 VideoFrame::Builder()
397 .set_video_frame_buffer(
398 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height))
399 .set_timestamp_rtp(99)
400 .set_timestamp_ms(99)
401 .set_rotation(kVideoRotation_0)
402 .build();
sprang57c2fff2017-01-16 06:24:02 -0800403 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700404 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700405 return frame;
406 }
407
asapersson02465b82017-04-10 01:12:52 -0700408 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700409 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700410 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
411 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700412 }
413
asapersson09f05612017-05-15 23:40:18 -0700414 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
415 const rtc::VideoSinkWants& wants2) {
416 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
417 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
418 }
419
Åsa Persson8c1bf952018-09-13 10:42:19 +0200420 void VerifyFpsMaxResolutionMax(const rtc::VideoSinkWants& wants) {
421 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
422 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
423 EXPECT_FALSE(wants.target_pixel_count);
424 }
425
asapersson09f05612017-05-15 23:40:18 -0700426 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
427 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200428 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700429 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
430 EXPECT_GT(wants1.max_pixel_count, 0);
431 }
432
433 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
434 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200435 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700436 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
437 }
438
asaperssonf7e294d2017-06-13 23:25:22 -0700439 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
440 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200441 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700442 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
443 }
444
445 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
446 const rtc::VideoSinkWants& wants2) {
447 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
448 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
449 }
450
451 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
452 const rtc::VideoSinkWants& wants2) {
453 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
454 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
455 }
456
457 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
458 const rtc::VideoSinkWants& wants2) {
459 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
460 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
461 EXPECT_GT(wants1.max_pixel_count, 0);
462 }
463
464 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
465 const rtc::VideoSinkWants& wants2) {
466 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
467 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
468 }
469
asapersson09f05612017-05-15 23:40:18 -0700470 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
471 int pixel_count) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200472 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700473 EXPECT_LT(wants.max_pixel_count, pixel_count);
474 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700475 }
476
477 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
478 EXPECT_LT(wants.max_framerate_fps, fps);
479 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
480 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700481 }
482
asaperssonf7e294d2017-06-13 23:25:22 -0700483 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
484 int expected_fps) {
485 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
486 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
487 EXPECT_FALSE(wants.target_pixel_count);
488 }
489
Jonathan Yubc771b72017-12-08 17:04:29 -0800490 void VerifyBalancedModeFpsRange(const rtc::VideoSinkWants& wants,
491 int last_frame_pixels) {
492 // Balanced mode should always scale FPS to the desired range before
493 // attempting to scale resolution.
494 int fps_limit = wants.max_framerate_fps;
495 if (last_frame_pixels <= 320 * 240) {
496 EXPECT_TRUE(7 <= fps_limit && fps_limit <= 10);
497 } else if (last_frame_pixels <= 480 * 270) {
498 EXPECT_TRUE(10 <= fps_limit && fps_limit <= 15);
499 } else if (last_frame_pixels <= 640 * 480) {
500 EXPECT_LE(15, fps_limit);
501 } else {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200502 EXPECT_EQ(kDefaultFramerate, fps_limit);
Jonathan Yubc771b72017-12-08 17:04:29 -0800503 }
504 }
505
sprang4847ae62017-06-27 07:06:52 -0700506 void WaitForEncodedFrame(int64_t expected_ntp_time) {
507 sink_.WaitForEncodedFrame(expected_ntp_time);
508 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
509 }
510
511 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
512 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
513 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
514 return ok;
515 }
516
517 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
518 sink_.WaitForEncodedFrame(expected_width, expected_height);
519 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
520 }
521
522 void ExpectDroppedFrame() {
523 sink_.ExpectDroppedFrame();
524 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
525 }
526
527 bool WaitForFrame(int64_t timeout_ms) {
528 bool ok = sink_.WaitForFrame(timeout_ms);
529 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
530 return ok;
531 }
532
perkj26091b12016-09-01 01:17:40 -0700533 class TestEncoder : public test::FakeEncoder {
534 public:
Niels Möllerc572ff32018-11-07 08:43:50 +0100535 TestEncoder() : FakeEncoder(Clock::GetRealTimeClock()) {}
perkj26091b12016-09-01 01:17:40 -0700536
asaperssonfab67072017-04-04 05:51:49 -0700537 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800538 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700539 return config_;
540 }
541
542 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800543 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700544 block_next_encode_ = true;
545 }
546
Erik Språngaed30702018-11-05 12:57:17 +0100547 VideoEncoder::EncoderInfo GetEncoderInfo() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800548 rtc::CritScope lock(&local_crit_sect_);
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100549 EncoderInfo info;
550 if (initialized_) {
551 if (quality_scaling_) {
552 info.scaling_settings =
553 VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
554 }
555 info.is_hardware_accelerated = is_hardware_accelerated_;
Erik Språngaed30702018-11-05 12:57:17 +0100556 }
557 return info;
kthelgason876222f2016-11-29 01:44:11 -0800558 }
559
perkjfa10b552016-10-02 23:45:26 -0700560 void ContinueEncode() { continue_encode_event_.Set(); }
561
562 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
563 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800564 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700565 EXPECT_EQ(timestamp_, timestamp);
566 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
567 }
568
kthelgason2fc52542017-03-03 00:24:41 -0800569 void SetQualityScaling(bool b) {
570 rtc::CritScope lock(&local_crit_sect_);
571 quality_scaling_ = b;
572 }
kthelgasonad9010c2017-02-14 00:46:51 -0800573
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100574 void SetIsHardwareAccelerated(bool is_hardware_accelerated) {
575 rtc::CritScope lock(&local_crit_sect_);
576 is_hardware_accelerated_ = is_hardware_accelerated;
577 }
578
sprangfe627f32017-03-29 08:24:59 -0700579 void ForceInitEncodeFailure(bool force_failure) {
580 rtc::CritScope lock(&local_crit_sect_);
581 force_init_encode_failed_ = force_failure;
582 }
583
Niels Möller6bb5ab92019-01-11 11:11:10 +0100584 void SimulateOvershoot(double rate_factor) {
585 rtc::CritScope lock(&local_crit_sect_);
586 rate_factor_ = rate_factor;
587 }
588
Erik Språngd7329ca2019-02-21 21:19:53 +0100589 uint32_t GetLastFramerate() const {
Niels Möller6bb5ab92019-01-11 11:11:10 +0100590 rtc::CritScope lock(&local_crit_sect_);
591 return last_framerate_;
592 }
593
Erik Språngd7329ca2019-02-21 21:19:53 +0100594 VideoFrame::UpdateRect GetLastUpdateRect() const {
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100595 rtc::CritScope lock(&local_crit_sect_);
596 return last_update_rect_;
597 }
598
Erik Språngd7329ca2019-02-21 21:19:53 +0100599 const std::vector<FrameType>& LastFrameTypes() const {
600 rtc::CritScope lock(&local_crit_sect_);
601 return last_frame_types_;
602 }
603
604 void InjectFrame(const VideoFrame& input_image, bool keyframe) {
605 const std::vector<FrameType> frame_type = {keyframe ? kVideoFrameKey
606 : kVideoFrameDelta};
607 {
608 rtc::CritScope lock(&local_crit_sect_);
609 last_frame_types_ = frame_type;
610 }
611 FakeEncoder::Encode(input_image, nullptr, &frame_type);
612 }
613
614 void ExpectNullFrame() {
615 rtc::CritScope lock(&local_crit_sect_);
616 expect_null_frame_ = true;
617 }
618
619 absl::optional<VideoBitrateAllocation> GetAndResetLastBitrateAllocation() {
620 auto allocation = last_bitrate_allocation_;
621 last_bitrate_allocation_.reset();
622 return allocation;
623 }
624
perkjfa10b552016-10-02 23:45:26 -0700625 private:
perkj26091b12016-09-01 01:17:40 -0700626 int32_t Encode(const VideoFrame& input_image,
627 const CodecSpecificInfo* codec_specific_info,
628 const std::vector<FrameType>* frame_types) override {
629 bool block_encode;
630 {
brandtre78d2662017-01-16 05:57:16 -0800631 rtc::CritScope lock(&local_crit_sect_);
Erik Språngd7329ca2019-02-21 21:19:53 +0100632 if (expect_null_frame_) {
633 EXPECT_EQ(input_image.timestamp(), 0u);
634 EXPECT_EQ(input_image.width(), 1);
635 last_frame_types_ = *frame_types;
636 expect_null_frame_ = false;
637 } else {
638 EXPECT_GT(input_image.timestamp(), timestamp_);
639 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
640 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
641 }
perkj26091b12016-09-01 01:17:40 -0700642
643 timestamp_ = input_image.timestamp();
644 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700645 last_input_width_ = input_image.width();
646 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700647 block_encode = block_next_encode_;
648 block_next_encode_ = false;
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100649 last_update_rect_ = input_image.update_rect();
Erik Språngd7329ca2019-02-21 21:19:53 +0100650 last_frame_types_ = *frame_types;
perkj26091b12016-09-01 01:17:40 -0700651 }
652 int32_t result =
653 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
654 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700655 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700656 return result;
657 }
658
sprangfe627f32017-03-29 08:24:59 -0700659 int32_t InitEncode(const VideoCodec* config,
660 int32_t number_of_cores,
661 size_t max_payload_size) override {
662 int res =
663 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
664 rtc::CritScope lock(&local_crit_sect_);
Erik Språng82fad3d2018-03-21 09:57:23 +0100665 if (config->codecType == kVideoCodecVP8) {
sprangfe627f32017-03-29 08:24:59 -0700666 // Simulate setting up temporal layers, in order to validate the life
667 // cycle of these objects.
668 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
sprangfe627f32017-03-29 08:24:59 -0700669 for (int i = 0; i < num_streams; ++i) {
670 allocated_temporal_layers_.emplace_back(
Erik Språng4529fbc2018-10-12 10:30:31 +0200671 CreateVp8TemporalLayers(Vp8TemporalLayersType::kFixedPattern,
672 config->VP8().numberOfTemporalLayers));
sprangfe627f32017-03-29 08:24:59 -0700673 }
674 }
675 if (force_init_encode_failed_)
676 return -1;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100677
678 initialized_ = true;
sprangfe627f32017-03-29 08:24:59 -0700679 return res;
680 }
681
Niels Möller6bb5ab92019-01-11 11:11:10 +0100682 int32_t SetRateAllocation(const VideoBitrateAllocation& rate_allocation,
683 uint32_t framerate) {
684 rtc::CritScope lock(&local_crit_sect_);
685 VideoBitrateAllocation adjusted_rate_allocation;
686 for (size_t si = 0; si < kMaxSpatialLayers; ++si) {
687 for (size_t ti = 0; ti < kMaxTemporalStreams; ++ti) {
688 if (rate_allocation.HasBitrate(si, ti)) {
689 adjusted_rate_allocation.SetBitrate(
690 si, ti,
691 static_cast<uint32_t>(rate_allocation.GetBitrate(si, ti) *
692 rate_factor_));
693 }
694 }
695 }
696 last_framerate_ = framerate;
Erik Språngd7329ca2019-02-21 21:19:53 +0100697 last_bitrate_allocation_ = rate_allocation;
Niels Möller6bb5ab92019-01-11 11:11:10 +0100698 return FakeEncoder::SetRateAllocation(adjusted_rate_allocation,
699 framerate);
700 }
701
brandtre78d2662017-01-16 05:57:16 -0800702 rtc::CriticalSection local_crit_sect_;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100703 bool initialized_ RTC_GUARDED_BY(local_crit_sect_) = false;
danilchapa37de392017-09-09 04:17:22 -0700704 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700705 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700706 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
707 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
708 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
709 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
710 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100711 bool is_hardware_accelerated_ RTC_GUARDED_BY(local_crit_sect_) = false;
Erik Språng4529fbc2018-10-12 10:30:31 +0200712 std::vector<std::unique_ptr<Vp8TemporalLayers>> allocated_temporal_layers_
danilchapa37de392017-09-09 04:17:22 -0700713 RTC_GUARDED_BY(local_crit_sect_);
714 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
Niels Möller6bb5ab92019-01-11 11:11:10 +0100715 double rate_factor_ RTC_GUARDED_BY(local_crit_sect_) = 1.0;
716 uint32_t last_framerate_ RTC_GUARDED_BY(local_crit_sect_) = 0;
Erik Språngd7329ca2019-02-21 21:19:53 +0100717 absl::optional<VideoBitrateAllocation> last_bitrate_allocation_;
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100718 VideoFrame::UpdateRect last_update_rect_
719 RTC_GUARDED_BY(local_crit_sect_) = {0, 0, 0, 0};
Erik Språngd7329ca2019-02-21 21:19:53 +0100720 std::vector<FrameType> last_frame_types_;
721 bool expect_null_frame_ = false;
perkj26091b12016-09-01 01:17:40 -0700722 };
723
mflodmancc3d4422017-08-03 08:27:51 -0700724 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700725 public:
726 explicit TestSink(TestEncoder* test_encoder)
Niels Möllerc572ff32018-11-07 08:43:50 +0100727 : test_encoder_(test_encoder) {}
perkj26091b12016-09-01 01:17:40 -0700728
perkj26091b12016-09-01 01:17:40 -0700729 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700730 EXPECT_TRUE(
731 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
732 }
733
734 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
735 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700736 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700737 if (!encoded_frame_event_.Wait(timeout_ms))
738 return false;
perkj26091b12016-09-01 01:17:40 -0700739 {
740 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800741 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700742 }
743 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700744 return true;
perkj26091b12016-09-01 01:17:40 -0700745 }
746
sprangb1ca0732017-02-01 08:38:12 -0800747 void WaitForEncodedFrame(uint32_t expected_width,
748 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700749 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100750 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700751 }
752
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100753 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700754 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800755 uint32_t width = 0;
756 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800757 {
758 rtc::CritScope lock(&crit_);
759 width = last_width_;
760 height = last_height_;
761 }
762 EXPECT_EQ(expected_height, height);
763 EXPECT_EQ(expected_width, width);
764 }
765
kthelgason2fc52542017-03-03 00:24:41 -0800766 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800767
sprangc5d62e22017-04-02 23:53:04 -0700768 bool WaitForFrame(int64_t timeout_ms) {
769 return encoded_frame_event_.Wait(timeout_ms);
770 }
771
perkj26091b12016-09-01 01:17:40 -0700772 void SetExpectNoFrames() {
773 rtc::CritScope lock(&crit_);
774 expect_frames_ = false;
775 }
776
asaperssonfab67072017-04-04 05:51:49 -0700777 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200778 rtc::CritScope lock(&crit_);
779 return number_of_reconfigurations_;
780 }
781
asaperssonfab67072017-04-04 05:51:49 -0700782 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200783 rtc::CritScope lock(&crit_);
784 return min_transmit_bitrate_bps_;
785 }
786
Erik Språngd7329ca2019-02-21 21:19:53 +0100787 void SetNumExpectedLayers(size_t num_layers) {
788 rtc::CritScope lock(&crit_);
789 num_expected_layers_ = num_layers;
790 }
791
perkj26091b12016-09-01 01:17:40 -0700792 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700793 Result OnEncodedImage(
794 const EncodedImage& encoded_image,
795 const CodecSpecificInfo* codec_specific_info,
796 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200797 rtc::CritScope lock(&crit_);
798 EXPECT_TRUE(expect_frames_);
Erik Språngd7329ca2019-02-21 21:19:53 +0100799 uint32_t timestamp = encoded_image.Timestamp();
800 if (last_timestamp_ != timestamp) {
801 num_received_layers_ = 1;
802 } else {
803 ++num_received_layers_;
804 }
805 last_timestamp_ = timestamp;
sprangb1ca0732017-02-01 08:38:12 -0800806 last_width_ = encoded_image._encodedWidth;
807 last_height_ = encoded_image._encodedHeight;
Erik Språngd7329ca2019-02-21 21:19:53 +0100808 if (num_received_layers_ == num_expected_layers_) {
809 encoded_frame_event_.Set();
810 }
sprangb1ca0732017-02-01 08:38:12 -0800811 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200812 }
813
Rasmus Brandtc402dbe2019-02-04 11:09:46 +0100814 void OnEncoderConfigurationChanged(
815 std::vector<VideoStream> streams,
816 VideoEncoderConfig::ContentType content_type,
817 int min_transmit_bitrate_bps) override {
Per512ecb32016-09-23 15:52:06 +0200818 rtc::CriticalSection crit_;
819 ++number_of_reconfigurations_;
820 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
821 }
822
perkj26091b12016-09-01 01:17:40 -0700823 rtc::CriticalSection crit_;
824 TestEncoder* test_encoder_;
825 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800826 uint32_t last_timestamp_ = 0;
827 uint32_t last_height_ = 0;
828 uint32_t last_width_ = 0;
Erik Språngd7329ca2019-02-21 21:19:53 +0100829 size_t num_expected_layers_ = 1;
830 size_t num_received_layers_ = 0;
perkj26091b12016-09-01 01:17:40 -0700831 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200832 int number_of_reconfigurations_ = 0;
833 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700834 };
835
836 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100837 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200838 int codec_width_;
839 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700840 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700841 TestEncoder fake_encoder_;
Niels Möllercbcbc222018-09-28 09:07:24 +0200842 test::VideoEncoderProxyFactory encoder_factory_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800843 std::unique_ptr<VideoBitrateAllocatorFactory> bitrate_allocator_factory_;
sprangc5d62e22017-04-02 23:53:04 -0700844 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700845 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800846 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700847 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700848 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700849};
850
mflodmancc3d4422017-08-03 08:27:51 -0700851TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
852 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Niels Möllerc572ff32018-11-07 08:43:50 +0100853 rtc::Event frame_destroyed_event;
perkja49cbd32016-09-16 07:53:41 -0700854 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700855 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700856 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700857 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700858}
859
mflodmancc3d4422017-08-03 08:27:51 -0700860TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700861 // Dropped since no target bitrate has been set.
Niels Möllerc572ff32018-11-07 08:43:50 +0100862 rtc::Event frame_destroyed_event;
Sebastian Janssona3177052018-04-10 13:05:49 +0200863 // The encoder will cache up to one frame for a short duration. Adding two
864 // frames means that the first frame will be dropped and the second frame will
865 // be sent when the encoder is enabled.
perkja49cbd32016-09-16 07:53:41 -0700866 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
Sebastian Janssona3177052018-04-10 13:05:49 +0200867 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkja49cbd32016-09-16 07:53:41 -0700868 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700869
mflodmancc3d4422017-08-03 08:27:51 -0700870 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700871
Sebastian Janssona3177052018-04-10 13:05:49 +0200872 // The pending frame should be received.
sprang4847ae62017-06-27 07:06:52 -0700873 WaitForEncodedFrame(2);
Sebastian Janssona3177052018-04-10 13:05:49 +0200874 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
875
876 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700877 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700878}
879
mflodmancc3d4422017-08-03 08:27:51 -0700880TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
881 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700882 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700883 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700884
mflodmancc3d4422017-08-03 08:27:51 -0700885 video_stream_encoder_->OnBitrateUpdated(0, 0, 0);
Sebastian Janssona3177052018-04-10 13:05:49 +0200886 // The encoder will cache up to one frame for a short duration. Adding two
887 // frames means that the first frame will be dropped and the second frame will
888 // be sent when the encoder is resumed.
perkja49cbd32016-09-16 07:53:41 -0700889 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Sebastian Janssona3177052018-04-10 13:05:49 +0200890 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700891
mflodmancc3d4422017-08-03 08:27:51 -0700892 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -0700893 WaitForEncodedFrame(3);
Sebastian Janssona3177052018-04-10 13:05:49 +0200894 video_source_.IncomingCapturedFrame(CreateFrame(4, nullptr));
895 WaitForEncodedFrame(4);
mflodmancc3d4422017-08-03 08:27:51 -0700896 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700897}
898
mflodmancc3d4422017-08-03 08:27:51 -0700899TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
900 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700901 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700902 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700903
904 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700905 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700906
perkja49cbd32016-09-16 07:53:41 -0700907 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700908 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700909 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700910}
911
mflodmancc3d4422017-08-03 08:27:51 -0700912TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
913 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700914
perkja49cbd32016-09-16 07:53:41 -0700915 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700916 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700917
mflodmancc3d4422017-08-03 08:27:51 -0700918 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700919 sink_.SetExpectNoFrames();
Niels Möllerc572ff32018-11-07 08:43:50 +0100920 rtc::Event frame_destroyed_event;
perkja49cbd32016-09-16 07:53:41 -0700921 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
922 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700923}
924
mflodmancc3d4422017-08-03 08:27:51 -0700925TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
926 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700927
928 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700929 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700930 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700931 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
932 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700933 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
934 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700935 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700936 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700937
mflodmancc3d4422017-08-03 08:27:51 -0700938 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700939}
940
mflodmancc3d4422017-08-03 08:27:51 -0700941TEST_F(VideoStreamEncoderTest,
942 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
943 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100944 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200945
946 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200947 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700948 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100949 // The encoder will have been configured once when the first frame is
950 // received.
951 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200952
953 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200954 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200955 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -0700956 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200957 kMaxPayloadLength);
Per512ecb32016-09-23 15:52:06 +0200958
959 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200960 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700961 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100962 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700963 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700964
mflodmancc3d4422017-08-03 08:27:51 -0700965 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -0700966}
967
mflodmancc3d4422017-08-03 08:27:51 -0700968TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
969 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkjfa10b552016-10-02 23:45:26 -0700970
971 // Capture a frame and wait for it to synchronize with the encoder thread.
972 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700973 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100974 // The encoder will have been configured once.
975 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700976 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
977 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
978
979 codec_width_ *= 2;
980 codec_height_ *= 2;
981 // Capture a frame with a higher resolution and wait for it to synchronize
982 // with the encoder thread.
983 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700984 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700985 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
986 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100987 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700988
mflodmancc3d4422017-08-03 08:27:51 -0700989 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -0700990}
991
mflodmancc3d4422017-08-03 08:27:51 -0700992TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -0700993 EXPECT_TRUE(video_source_.has_sinks());
994 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700995 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700996 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -0700997 EXPECT_FALSE(video_source_.has_sinks());
998 EXPECT_TRUE(new_video_source.has_sinks());
999
mflodmancc3d4422017-08-03 08:27:51 -07001000 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001001}
1002
mflodmancc3d4422017-08-03 08:27:51 -07001003TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -07001004 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -07001005 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -07001006 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -07001007 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001008}
1009
Jonathan Yubc771b72017-12-08 17:04:29 -08001010TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
1011 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -07001012 const int kWidth = 1280;
1013 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -08001014
1015 // We rely on the automatic resolution adaptation, but we handle framerate
1016 // adaptation manually by mocking the stats proxy.
1017 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -07001018
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001019 // Enable BALANCED preference, no initial limitation.
Jonathan Yubc771b72017-12-08 17:04:29 -08001020 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001021 video_stream_encoder_->SetSource(&video_source_,
1022 webrtc::DegradationPreference::BALANCED);
Jonathan Yubc771b72017-12-08 17:04:29 -08001023 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001024 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001025 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -07001026 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1027
Jonathan Yubc771b72017-12-08 17:04:29 -08001028 // Adapt down as far as possible.
1029 rtc::VideoSinkWants last_wants;
1030 int64_t t = 1;
1031 int loop_count = 0;
1032 do {
1033 ++loop_count;
1034 last_wants = video_source_.sink_wants();
1035
1036 // Simulate the framerate we've been asked to adapt to.
1037 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
1038 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
1039 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1040 mock_stats.input_frame_rate = fps;
1041 stats_proxy_->SetMockStats(mock_stats);
1042
1043 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1044 sink_.WaitForEncodedFrame(t);
1045 t += frame_interval_ms;
1046
mflodmancc3d4422017-08-03 08:27:51 -07001047 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08001048 VerifyBalancedModeFpsRange(
1049 video_source_.sink_wants(),
1050 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1051 } while (video_source_.sink_wants().max_pixel_count <
1052 last_wants.max_pixel_count ||
1053 video_source_.sink_wants().max_framerate_fps <
1054 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001055
Jonathan Yubc771b72017-12-08 17:04:29 -08001056 // Verify that we've adapted all the way down.
1057 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001058 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001059 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
1060 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -07001061 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -08001062 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
1063 *video_source_.last_sent_height());
1064 EXPECT_EQ(kMinBalancedFramerateFps,
1065 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001066
Jonathan Yubc771b72017-12-08 17:04:29 -08001067 // Adapt back up the same number of times we adapted down.
1068 for (int i = 0; i < loop_count - 1; ++i) {
1069 last_wants = video_source_.sink_wants();
1070
1071 // Simulate the framerate we've been asked to adapt to.
1072 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
1073 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
1074 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1075 mock_stats.input_frame_rate = fps;
1076 stats_proxy_->SetMockStats(mock_stats);
1077
1078 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1079 sink_.WaitForEncodedFrame(t);
1080 t += frame_interval_ms;
1081
mflodmancc3d4422017-08-03 08:27:51 -07001082 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -08001083 VerifyBalancedModeFpsRange(
1084 video_source_.sink_wants(),
1085 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1086 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
1087 last_wants.max_pixel_count ||
1088 video_source_.sink_wants().max_framerate_fps >
1089 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001090 }
1091
Åsa Persson8c1bf952018-09-13 10:42:19 +02001092 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001093 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001094 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001095 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1096 EXPECT_EQ((loop_count - 1) * 2,
1097 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -07001098
mflodmancc3d4422017-08-03 08:27:51 -07001099 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001100}
mflodmancc3d4422017-08-03 08:27:51 -07001101TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
1102 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001103 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001104
sprangc5d62e22017-04-02 23:53:04 -07001105 const int kFrameWidth = 1280;
1106 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07001107
Åsa Persson8c1bf952018-09-13 10:42:19 +02001108 int64_t frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -07001109
kthelgason5e13d412016-12-01 03:59:51 -08001110 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001111 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001112 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001113 frame_timestamp += kFrameIntervalMs;
1114
perkj803d97f2016-11-01 11:45:46 -07001115 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001116 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001117 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001118 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001119 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001120 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -07001121
asapersson0944a802017-04-07 00:57:58 -07001122 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -07001123 // wanted resolution.
1124 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
1125 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
1126 kFrameWidth * kFrameHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001127 EXPECT_EQ(kDefaultFramerate, video_source_.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001128
1129 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -07001130 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001131 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001132 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001133
sprangc5d62e22017-04-02 23:53:04 -07001134 // Initially no degradation registered.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001135 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001136
sprangc5d62e22017-04-02 23:53:04 -07001137 // Force an input frame rate to be available, or the adaptation call won't
1138 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -07001139 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -07001140 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -07001141 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -07001142 stats_proxy_->SetMockStats(stats);
1143
mflodmancc3d4422017-08-03 08:27:51 -07001144 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001145 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001146 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001147 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001148 frame_timestamp += kFrameIntervalMs;
1149
1150 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001151 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001152 EXPECT_EQ(std::numeric_limits<int>::max(),
1153 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001154 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001155
asapersson02465b82017-04-10 01:12:52 -07001156 // Turn off degradation completely.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001157 video_stream_encoder_->SetSource(&new_video_source,
1158 webrtc::DegradationPreference::DISABLED);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001159 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001160
mflodmancc3d4422017-08-03 08:27:51 -07001161 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001162 new_video_source.IncomingCapturedFrame(
1163 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001164 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001165 frame_timestamp += kFrameIntervalMs;
1166
1167 // Still no degradation.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001168 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001169
1170 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001171 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001172 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
sprangc5d62e22017-04-02 23:53:04 -07001173 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1174 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001175 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001176 EXPECT_EQ(kDefaultFramerate, new_video_source.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001177
1178 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001179 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001180 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001181 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1182 EXPECT_EQ(std::numeric_limits<int>::max(),
1183 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001184 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001185
mflodmancc3d4422017-08-03 08:27:51 -07001186 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001187}
1188
mflodmancc3d4422017-08-03 08:27:51 -07001189TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
1190 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001191
asaperssonfab67072017-04-04 05:51:49 -07001192 const int kWidth = 1280;
1193 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001194 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001195 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001196 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1197 EXPECT_FALSE(stats.bw_limited_resolution);
1198 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1199
1200 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001201 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001202 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001203 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001204
1205 stats = stats_proxy_->GetStats();
1206 EXPECT_TRUE(stats.bw_limited_resolution);
1207 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1208
1209 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001210 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001211 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001212 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001213
1214 stats = stats_proxy_->GetStats();
1215 EXPECT_FALSE(stats.bw_limited_resolution);
1216 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1217 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1218
mflodmancc3d4422017-08-03 08:27:51 -07001219 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001220}
1221
mflodmancc3d4422017-08-03 08:27:51 -07001222TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
1223 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001224
1225 const int kWidth = 1280;
1226 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001227 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001228 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001229 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1230 EXPECT_FALSE(stats.cpu_limited_resolution);
1231 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1232
1233 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001234 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001235 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001236 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001237
1238 stats = stats_proxy_->GetStats();
1239 EXPECT_TRUE(stats.cpu_limited_resolution);
1240 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1241
1242 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001243 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001244 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001245 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001246
1247 stats = stats_proxy_->GetStats();
1248 EXPECT_FALSE(stats.cpu_limited_resolution);
1249 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001250 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001251
mflodmancc3d4422017-08-03 08:27:51 -07001252 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001253}
1254
mflodmancc3d4422017-08-03 08:27:51 -07001255TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
1256 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001257
asaperssonfab67072017-04-04 05:51:49 -07001258 const int kWidth = 1280;
1259 const int kHeight = 720;
1260 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001261 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001262 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001263 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001264 EXPECT_FALSE(stats.cpu_limited_resolution);
1265 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1266
asaperssonfab67072017-04-04 05:51:49 -07001267 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001268 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001269 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001270 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001271 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001272 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001273 EXPECT_TRUE(stats.cpu_limited_resolution);
1274 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1275
1276 // Set new source with adaptation still enabled.
1277 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001278 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001279 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001280
asaperssonfab67072017-04-04 05:51:49 -07001281 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001282 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001283 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001284 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001285 EXPECT_TRUE(stats.cpu_limited_resolution);
1286 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1287
1288 // Set adaptation disabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001289 video_stream_encoder_->SetSource(&new_video_source,
1290 webrtc::DegradationPreference::DISABLED);
kthelgason876222f2016-11-29 01:44:11 -08001291
asaperssonfab67072017-04-04 05:51:49 -07001292 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001293 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001294 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001295 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001296 EXPECT_FALSE(stats.cpu_limited_resolution);
1297 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1298
1299 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001300 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001301 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001302
asaperssonfab67072017-04-04 05:51:49 -07001303 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001304 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001305 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001306 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001307 EXPECT_TRUE(stats.cpu_limited_resolution);
1308 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1309
asaperssonfab67072017-04-04 05:51:49 -07001310 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001311 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001312 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001313 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001314 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001315 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001316 EXPECT_FALSE(stats.cpu_limited_resolution);
1317 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001318 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001319
mflodmancc3d4422017-08-03 08:27:51 -07001320 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001321}
1322
mflodmancc3d4422017-08-03 08:27:51 -07001323TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
1324 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001325
asaperssonfab67072017-04-04 05:51:49 -07001326 const int kWidth = 1280;
1327 const int kHeight = 720;
1328 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001329 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001330 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001331 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001332 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001333 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001334
1335 // Set new source with adaptation still enabled.
1336 test::FrameForwarder new_video_source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001337 video_stream_encoder_->SetSource(&new_video_source,
1338 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001339
asaperssonfab67072017-04-04 05:51:49 -07001340 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001341 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001342 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001343 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001344 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001345 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001346
asaperssonfab67072017-04-04 05:51:49 -07001347 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001348 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001349 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001350 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001351 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001352 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001353 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001354 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001355
asaperssonfab67072017-04-04 05:51:49 -07001356 // Set new source with adaptation still enabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001357 video_stream_encoder_->SetSource(&new_video_source,
1358 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001359
asaperssonfab67072017-04-04 05:51:49 -07001360 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001361 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001362 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001363 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001364 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001365 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001366
asapersson02465b82017-04-10 01:12:52 -07001367 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001368 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001369 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001370
asaperssonfab67072017-04-04 05:51:49 -07001371 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001372 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001373 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001374 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001375 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001376 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1377 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001378
mflodmancc3d4422017-08-03 08:27:51 -07001379 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001380}
1381
mflodmancc3d4422017-08-03 08:27:51 -07001382TEST_F(VideoStreamEncoderTest,
1383 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1384 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001385
1386 const int kWidth = 1280;
1387 const int kHeight = 720;
Åsa Persson8c1bf952018-09-13 10:42:19 +02001388 int64_t timestamp_ms = kFrameIntervalMs;
asapersson36e9eb42017-03-31 05:29:12 -07001389 video_source_.set_adaptation_enabled(true);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001390 video_source_.IncomingCapturedFrame(
1391 CreateFrame(timestamp_ms, kWidth, kHeight));
1392 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001393 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1394 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1395 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1396
1397 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001398 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001399 timestamp_ms += kFrameIntervalMs;
1400 video_source_.IncomingCapturedFrame(
1401 CreateFrame(timestamp_ms, kWidth, kHeight));
1402 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001403 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1404 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1405 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1406
1407 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001408 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001409 timestamp_ms += kFrameIntervalMs;
1410 video_source_.IncomingCapturedFrame(
1411 CreateFrame(timestamp_ms, kWidth, kHeight));
1412 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001413 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1414 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1415 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1416
Niels Möller4db138e2018-04-19 09:04:13 +02001417 // Leave source unchanged, but disable quality scaler.
asapersson36e9eb42017-03-31 05:29:12 -07001418 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02001419
1420 VideoEncoderConfig video_encoder_config;
1421 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
1422 // Make format different, to force recreation of encoder.
1423 video_encoder_config.video_format.parameters["foo"] = "foo";
1424 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001425 kMaxPayloadLength);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001426 timestamp_ms += kFrameIntervalMs;
1427 video_source_.IncomingCapturedFrame(
1428 CreateFrame(timestamp_ms, kWidth, kHeight));
1429 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001430 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1431 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1432 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1433
mflodmancc3d4422017-08-03 08:27:51 -07001434 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001435}
1436
mflodmancc3d4422017-08-03 08:27:51 -07001437TEST_F(VideoStreamEncoderTest,
1438 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
1439 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001440
asapersson0944a802017-04-07 00:57:58 -07001441 const int kWidth = 1280;
1442 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001443 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001444
asaperssonfab67072017-04-04 05:51:49 -07001445 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001446 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001447 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001448 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001449 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001450 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1451
asapersson02465b82017-04-10 01:12:52 -07001452 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001453 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001454 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001455 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001456 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001457 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001458 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001459 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1460
1461 // Set new source with adaptation still enabled.
1462 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001463 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001464 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001465
1466 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001467 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001468 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001469 stats = stats_proxy_->GetStats();
1470 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001471 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001472 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1473
sprangc5d62e22017-04-02 23:53:04 -07001474 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001475 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001476 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001477 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001478 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001479 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001480 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001481 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001482 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001483 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001484 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1485
sprangc5d62e22017-04-02 23:53:04 -07001486 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001487 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001488 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1489 mock_stats.input_frame_rate = 30;
1490 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001491 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001492 stats_proxy_->ResetMockStats();
1493
1494 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001495 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001496 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001497
1498 // Framerate now adapted.
1499 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001500 EXPECT_FALSE(stats.cpu_limited_resolution);
1501 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001502 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1503
1504 // Disable CPU adaptation.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001505 video_stream_encoder_->SetSource(&new_video_source,
1506 webrtc::DegradationPreference::DISABLED);
sprangc5d62e22017-04-02 23:53:04 -07001507 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001508 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001509 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001510
1511 stats = stats_proxy_->GetStats();
1512 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001513 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001514 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1515
1516 // Try to trigger overuse. Should not succeed.
1517 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001518 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001519 stats_proxy_->ResetMockStats();
1520
1521 stats = stats_proxy_->GetStats();
1522 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001523 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001524 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1525
1526 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001527 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001528 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssonfab67072017-04-04 05:51:49 -07001529 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001530 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001531 stats = stats_proxy_->GetStats();
1532 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001533 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001534 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001535
1536 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001537 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001538 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001539 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001540 stats = stats_proxy_->GetStats();
1541 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001542 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001543 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1544
1545 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001546 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001547 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001548 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001549 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001550 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001551 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001552 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001553 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001554 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001555 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1556
1557 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001558 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001559 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001560 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001561 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001562 stats = stats_proxy_->GetStats();
1563 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001564 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001565 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001566 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001567
mflodmancc3d4422017-08-03 08:27:51 -07001568 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001569}
1570
mflodmancc3d4422017-08-03 08:27:51 -07001571TEST_F(VideoStreamEncoderTest,
1572 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001573 const int kWidth = 1280;
1574 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001575 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001576
asaperssonfab67072017-04-04 05:51:49 -07001577 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001578 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001579
asaperssonfab67072017-04-04 05:51:49 -07001580 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001581 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001582
asaperssonfab67072017-04-04 05:51:49 -07001583 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001584 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001585
asaperssonfab67072017-04-04 05:51:49 -07001586 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001587 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001588
kthelgason876222f2016-11-29 01:44:11 -08001589 // Expect a scale down.
1590 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001591 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001592
asapersson02465b82017-04-10 01:12:52 -07001593 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001594 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001595 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001596 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001597
asaperssonfab67072017-04-04 05:51:49 -07001598 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001599 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001600 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001601 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001602
asaperssonfab67072017-04-04 05:51:49 -07001603 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001604 EXPECT_EQ(std::numeric_limits<int>::max(),
1605 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001606
asaperssonfab67072017-04-04 05:51:49 -07001607 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001608 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001609 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001610 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001611
asapersson02465b82017-04-10 01:12:52 -07001612 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001613 EXPECT_EQ(std::numeric_limits<int>::max(),
1614 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001615
mflodmancc3d4422017-08-03 08:27:51 -07001616 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001617}
1618
mflodmancc3d4422017-08-03 08:27:51 -07001619TEST_F(VideoStreamEncoderTest,
1620 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001621 const int kWidth = 1280;
1622 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001623 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001624
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001625 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001626 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001627 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001628 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001629
1630 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001631 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001632 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001633 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1634 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1635
1636 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001637 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001638 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001639 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1640 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1641 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1642
1643 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001644 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001645 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1646 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1647 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1648
mflodmancc3d4422017-08-03 08:27:51 -07001649 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001650}
1651
mflodmancc3d4422017-08-03 08:27:51 -07001652TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001653 const int kWidth = 1280;
1654 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001655 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001656
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001657 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001658 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001659 video_stream_encoder_->SetSource(&source,
1660 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001661 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1662 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001663 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001664
1665 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001666 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001667 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1668 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1669 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1670 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1671
1672 // Trigger adapt down for same input resolution, expect no change.
1673 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1674 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001675 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001676 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1677 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1678 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1679
1680 // Trigger adapt down for larger input resolution, expect no change.
1681 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1682 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001683 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001684 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1685 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1686 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1687
mflodmancc3d4422017-08-03 08:27:51 -07001688 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001689}
1690
mflodmancc3d4422017-08-03 08:27:51 -07001691TEST_F(VideoStreamEncoderTest,
1692 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001693 const int kWidth = 1280;
1694 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001695 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001696
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001697 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001698 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001699 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001700 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001701
1702 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001703 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001704 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001705 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1706 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1707
1708 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001709 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001710 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001711 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1712 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1713
mflodmancc3d4422017-08-03 08:27:51 -07001714 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001715}
1716
mflodmancc3d4422017-08-03 08:27:51 -07001717TEST_F(VideoStreamEncoderTest,
1718 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001719 const int kWidth = 1280;
1720 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001721 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001722
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001723 // Enable MAINTAIN_RESOLUTION preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001724 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001725 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001726 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
asapersson02465b82017-04-10 01:12:52 -07001727
1728 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001729 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001730 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001731 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001732 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1733
1734 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001735 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001736 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001737 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001738 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1739
mflodmancc3d4422017-08-03 08:27:51 -07001740 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001741}
1742
mflodmancc3d4422017-08-03 08:27:51 -07001743TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001744 const int kWidth = 1280;
1745 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001746 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001747
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001748 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001749 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001750 video_stream_encoder_->SetSource(&source,
1751 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001752
1753 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1754 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001755 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001756 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1757 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1758 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1759
1760 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001761 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001762 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001763 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1764 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1765 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1766
mflodmancc3d4422017-08-03 08:27:51 -07001767 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001768}
1769
mflodmancc3d4422017-08-03 08:27:51 -07001770TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001771 const int kWidth = 1280;
1772 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001773 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001774
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001775 // Enable DISABLED preference, no initial limitation.
asapersson09f05612017-05-15 23:40:18 -07001776 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001777 video_stream_encoder_->SetSource(&source,
1778 webrtc::DegradationPreference::DISABLED);
asapersson09f05612017-05-15 23:40:18 -07001779
1780 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1781 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001782 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001783 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1784 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1785 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1786
1787 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001788 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001789 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001790 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1791 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1792 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1793
mflodmancc3d4422017-08-03 08:27:51 -07001794 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001795}
1796
mflodmancc3d4422017-08-03 08:27:51 -07001797TEST_F(VideoStreamEncoderTest,
1798 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001799 const int kWidth = 1280;
1800 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001801 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001802
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001803 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001804 AdaptingFrameForwarder source;
1805 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001806 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001807 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001808
1809 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001810 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001811 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001812 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1813 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1814
1815 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001816 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001817 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001818 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001819 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001820 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1821 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1822
1823 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001824 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001825 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001826 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1827 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1828 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1829
mflodmancc3d4422017-08-03 08:27:51 -07001830 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001831}
1832
mflodmancc3d4422017-08-03 08:27:51 -07001833TEST_F(VideoStreamEncoderTest,
1834 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001835 const int kWidth = 1280;
1836 const int kHeight = 720;
1837 const int kInputFps = 30;
mflodmancc3d4422017-08-03 08:27:51 -07001838 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001839
1840 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1841 stats.input_frame_rate = kInputFps;
1842 stats_proxy_->SetMockStats(stats);
1843
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001844 // Expect no scaling to begin with (preference: MAINTAIN_FRAMERATE).
asapersson09f05612017-05-15 23:40:18 -07001845 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1846 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001847 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001848
1849 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001850 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001851 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1852 sink_.WaitForEncodedFrame(2);
1853 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1854
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001855 // Enable MAINTAIN_RESOLUTION preference.
asapersson09f05612017-05-15 23:40:18 -07001856 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001857 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001858 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001859 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001860
1861 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001862 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001863 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1864 sink_.WaitForEncodedFrame(3);
1865 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1866
1867 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001868 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001869 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001870
mflodmancc3d4422017-08-03 08:27:51 -07001871 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001872}
1873
mflodmancc3d4422017-08-03 08:27:51 -07001874TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001875 const int kWidth = 1280;
1876 const int kHeight = 720;
1877 const size_t kNumFrames = 10;
1878
mflodmancc3d4422017-08-03 08:27:51 -07001879 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001880
asaperssond0de2952017-04-21 01:47:31 -07001881 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001882 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001883 video_source_.set_adaptation_enabled(true);
1884
1885 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1886 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1887
1888 int downscales = 0;
1889 for (size_t i = 1; i <= kNumFrames; i++) {
Åsa Persson8c1bf952018-09-13 10:42:19 +02001890 video_source_.IncomingCapturedFrame(
1891 CreateFrame(i * kFrameIntervalMs, kWidth, kHeight));
1892 WaitForEncodedFrame(i * kFrameIntervalMs);
asaperssond0de2952017-04-21 01:47:31 -07001893
asaperssonfab67072017-04-04 05:51:49 -07001894 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001895 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001896 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001897 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001898
1899 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1900 ++downscales;
1901
1902 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1903 EXPECT_EQ(downscales,
1904 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1905 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001906 }
mflodmancc3d4422017-08-03 08:27:51 -07001907 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001908}
1909
mflodmancc3d4422017-08-03 08:27:51 -07001910TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001911 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1912 const int kWidth = 1280;
1913 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001914 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001915
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001916 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001917 AdaptingFrameForwarder source;
1918 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001919 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001920 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001921
Åsa Persson8c1bf952018-09-13 10:42:19 +02001922 int64_t timestamp_ms = kFrameIntervalMs;
1923 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001924 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001925 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001926 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1927 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1928
1929 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001930 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001931 timestamp_ms += kFrameIntervalMs;
1932 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1933 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001934 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001935 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1936 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1937
1938 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001939 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001940 timestamp_ms += kFrameIntervalMs;
1941 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001942 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001943 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001944 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1945 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1946
1947 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001948 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001949 timestamp_ms += kFrameIntervalMs;
1950 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1951 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001952 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001953 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1954 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1955
1956 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001957 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001958 timestamp_ms += kFrameIntervalMs;
1959 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asapersson09f05612017-05-15 23:40:18 -07001960 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001961 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001962 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1963 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1964
mflodmancc3d4422017-08-03 08:27:51 -07001965 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001966}
1967
mflodmancc3d4422017-08-03 08:27:51 -07001968TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07001969 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
1970 const int kWidth = 1280;
1971 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001972 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001973
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001974 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001975 AdaptingFrameForwarder source;
1976 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001977 video_stream_encoder_->SetSource(&source,
1978 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001979
Åsa Persson8c1bf952018-09-13 10:42:19 +02001980 int64_t timestamp_ms = kFrameIntervalMs;
1981 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001982 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001983 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001984 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1985 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1986
1987 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001988 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001989 timestamp_ms += kFrameIntervalMs;
1990 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1991 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07001992 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1993 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1994 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1995
1996 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001997 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001998 timestamp_ms += kFrameIntervalMs;
1999 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07002000 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002001 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002002 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2003 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2004
2005 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002006 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002007 timestamp_ms += kFrameIntervalMs;
2008 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2009 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002010 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2011 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2012 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2013
2014 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002015 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002016 timestamp_ms += kFrameIntervalMs;
2017 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07002018 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002019 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002020 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2021 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2022
mflodmancc3d4422017-08-03 08:27:51 -07002023 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002024}
2025
mflodmancc3d4422017-08-03 08:27:51 -07002026TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002027 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
2028 const int kWidth = 1280;
2029 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07002030 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002031
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002032 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002033 AdaptingFrameForwarder source;
2034 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002035 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002036 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002037
Åsa Persson8c1bf952018-09-13 10:42:19 +02002038 int64_t 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_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2044 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2045 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2046
2047 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002048 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002049 timestamp_ms += kFrameIntervalMs;
2050 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2051 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002052 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002053 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2054 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2055 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2056 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2057
2058 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07002059 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002060 timestamp_ms += kFrameIntervalMs;
2061 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2062 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002063 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002064 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2065 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2066 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2067 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2068
Jonathan Yubc771b72017-12-08 17:04:29 -08002069 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002070 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002071 timestamp_ms += kFrameIntervalMs;
2072 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2073 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002074 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002075 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2076 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002077 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002078 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2079
Jonathan Yubc771b72017-12-08 17:04:29 -08002080 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07002081 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002082 timestamp_ms += kFrameIntervalMs;
2083 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2084 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002085 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002086 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07002087 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2088 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2089 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2090 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2091
Jonathan Yubc771b72017-12-08 17:04:29 -08002092 // Trigger quality adapt down, expect no change (min resolution reached).
2093 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002094 timestamp_ms += kFrameIntervalMs;
2095 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2096 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002097 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
2098 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2099 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2100 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2101 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2102
2103 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002104 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002105 timestamp_ms += kFrameIntervalMs;
2106 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2107 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002108 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002109 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2110 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2111 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2112 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2113
2114 // Trigger cpu adapt up, expect upscaled resolution (640x360).
2115 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002116 timestamp_ms += kFrameIntervalMs;
2117 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2118 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002119 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2120 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2121 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2122 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2123 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2124
2125 // Trigger cpu adapt up, expect upscaled resolution (960x540).
2126 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002127 timestamp_ms += kFrameIntervalMs;
2128 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2129 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002130 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002131 last_wants = source.sink_wants();
2132 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2133 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002134 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002135 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2136
2137 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002138 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002139 timestamp_ms += kFrameIntervalMs;
2140 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2141 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002142 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002143 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2144 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002145 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002146 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2147
2148 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002149 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002150 timestamp_ms += kFrameIntervalMs;
2151 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002152 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002153 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002154 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002155 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2156 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002157 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002158 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002159
mflodmancc3d4422017-08-03 08:27:51 -07002160 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002161}
2162
mflodmancc3d4422017-08-03 08:27:51 -07002163TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002164 const int kWidth = 640;
2165 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002166
mflodmancc3d4422017-08-03 08:27:51 -07002167 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002168
perkj803d97f2016-11-01 11:45:46 -07002169 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002170 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002171 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002172 }
2173
mflodmancc3d4422017-08-03 08:27:51 -07002174 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002175 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002176 video_source_.IncomingCapturedFrame(CreateFrame(
2177 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002178 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002179 }
2180
mflodmancc3d4422017-08-03 08:27:51 -07002181 video_stream_encoder_->Stop();
2182 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002183 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002184
perkj803d97f2016-11-01 11:45:46 -07002185 EXPECT_EQ(1,
2186 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2187 EXPECT_EQ(
2188 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2189}
2190
mflodmancc3d4422017-08-03 08:27:51 -07002191TEST_F(VideoStreamEncoderTest,
2192 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2193 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002194 const int kWidth = 640;
2195 const int kHeight = 360;
2196
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002197 video_stream_encoder_->SetSource(&video_source_,
2198 webrtc::DegradationPreference::DISABLED);
asaperssonf4e44af2017-04-19 02:01:06 -07002199
2200 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2201 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002202 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002203 }
2204
mflodmancc3d4422017-08-03 08:27:51 -07002205 video_stream_encoder_->Stop();
2206 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002207 stats_proxy_.reset();
2208
2209 EXPECT_EQ(0,
2210 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2211}
2212
mflodmancc3d4422017-08-03 08:27:51 -07002213TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002214 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02002215 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002216
2217 const int kDefaultFps = 30;
Erik Språng566124a2018-04-23 12:32:22 +02002218 const VideoBitrateAllocation expected_bitrate =
sprang57c2fff2017-01-16 06:24:02 -08002219 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002220 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002221
sprang57c2fff2017-01-16 06:24:02 -08002222 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
Niels Möller6bb5ab92019-01-11 11:11:10 +01002223 .Times(1);
mflodmancc3d4422017-08-03 08:27:51 -07002224 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002225
sprang57c2fff2017-01-16 06:24:02 -08002226 video_source_.IncomingCapturedFrame(
Erik Språngd7329ca2019-02-21 21:19:53 +01002227 CreateFrame(rtc::TimeMillis(), codec_width_, codec_height_));
2228 WaitForEncodedFrame(rtc::TimeMillis());
2229 absl::optional<VideoBitrateAllocation> bitrate_allocation =
2230 fake_encoder_.GetAndResetLastBitrateAllocation();
2231 // Check that encoder has been updated too, not just allocation observer.
2232 EXPECT_EQ(bitrate_allocation->get_sum_bps(), kLowTargetBitrateBps);
2233 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec / kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002234
2235 // Not called on second frame.
2236 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2237 .Times(0);
2238 video_source_.IncomingCapturedFrame(
Erik Språngd7329ca2019-02-21 21:19:53 +01002239 CreateFrame(rtc::TimeMillis(), codec_width_, codec_height_));
2240 WaitForEncodedFrame(rtc::TimeMillis());
2241 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec / kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002242
2243 // Called after a process interval.
2244 const int64_t kProcessIntervalMs =
2245 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang57c2fff2017-01-16 06:24:02 -08002246 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2247 .Times(1);
Erik Språngd7329ca2019-02-21 21:19:53 +01002248 const int64_t start_time_ms = rtc::TimeMillis();
2249 while (rtc::TimeMillis() - start_time_ms < kProcessIntervalMs) {
2250 video_source_.IncomingCapturedFrame(
2251 CreateFrame(rtc::TimeMillis(), codec_width_, codec_height_));
2252 WaitForEncodedFrame(rtc::TimeMillis());
2253 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec / kDefaultFps);
2254 }
2255
2256 // Since rates are unchanged, encoder should not be reconfigured.
2257 EXPECT_FALSE(fake_encoder_.GetAndResetLastBitrateAllocation().has_value());
sprang57c2fff2017-01-16 06:24:02 -08002258
mflodmancc3d4422017-08-03 08:27:51 -07002259 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002260}
2261
Niels Möller7dc26b72017-12-06 10:27:48 +01002262TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2263 const int kFrameWidth = 1280;
2264 const int kFrameHeight = 720;
2265 const int kFramerate = 24;
2266
2267 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2268 test::FrameForwarder source;
2269 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002270 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002271
2272 // Insert a single frame, triggering initial configuration.
2273 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2274 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2275
2276 EXPECT_EQ(
2277 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2278 kDefaultFramerate);
2279
2280 // Trigger reconfigure encoder (without resetting the entire instance).
2281 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002282 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002283 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2284 video_encoder_config.number_of_streams = 1;
2285 video_encoder_config.video_stream_factory =
2286 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2287 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002288 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002289 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2290
2291 // Detector should be updated with fps limit from codec config.
2292 EXPECT_EQ(
2293 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2294 kFramerate);
2295
2296 // Trigger overuse, max framerate should be reduced.
2297 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2298 stats.input_frame_rate = kFramerate;
2299 stats_proxy_->SetMockStats(stats);
2300 video_stream_encoder_->TriggerCpuOveruse();
2301 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2302 int adapted_framerate =
2303 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2304 EXPECT_LT(adapted_framerate, kFramerate);
2305
2306 // Trigger underuse, max framerate should go back to codec configured fps.
2307 // Set extra low fps, to make sure it's actually reset, not just incremented.
2308 stats = stats_proxy_->GetStats();
2309 stats.input_frame_rate = adapted_framerate / 2;
2310 stats_proxy_->SetMockStats(stats);
2311 video_stream_encoder_->TriggerCpuNormalUsage();
2312 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2313 EXPECT_EQ(
2314 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2315 kFramerate);
2316
2317 video_stream_encoder_->Stop();
2318}
2319
2320TEST_F(VideoStreamEncoderTest,
2321 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2322 const int kFrameWidth = 1280;
2323 const int kFrameHeight = 720;
2324 const int kLowFramerate = 15;
2325 const int kHighFramerate = 25;
2326
2327 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2328 test::FrameForwarder source;
2329 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002330 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002331
2332 // Trigger initial configuration.
2333 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002334 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002335 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2336 video_encoder_config.number_of_streams = 1;
2337 video_encoder_config.video_stream_factory =
2338 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2339 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2340 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002341 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002342 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2343
2344 EXPECT_EQ(
2345 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2346 kLowFramerate);
2347
2348 // Trigger overuse, max framerate should be reduced.
2349 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2350 stats.input_frame_rate = kLowFramerate;
2351 stats_proxy_->SetMockStats(stats);
2352 video_stream_encoder_->TriggerCpuOveruse();
2353 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2354 int adapted_framerate =
2355 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2356 EXPECT_LT(adapted_framerate, kLowFramerate);
2357
2358 // Reconfigure the encoder with a new (higher max framerate), max fps should
2359 // still respect the adaptation.
2360 video_encoder_config.video_stream_factory =
2361 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2362 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2363 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002364 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002365 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2366
2367 EXPECT_EQ(
2368 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2369 adapted_framerate);
2370
2371 // Trigger underuse, max framerate should go back to codec configured fps.
2372 stats = stats_proxy_->GetStats();
2373 stats.input_frame_rate = adapted_framerate;
2374 stats_proxy_->SetMockStats(stats);
2375 video_stream_encoder_->TriggerCpuNormalUsage();
2376 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2377 EXPECT_EQ(
2378 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2379 kHighFramerate);
2380
2381 video_stream_encoder_->Stop();
2382}
2383
mflodmancc3d4422017-08-03 08:27:51 -07002384TEST_F(VideoStreamEncoderTest,
2385 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002386 const int kFrameWidth = 1280;
2387 const int kFrameHeight = 720;
2388 const int kFramerate = 24;
2389
mflodmancc3d4422017-08-03 08:27:51 -07002390 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002391 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002392 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002393 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangfda496a2017-06-15 04:21:07 -07002394
2395 // Trigger initial configuration.
2396 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002397 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002398 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2399 video_encoder_config.number_of_streams = 1;
2400 video_encoder_config.video_stream_factory =
2401 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2402 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002403 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002404 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002405 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002406
Niels Möller7dc26b72017-12-06 10:27:48 +01002407 EXPECT_EQ(
2408 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2409 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002410
2411 // Trigger overuse, max framerate should be reduced.
2412 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2413 stats.input_frame_rate = kFramerate;
2414 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002415 video_stream_encoder_->TriggerCpuOveruse();
2416 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002417 int adapted_framerate =
2418 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002419 EXPECT_LT(adapted_framerate, kFramerate);
2420
2421 // Change degradation preference to not enable framerate scaling. Target
2422 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002423 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002424 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -07002425 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002426 EXPECT_EQ(
2427 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2428 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002429
mflodmancc3d4422017-08-03 08:27:51 -07002430 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002431}
2432
mflodmancc3d4422017-08-03 08:27:51 -07002433TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002434 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002435 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002436 const int kWidth = 640;
2437 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002438
asaperssonfab67072017-04-04 05:51:49 -07002439 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002440
2441 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002442 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002443
2444 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002445 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002446
sprangc5d62e22017-04-02 23:53:04 -07002447 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002448
asaperssonfab67072017-04-04 05:51:49 -07002449 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002450 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002451 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002452
2453 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002454 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002455
sprangc5d62e22017-04-02 23:53:04 -07002456 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002457
mflodmancc3d4422017-08-03 08:27:51 -07002458 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002459}
2460
mflodmancc3d4422017-08-03 08:27:51 -07002461TEST_F(VideoStreamEncoderTest,
2462 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002463 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002464 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002465 const int kWidth = 640;
2466 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002467
2468 // We expect the n initial frames to get dropped.
2469 int i;
2470 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002471 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002472 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002473 }
2474 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002475 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002476 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002477
2478 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002479 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002480
mflodmancc3d4422017-08-03 08:27:51 -07002481 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002482}
2483
mflodmancc3d4422017-08-03 08:27:51 -07002484TEST_F(VideoStreamEncoderTest,
2485 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002486 const int kWidth = 640;
2487 const int kHeight = 360;
mflodmancc3d4422017-08-03 08:27:51 -07002488 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002489
2490 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002491 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002492 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason2bc68642017-02-07 07:02:22 -08002493
asaperssonfab67072017-04-04 05:51:49 -07002494 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002495 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002496 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002497
mflodmancc3d4422017-08-03 08:27:51 -07002498 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002499}
2500
mflodmancc3d4422017-08-03 08:27:51 -07002501TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002502 const int kWidth = 640;
2503 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002504 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02002505
2506 VideoEncoderConfig video_encoder_config;
2507 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
2508 // Make format different, to force recreation of encoder.
2509 video_encoder_config.video_format.parameters["foo"] = "foo";
2510 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002511 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002512 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002513
kthelgasonb83797b2017-02-14 11:57:25 -08002514 // Force quality scaler reconfiguration by resetting the source.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002515 video_stream_encoder_->SetSource(&video_source_,
2516 webrtc::DegradationPreference::BALANCED);
kthelgasonad9010c2017-02-14 00:46:51 -08002517
asaperssonfab67072017-04-04 05:51:49 -07002518 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002519 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002520 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002521
mflodmancc3d4422017-08-03 08:27:51 -07002522 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002523 fake_encoder_.SetQualityScaling(true);
2524}
2525
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002526TEST_F(VideoStreamEncoderTest, InitialFrameDropActivatesWhenBWEstimateReady) {
2527 webrtc::test::ScopedFieldTrials field_trials(
2528 "WebRTC-InitialFramedrop/Enabled/");
2529 // Reset encoder for field trials to take effect.
2530 ConfigureEncoder(video_encoder_config_.Copy());
2531 const int kTooLowBitrateForFrameSizeBps = 10000;
2532 const int kWidth = 640;
2533 const int kHeight = 360;
2534
2535 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2536 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2537 // Frame should not be dropped.
2538 WaitForEncodedFrame(1);
2539
2540 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
2541 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
2542 // Expect to drop this frame, the wait should time out.
2543 ExpectDroppedFrame();
2544
2545 // Expect the sink_wants to specify a scaled frame.
2546 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
2547 video_stream_encoder_->Stop();
2548}
2549
mflodmancc3d4422017-08-03 08:27:51 -07002550TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002551 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2552 const int kTooSmallWidth = 10;
2553 const int kTooSmallHeight = 10;
mflodmancc3d4422017-08-03 08:27:51 -07002554 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002555
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002556 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002557 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002558 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002559 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002560 VerifyNoLimitation(source.sink_wants());
2561 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2562
2563 // Trigger adapt down, too small frame, expect no change.
2564 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002565 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002566 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002567 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002568 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2569 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2570
mflodmancc3d4422017-08-03 08:27:51 -07002571 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002572}
2573
mflodmancc3d4422017-08-03 08:27:51 -07002574TEST_F(VideoStreamEncoderTest,
2575 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002576 const int kTooSmallWidth = 10;
2577 const int kTooSmallHeight = 10;
2578 const int kFpsLimit = 7;
mflodmancc3d4422017-08-03 08:27:51 -07002579 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002580
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002581 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002582 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002583 video_stream_encoder_->SetSource(&source,
2584 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002585 VerifyNoLimitation(source.sink_wants());
2586 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2587 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2588
2589 // Trigger adapt down, expect limited framerate.
2590 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002591 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002592 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002593 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2594 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2595 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2596 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2597
2598 // Trigger adapt down, too small frame, expect no change.
2599 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002600 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002601 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002602 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2603 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2604 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2605 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2606
mflodmancc3d4422017-08-03 08:27:51 -07002607 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002608}
2609
mflodmancc3d4422017-08-03 08:27:51 -07002610TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002611 fake_encoder_.ForceInitEncodeFailure(true);
mflodmancc3d4422017-08-03 08:27:51 -07002612 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Niels Möllerf1338562018-04-26 09:51:47 +02002613 ResetEncoder("VP8", 2, 1, 1, false);
asapersson02465b82017-04-10 01:12:52 -07002614 const int kFrameWidth = 1280;
2615 const int kFrameHeight = 720;
2616 video_source_.IncomingCapturedFrame(
2617 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002618 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002619 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002620}
2621
sprangb1ca0732017-02-01 08:38:12 -08002622// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002623TEST_F(VideoStreamEncoderTest,
2624 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
2625 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002626
2627 const int kFrameWidth = 1280;
2628 const int kFrameHeight = 720;
2629 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002630 // requested by
2631 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002632 video_source_.set_adaptation_enabled(true);
2633
2634 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002635 CreateFrame(1 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002636 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002637
2638 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002639 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002640 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002641 CreateFrame(2 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002642 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002643
asaperssonfab67072017-04-04 05:51:49 -07002644 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002645 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002646 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002647 CreateFrame(3 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002648 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002649
mflodmancc3d4422017-08-03 08:27:51 -07002650 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002651}
sprangfe627f32017-03-29 08:24:59 -07002652
mflodmancc3d4422017-08-03 08:27:51 -07002653TEST_F(VideoStreamEncoderTest,
2654 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002655 const int kFrameWidth = 1280;
2656 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07002657
mflodmancc3d4422017-08-03 08:27:51 -07002658 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2659 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002660 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002661 video_source_.set_adaptation_enabled(true);
2662
sprang4847ae62017-06-27 07:06:52 -07002663 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002664
2665 video_source_.IncomingCapturedFrame(
2666 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002667 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002668
2669 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002670 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002671
2672 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002673 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002674 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002675 video_source_.IncomingCapturedFrame(
2676 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002677 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002678 }
2679
2680 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002681 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002682 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002683 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002684 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002685 video_source_.IncomingCapturedFrame(
2686 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002687 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002688 ++num_frames_dropped;
2689 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002690 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002691 }
2692 }
2693
sprang4847ae62017-06-27 07:06:52 -07002694 // Add some slack to account for frames dropped by the frame dropper.
2695 const int kErrorMargin = 1;
2696 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002697 kErrorMargin);
2698
2699 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002700 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002701 num_frames_dropped = 0;
Åsa Persson8c1bf952018-09-13 10:42:19 +02002702 for (int i = 0; i <= max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002703 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002704 video_source_.IncomingCapturedFrame(
2705 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002706 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002707 ++num_frames_dropped;
2708 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002709 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002710 }
2711 }
sprang4847ae62017-06-27 07:06:52 -07002712 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002713 kErrorMargin);
2714
2715 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002716 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002717 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002718 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002719 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002720 video_source_.IncomingCapturedFrame(
2721 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002722 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002723 ++num_frames_dropped;
2724 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002725 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002726 }
2727 }
sprang4847ae62017-06-27 07:06:52 -07002728 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002729 kErrorMargin);
2730
2731 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002732 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002733 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002734 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002735 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002736 video_source_.IncomingCapturedFrame(
2737 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002738 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002739 ++num_frames_dropped;
2740 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002741 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002742 }
2743 }
2744 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2745
mflodmancc3d4422017-08-03 08:27:51 -07002746 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002747}
2748
mflodmancc3d4422017-08-03 08:27:51 -07002749TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002750 const int kFramerateFps = 5;
2751 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002752 const int kFrameWidth = 1280;
2753 const int kFrameHeight = 720;
2754
sprang4847ae62017-06-27 07:06:52 -07002755 // Reconfigure encoder with two temporal layers and screensharing, which will
2756 // disable frame dropping and make testing easier.
Niels Möllerf1338562018-04-26 09:51:47 +02002757 ResetEncoder("VP8", 1, 2, 1, true);
sprang4847ae62017-06-27 07:06:52 -07002758
mflodmancc3d4422017-08-03 08:27:51 -07002759 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2760 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002761 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002762 video_source_.set_adaptation_enabled(true);
2763
sprang4847ae62017-06-27 07:06:52 -07002764 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002765
2766 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08002767 rtc::VideoSinkWants last_wants;
2768 do {
2769 last_wants = video_source_.sink_wants();
2770
sprangc5d62e22017-04-02 23:53:04 -07002771 // Insert frames to get a new fps estimate...
2772 for (int j = 0; j < kFramerateFps; ++j) {
2773 video_source_.IncomingCapturedFrame(
2774 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08002775 if (video_source_.last_sent_width()) {
2776 sink_.WaitForEncodedFrame(timestamp_ms);
2777 }
sprangc5d62e22017-04-02 23:53:04 -07002778 timestamp_ms += kFrameIntervalMs;
Yves Gerey665174f2018-06-19 15:03:05 +02002779 fake_clock_.AdvanceTimeMicros(kFrameIntervalMs *
2780 rtc::kNumMicrosecsPerMillisec);
sprangc5d62e22017-04-02 23:53:04 -07002781 }
2782 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002783 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08002784 } while (video_source_.sink_wants().max_framerate_fps <
2785 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07002786
Jonathan Yubc771b72017-12-08 17:04:29 -08002787 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07002788
mflodmancc3d4422017-08-03 08:27:51 -07002789 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002790}
asaperssonf7e294d2017-06-13 23:25:22 -07002791
mflodmancc3d4422017-08-03 08:27:51 -07002792TEST_F(VideoStreamEncoderTest,
2793 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002794 const int kWidth = 1280;
2795 const int kHeight = 720;
2796 const int64_t kFrameIntervalMs = 150;
2797 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002798 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002799
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002800 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002801 AdaptingFrameForwarder source;
2802 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002803 video_stream_encoder_->SetSource(&source,
2804 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002805 timestamp_ms += kFrameIntervalMs;
2806 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002807 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002808 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002809 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2810 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2811 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2812
2813 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002814 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002815 timestamp_ms += kFrameIntervalMs;
2816 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002817 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002818 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2819 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2820 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2821 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2822
2823 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002824 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002825 timestamp_ms += kFrameIntervalMs;
2826 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002827 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002828 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2829 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2830 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2831 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2832
2833 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002834 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002835 timestamp_ms += kFrameIntervalMs;
2836 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002837 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002838 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2839 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2840 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2841 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2842
2843 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002844 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002845 timestamp_ms += kFrameIntervalMs;
2846 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002847 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002848 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2849 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2850 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2851 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2852
2853 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002854 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002855 timestamp_ms += kFrameIntervalMs;
2856 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002857 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002858 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2859 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2860 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2861 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2862
2863 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002864 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002865 timestamp_ms += kFrameIntervalMs;
2866 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002867 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002868 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2869 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2870 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2871 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2872
2873 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002874 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002875 timestamp_ms += kFrameIntervalMs;
2876 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002877 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002878 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2879 rtc::VideoSinkWants last_wants = source.sink_wants();
2880 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2881 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2882 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2883
2884 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002885 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002886 timestamp_ms += kFrameIntervalMs;
2887 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002888 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002889 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2890 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2891 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2892 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2893
2894 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002895 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002896 timestamp_ms += kFrameIntervalMs;
2897 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002898 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002899 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2900 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2901 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2902 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2903
2904 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002905 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002906 timestamp_ms += kFrameIntervalMs;
2907 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002908 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002909 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2910 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2911 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2912 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2913
2914 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002915 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002916 timestamp_ms += kFrameIntervalMs;
2917 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002918 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002919 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2920 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2921 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2922 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2923
2924 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002925 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002926 timestamp_ms += kFrameIntervalMs;
2927 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002928 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002929 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2930 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2931 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2932 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2933
2934 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002935 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002936 timestamp_ms += kFrameIntervalMs;
2937 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002938 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002939 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2940 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2941 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2942 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2943
2944 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002945 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002946 timestamp_ms += kFrameIntervalMs;
2947 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002948 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002949 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2950 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2951 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2952 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2953
2954 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002955 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002956 timestamp_ms += kFrameIntervalMs;
2957 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002958 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002959 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002960 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002961 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2962 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2963 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2964
2965 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002966 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002967 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002968 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2969
mflodmancc3d4422017-08-03 08:27:51 -07002970 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002971}
2972
mflodmancc3d4422017-08-03 08:27:51 -07002973TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07002974 const int kWidth = 1280;
2975 const int kHeight = 720;
2976 const int64_t kFrameIntervalMs = 150;
2977 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002978 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002979
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002980 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002981 AdaptingFrameForwarder source;
2982 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002983 video_stream_encoder_->SetSource(&source,
2984 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002985 timestamp_ms += kFrameIntervalMs;
2986 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002987 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002988 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002989 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2990 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2991 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2992 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2993 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2994 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2995
2996 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002997 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002998 timestamp_ms += kFrameIntervalMs;
2999 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003000 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003001 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
3002 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3003 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3004 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3005 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3006 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3007 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3008
3009 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003010 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003011 timestamp_ms += kFrameIntervalMs;
3012 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003013 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003014 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
3015 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3016 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3017 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3018 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3019 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3020 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3021
3022 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003023 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003024 timestamp_ms += kFrameIntervalMs;
3025 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003026 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003027 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
3028 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3029 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3030 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3031 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3032 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3033 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3034
3035 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003036 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003037 timestamp_ms += kFrameIntervalMs;
3038 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003039 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003040 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
3041 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3042 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3043 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3044 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3045 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3046 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3047
3048 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003049 video_stream_encoder_->TriggerQualityHigh();
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 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3054 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3055 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3056 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3057 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3058 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3059 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3060
3061 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003062 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003063 timestamp_ms += kFrameIntervalMs;
3064 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003065 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003066 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02003067 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003068 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3069 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3070 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3071 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3072 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3073 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3074
3075 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003076 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003077 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003078 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3079 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3080
mflodmancc3d4422017-08-03 08:27:51 -07003081 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003082}
3083
mflodmancc3d4422017-08-03 08:27:51 -07003084TEST_F(VideoStreamEncoderTest,
3085 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07003086 const int kWidth = 640;
3087 const int kHeight = 360;
3088 const int kFpsLimit = 15;
3089 const int64_t kFrameIntervalMs = 150;
3090 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07003091 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07003092
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003093 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07003094 AdaptingFrameForwarder source;
3095 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003096 video_stream_encoder_->SetSource(&source,
3097 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07003098 timestamp_ms += kFrameIntervalMs;
3099 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003100 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003101 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003102 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3103 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3104 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3105 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3106 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3107 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3108
3109 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003110 video_stream_encoder_->TriggerCpuOveruse();
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 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
3115 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3116 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3117 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3118 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3119 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3120 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3121
3122 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003123 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003124 timestamp_ms += kFrameIntervalMs;
3125 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003126 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003127 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
3128 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3129 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3130 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3131 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3132 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3133 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3134
3135 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003136 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003137 timestamp_ms += kFrameIntervalMs;
3138 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003139 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003140 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3141 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3142 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3143 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3144 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3145 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3146 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3147
3148 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003149 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003150 timestamp_ms += kFrameIntervalMs;
3151 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003152 WaitForEncodedFrame(timestamp_ms);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003153 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003154 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3155 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3156 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3157 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3158 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3159 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3160
3161 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003162 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003163 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003164 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3165 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3166
mflodmancc3d4422017-08-03 08:27:51 -07003167 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003168}
3169
mflodmancc3d4422017-08-03 08:27:51 -07003170TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003171 // Simulates simulcast behavior and makes highest stream resolutions divisible
3172 // by 4.
3173 class CroppingVideoStreamFactory
3174 : public VideoEncoderConfig::VideoStreamFactoryInterface {
3175 public:
3176 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
3177 int framerate)
3178 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
3179 EXPECT_GT(num_temporal_layers, 0u);
3180 EXPECT_GT(framerate, 0);
3181 }
3182
3183 private:
3184 std::vector<VideoStream> CreateEncoderStreams(
3185 int width,
3186 int height,
3187 const VideoEncoderConfig& encoder_config) override {
Yves Gerey665174f2018-06-19 15:03:05 +02003188 std::vector<VideoStream> streams = test::CreateVideoStreams(
3189 width - width % 4, height - height % 4, encoder_config);
ilnik6b826ef2017-06-16 06:53:48 -07003190 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +01003191 stream.num_temporal_layers = num_temporal_layers_;
ilnik6b826ef2017-06-16 06:53:48 -07003192 stream.max_framerate = framerate_;
3193 }
3194 return streams;
3195 }
3196
3197 const size_t num_temporal_layers_;
3198 const int framerate_;
3199 };
3200
3201 const int kFrameWidth = 1920;
3202 const int kFrameHeight = 1080;
3203 // 3/4 of 1920.
3204 const int kAdaptedFrameWidth = 1440;
3205 // 3/4 of 1080 rounded down to multiple of 4.
3206 const int kAdaptedFrameHeight = 808;
3207 const int kFramerate = 24;
3208
mflodmancc3d4422017-08-03 08:27:51 -07003209 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003210 // Trigger reconfigure encoder (without resetting the entire instance).
3211 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02003212 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07003213 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3214 video_encoder_config.number_of_streams = 1;
3215 video_encoder_config.video_stream_factory =
3216 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003217 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02003218 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07003219 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003220
3221 video_source_.set_adaptation_enabled(true);
3222
3223 video_source_.IncomingCapturedFrame(
3224 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003225 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003226
3227 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003228 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003229 video_source_.IncomingCapturedFrame(
3230 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003231 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003232
mflodmancc3d4422017-08-03 08:27:51 -07003233 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003234}
3235
mflodmancc3d4422017-08-03 08:27:51 -07003236TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003237 const int kFrameWidth = 1280;
3238 const int kFrameHeight = 720;
3239 const int kLowFps = 2;
3240 const int kHighFps = 30;
3241
mflodmancc3d4422017-08-03 08:27:51 -07003242 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003243
3244 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3245 max_framerate_ = kLowFps;
3246
3247 // Insert 2 seconds of 2fps video.
3248 for (int i = 0; i < kLowFps * 2; ++i) {
3249 video_source_.IncomingCapturedFrame(
3250 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3251 WaitForEncodedFrame(timestamp_ms);
3252 timestamp_ms += 1000 / kLowFps;
3253 }
3254
3255 // Make sure encoder is updated with new target.
mflodmancc3d4422017-08-03 08:27:51 -07003256 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003257 video_source_.IncomingCapturedFrame(
3258 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3259 WaitForEncodedFrame(timestamp_ms);
3260 timestamp_ms += 1000 / kLowFps;
3261
3262 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3263
3264 // Insert 30fps frames for just a little more than the forced update period.
3265 const int kVcmTimerIntervalFrames =
3266 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3267 const int kFrameIntervalMs = 1000 / kHighFps;
3268 max_framerate_ = kHighFps;
3269 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3270 video_source_.IncomingCapturedFrame(
3271 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3272 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3273 // be dropped if the encoder hans't been updated with the new higher target
3274 // framerate yet, causing it to overshoot the target bitrate and then
3275 // suffering the wrath of the media optimizer.
3276 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3277 timestamp_ms += kFrameIntervalMs;
3278 }
3279
3280 // Don expect correct measurement just yet, but it should be higher than
3281 // before.
3282 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3283
mflodmancc3d4422017-08-03 08:27:51 -07003284 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003285}
3286
mflodmancc3d4422017-08-03 08:27:51 -07003287TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003288 const int kFrameWidth = 1280;
3289 const int kFrameHeight = 720;
3290 const int kTargetBitrateBps = 1000000;
3291
3292 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02003293 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
mflodmancc3d4422017-08-03 08:27:51 -07003294 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3295 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003296
3297 // Insert a first video frame, causes another bitrate update.
3298 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3299 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3300 video_source_.IncomingCapturedFrame(
3301 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3302 WaitForEncodedFrame(timestamp_ms);
3303
3304 // Next, simulate video suspension due to pacer queue overrun.
mflodmancc3d4422017-08-03 08:27:51 -07003305 video_stream_encoder_->OnBitrateUpdated(0, 0, 1);
sprang4847ae62017-06-27 07:06:52 -07003306
3307 // Skip ahead until a new periodic parameter update should have occured.
3308 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3309 fake_clock_.AdvanceTimeMicros(
3310 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3311 rtc::kNumMicrosecsPerMillisec);
3312
3313 // Bitrate observer should not be called.
3314 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3315 video_source_.IncomingCapturedFrame(
3316 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3317 ExpectDroppedFrame();
3318
mflodmancc3d4422017-08-03 08:27:51 -07003319 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003320}
ilnik6b826ef2017-06-16 06:53:48 -07003321
Niels Möller4db138e2018-04-19 09:04:13 +02003322TEST_F(VideoStreamEncoderTest,
3323 DefaultCpuAdaptationThresholdsForSoftwareEncoder) {
3324 const int kFrameWidth = 1280;
3325 const int kFrameHeight = 720;
3326 const CpuOveruseOptions default_options;
3327 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3328 video_source_.IncomingCapturedFrame(
3329 CreateFrame(1, kFrameWidth, kFrameHeight));
3330 WaitForEncodedFrame(1);
3331 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3332 .low_encode_usage_threshold_percent,
3333 default_options.low_encode_usage_threshold_percent);
3334 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3335 .high_encode_usage_threshold_percent,
3336 default_options.high_encode_usage_threshold_percent);
3337 video_stream_encoder_->Stop();
3338}
3339
3340TEST_F(VideoStreamEncoderTest,
3341 HigherCpuAdaptationThresholdsForHardwareEncoder) {
3342 const int kFrameWidth = 1280;
3343 const int kFrameHeight = 720;
3344 CpuOveruseOptions hardware_options;
3345 hardware_options.low_encode_usage_threshold_percent = 150;
3346 hardware_options.high_encode_usage_threshold_percent = 200;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +01003347 fake_encoder_.SetIsHardwareAccelerated(true);
Niels Möller4db138e2018-04-19 09:04:13 +02003348
3349 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3350 video_source_.IncomingCapturedFrame(
3351 CreateFrame(1, kFrameWidth, kFrameHeight));
3352 WaitForEncodedFrame(1);
3353 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3354 .low_encode_usage_threshold_percent,
3355 hardware_options.low_encode_usage_threshold_percent);
3356 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3357 .high_encode_usage_threshold_percent,
3358 hardware_options.high_encode_usage_threshold_percent);
3359 video_stream_encoder_->Stop();
3360}
3361
Niels Möller6bb5ab92019-01-11 11:11:10 +01003362TEST_F(VideoStreamEncoderTest, DropsFramesWhenEncoderOvershoots) {
3363 const int kFrameWidth = 320;
3364 const int kFrameHeight = 240;
3365 const int kFps = 30;
3366 const int kTargetBitrateBps = 120000;
3367 const int kNumFramesInRun = kFps * 5; // Runs of five seconds.
3368
3369 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3370
3371 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3372 max_framerate_ = kFps;
3373
3374 // Insert 3 seconds of video, verify number of drops with normal bitrate.
3375 fake_encoder_.SimulateOvershoot(1.0);
3376 int num_dropped = 0;
3377 for (int i = 0; i < kNumFramesInRun; ++i) {
3378 video_source_.IncomingCapturedFrame(
3379 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3380 // Wait up to two frame durations for a frame to arrive.
3381 if (!TimedWaitForEncodedFrame(timestamp_ms, 2 * 1000 / kFps)) {
3382 ++num_dropped;
3383 }
3384 timestamp_ms += 1000 / kFps;
3385 }
3386
Erik Språnga8d48ab2019-02-08 14:17:40 +01003387 // Framerate should be measured to be near the expected target rate.
3388 EXPECT_NEAR(fake_encoder_.GetLastFramerate(), kFps, 1);
3389
3390 // Frame drops should be within 5% of expected 0%.
3391 EXPECT_NEAR(num_dropped, 0, 5 * kNumFramesInRun / 100);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003392
3393 // Make encoder produce frames at double the expected bitrate during 3 seconds
3394 // of video, verify number of drops. Rate needs to be slightly changed in
3395 // order to force the rate to be reconfigured.
Erik Språng7ca375c2019-02-06 16:20:17 +01003396 double overshoot_factor = 2.0;
3397 if (RateControlSettings::ParseFromFieldTrials().UseEncoderBitrateAdjuster()) {
3398 // With bitrate adjuster, when need to overshoot even more to trigger
3399 // frame dropping.
3400 overshoot_factor *= 2;
3401 }
3402 fake_encoder_.SimulateOvershoot(overshoot_factor);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003403 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps + 1000, 0, 0);
3404 num_dropped = 0;
3405 for (int i = 0; i < kNumFramesInRun; ++i) {
3406 video_source_.IncomingCapturedFrame(
3407 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3408 // Wait up to two frame durations for a frame to arrive.
3409 if (!TimedWaitForEncodedFrame(timestamp_ms, 2 * 1000 / kFps)) {
3410 ++num_dropped;
3411 }
3412 timestamp_ms += 1000 / kFps;
3413 }
3414
Erik Språnga8d48ab2019-02-08 14:17:40 +01003415 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3416
3417 // Target framerate should be still be near the expected target, despite
3418 // the frame drops.
3419 EXPECT_NEAR(fake_encoder_.GetLastFramerate(), kFps, 1);
3420
3421 // Frame drops should be within 5% of expected 50%.
3422 EXPECT_NEAR(num_dropped, kNumFramesInRun / 2, 5 * kNumFramesInRun / 100);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003423
3424 video_stream_encoder_->Stop();
3425}
3426
3427TEST_F(VideoStreamEncoderTest, ConfiguresCorrectFrameRate) {
3428 const int kFrameWidth = 320;
3429 const int kFrameHeight = 240;
3430 const int kActualInputFps = 24;
3431 const int kTargetBitrateBps = 120000;
3432
3433 ASSERT_GT(max_framerate_, kActualInputFps);
3434
3435 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3436 max_framerate_ = kActualInputFps;
3437 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3438
3439 // Insert 3 seconds of video, with an input fps lower than configured max.
3440 for (int i = 0; i < kActualInputFps * 3; ++i) {
3441 video_source_.IncomingCapturedFrame(
3442 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3443 // Wait up to two frame durations for a frame to arrive.
3444 WaitForEncodedFrame(timestamp_ms);
3445 timestamp_ms += 1000 / kActualInputFps;
3446 }
3447
3448 EXPECT_NEAR(kActualInputFps, fake_encoder_.GetLastFramerate(), 1);
3449
3450 video_stream_encoder_->Stop();
3451}
3452
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01003453TEST_F(VideoStreamEncoderTest, AccumulatesUpdateRectOnDroppedFrames) {
3454 VideoFrame::UpdateRect rect;
3455 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3456
3457 fake_encoder_.BlockNextEncode();
3458 video_source_.IncomingCapturedFrame(
3459 CreateFrameWithUpdatedPixel(1, nullptr, 0));
3460 WaitForEncodedFrame(1);
3461 // On the very first frame full update should be forced.
3462 rect = fake_encoder_.GetLastUpdateRect();
3463 EXPECT_EQ(rect.offset_x, 0);
3464 EXPECT_EQ(rect.offset_y, 0);
3465 EXPECT_EQ(rect.height, codec_height_);
3466 EXPECT_EQ(rect.width, codec_width_);
3467 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
3468 // call to ContinueEncode.
3469 video_source_.IncomingCapturedFrame(
3470 CreateFrameWithUpdatedPixel(2, nullptr, 1));
3471 ExpectDroppedFrame();
3472 video_source_.IncomingCapturedFrame(
3473 CreateFrameWithUpdatedPixel(3, nullptr, 10));
3474 ExpectDroppedFrame();
3475 fake_encoder_.ContinueEncode();
3476 WaitForEncodedFrame(3);
3477 // Updates to pixels 1 and 10 should be accumulated to one 10x1 rect.
3478 rect = fake_encoder_.GetLastUpdateRect();
3479 EXPECT_EQ(rect.offset_x, 1);
3480 EXPECT_EQ(rect.offset_y, 0);
3481 EXPECT_EQ(rect.width, 10);
3482 EXPECT_EQ(rect.height, 1);
3483
3484 video_source_.IncomingCapturedFrame(
3485 CreateFrameWithUpdatedPixel(4, nullptr, 0));
3486 WaitForEncodedFrame(4);
3487 // Previous frame was encoded, so no accumulation should happen.
3488 rect = fake_encoder_.GetLastUpdateRect();
3489 EXPECT_EQ(rect.offset_x, 0);
3490 EXPECT_EQ(rect.offset_y, 0);
3491 EXPECT_EQ(rect.width, 1);
3492 EXPECT_EQ(rect.height, 1);
3493
3494 video_stream_encoder_->Stop();
3495}
3496
Erik Språngd7329ca2019-02-21 21:19:53 +01003497TEST_F(VideoStreamEncoderTest, SetsFrameTypes) {
3498 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3499
3500 // First frame is always keyframe.
3501 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
3502 WaitForEncodedFrame(1);
3503 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
3504 testing::ElementsAre(FrameType{kVideoFrameKey}));
3505
3506 // Insert delta frame.
3507 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
3508 WaitForEncodedFrame(2);
3509 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
3510 testing::ElementsAre(FrameType{kVideoFrameDelta}));
3511
3512 // Request next frame be a key-frame.
3513 video_stream_encoder_->SendKeyFrame();
3514 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
3515 WaitForEncodedFrame(3);
3516 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
3517 testing::ElementsAre(FrameType{kVideoFrameKey}));
3518
3519 video_stream_encoder_->Stop();
3520}
3521
3522TEST_F(VideoStreamEncoderTest, SetsFrameTypesSimulcast) {
3523 // Setup simulcast with three streams.
3524 ResetEncoder("VP8", 3, 1, 1, false);
3525 video_stream_encoder_->OnBitrateUpdated(kSimulcastTargetBitrateBps, 0, 0);
3526 // Wait for all three layers before triggering event.
3527 sink_.SetNumExpectedLayers(3);
3528
3529 // First frame is always keyframe.
3530 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
3531 WaitForEncodedFrame(1);
3532 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
3533 testing::ElementsAreArray(
3534 {kVideoFrameKey, kVideoFrameKey, kVideoFrameKey}));
3535
3536 // Insert delta frame.
3537 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
3538 WaitForEncodedFrame(2);
3539 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
3540 testing::ElementsAreArray(
3541 {kVideoFrameDelta, kVideoFrameDelta, kVideoFrameDelta}));
3542
3543 // Request next frame be a key-frame.
3544 // Only first stream is configured to produce key-frame.
3545 video_stream_encoder_->SendKeyFrame();
3546 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
3547 WaitForEncodedFrame(3);
3548 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
3549 testing::ElementsAreArray(
3550 {kVideoFrameKey, kVideoFrameDelta, kVideoFrameDelta}));
3551
3552 video_stream_encoder_->Stop();
3553}
3554
3555TEST_F(VideoStreamEncoderTest, RequestKeyframeInternalSource) {
3556 // Configure internal source factory and setup test again.
3557 encoder_factory_.SetHasInternalSource(true);
3558 ResetEncoder("VP8", 1, 1, 1, false);
3559 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3560
3561 // Call encoder directly, simulating internal source where encoded frame
3562 // callback in VideoStreamEncoder is called despite no OnFrame().
3563 fake_encoder_.InjectFrame(CreateFrame(1, nullptr), true);
3564 EXPECT_TRUE(WaitForFrame(kDefaultTimeoutMs));
3565 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
3566 testing::ElementsAre(FrameType{kVideoFrameKey}));
3567
3568 const std::vector<FrameType> kDeltaFrame = {kVideoFrameDelta};
3569 // Need to set timestamp manually since manually for injected frame.
3570 VideoFrame frame = CreateFrame(101, nullptr);
3571 frame.set_timestamp(101);
3572 fake_encoder_.InjectFrame(frame, false);
3573 EXPECT_TRUE(WaitForFrame(kDefaultTimeoutMs));
3574 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
3575 testing::ElementsAre(FrameType{kVideoFrameDelta}));
3576
3577 // Request key-frame. The forces a dummy frame down into the encoder.
3578 fake_encoder_.ExpectNullFrame();
3579 video_stream_encoder_->SendKeyFrame();
3580 EXPECT_TRUE(WaitForFrame(kDefaultTimeoutMs));
3581 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
3582 testing::ElementsAre(FrameType{kVideoFrameKey}));
3583
3584 video_stream_encoder_->Stop();
3585}
perkj26091b12016-09-01 01:17:40 -07003586} // namespace webrtc