blob: 278e566666bb8be910f26da0ab37f7a535cba53d [file] [log] [blame]
perkj26091b12016-09-01 01:17:40 -07001/*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Erik Språng4529fbc2018-10-12 10:30:31 +020011#include "video/video_stream_encoder.h"
12
sprangfe627f32017-03-29 08:24:59 -070013#include <algorithm>
perkj803d97f2016-11-01 11:45:46 -070014#include <limits>
Per512ecb32016-09-23 15:52:06 +020015#include <utility>
16
Sebastian Jansson74682c12019-03-01 11:50:20 +010017#include "api/task_queue/global_task_queue_factory.h"
Jiawei Ouc2ebe212018-11-08 10:02:56 -080018#include "api/video/builtin_video_bitrate_allocator_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "api/video/i420_buffer.h"
Erik Språngf93eda12019-01-16 17:10:57 +010020#include "api/video/video_bitrate_allocation.h"
Erik Språng4529fbc2018-10-12 10:30:31 +020021#include "api/video_codecs/vp8_temporal_layers.h"
Elad Aloncde8ab22019-03-20 11:56:20 +010022#include "api/video_codecs/vp8_temporal_layers_factory.h"
Steve Anton10542f22019-01-11 09:11:00 -080023#include "media/base/video_adapter.h"
Sergey Silkin86684962018-03-28 19:32:37 +020024#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
Åsa Perssonc29cb2c2019-03-25 12:06:59 +010026#include "modules/video_coding/utility/simulcast_rate_allocator.h"
Steve Anton10542f22019-01-11 09:11:00 -080027#include "rtc_base/fake_clock.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020028#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080029#include "rtc_base/ref_counted_object.h"
Erik Språng7ca375c2019-02-06 16:20:17 +010030#include "system_wrappers/include/field_trial.h"
Mirko Bonadei17f48782018-09-28 08:51:10 +020031#include "system_wrappers/include/metrics.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020032#include "system_wrappers/include/sleep.h"
33#include "test/encoder_settings.h"
34#include "test/fake_encoder.h"
Kári Tristan Helgason639602a2018-08-02 10:51:40 +020035#include "test/field_trial.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020036#include "test/frame_generator.h"
37#include "test/gmock.h"
38#include "test/gtest.h"
Niels Möllercbcbc222018-09-28 09:07:24 +020039#include "test/video_encoder_proxy_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020040#include "video/send_statistics_proxy.h"
perkj26091b12016-09-01 01:17:40 -070041
42namespace webrtc {
43
sprangb1ca0732017-02-01 08:38:12 -080044using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080045using ::testing::_;
kthelgason876222f2016-11-29 01:44:11 -080046
perkj803d97f2016-11-01 11:45:46 -070047namespace {
Åsa Persson8c1bf952018-09-13 10:42:19 +020048const int kMinPixelsPerFrame = 320 * 180;
49const int kMinFramerateFps = 2;
50const int kMinBalancedFramerateFps = 7;
51const int64_t kFrameTimeoutMs = 100;
asapersson5f7226f2016-11-25 04:37:00 -080052const size_t kMaxPayloadLength = 1440;
Erik Språngd7329ca2019-02-21 21:19:53 +010053const uint32_t kTargetBitrateBps = 1000000;
54const uint32_t kSimulcastTargetBitrateBps = 3150000;
55const uint32_t kLowTargetBitrateBps = kTargetBitrateBps / 10;
kthelgason2bc68642017-02-07 07:02:22 -080056const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070057const int kDefaultFramerate = 30;
Åsa Persson8c1bf952018-09-13 10:42:19 +020058const int64_t kFrameIntervalMs = rtc::kNumMillisecsPerSec / kDefaultFramerate;
asapersson5f7226f2016-11-25 04:37:00 -080059
perkj803d97f2016-11-01 11:45:46 -070060class TestBuffer : public webrtc::I420Buffer {
61 public:
62 TestBuffer(rtc::Event* event, int width, int height)
63 : I420Buffer(width, height), event_(event) {}
64
65 private:
66 friend class rtc::RefCountedObject<TestBuffer>;
67 ~TestBuffer() override {
68 if (event_)
69 event_->Set();
70 }
71 rtc::Event* const event_;
72};
73
Niels Möller7dc26b72017-12-06 10:27:48 +010074class CpuOveruseDetectorProxy : public OveruseFrameDetector {
75 public:
Niels Möllerd1f7eb62018-03-28 16:40:58 +020076 explicit CpuOveruseDetectorProxy(CpuOveruseMetricsObserver* metrics_observer)
77 : OveruseFrameDetector(metrics_observer),
Niels Möller7dc26b72017-12-06 10:27:48 +010078 last_target_framerate_fps_(-1) {}
79 virtual ~CpuOveruseDetectorProxy() {}
80
81 void OnTargetFramerateUpdated(int framerate_fps) override {
82 rtc::CritScope cs(&lock_);
83 last_target_framerate_fps_ = framerate_fps;
84 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
85 }
86
87 int GetLastTargetFramerate() {
88 rtc::CritScope cs(&lock_);
89 return last_target_framerate_fps_;
90 }
91
Niels Möller4db138e2018-04-19 09:04:13 +020092 CpuOveruseOptions GetOptions() { return options_; }
93
Niels Möller7dc26b72017-12-06 10:27:48 +010094 private:
95 rtc::CriticalSection lock_;
96 int last_target_framerate_fps_ RTC_GUARDED_BY(lock_);
97};
98
mflodmancc3d4422017-08-03 08:27:51 -070099class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -0700100 public:
Niels Möller213618e2018-07-24 09:29:58 +0200101 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
102 const VideoStreamEncoderSettings& settings)
Sebastian Jansson572c60f2019-03-04 18:30:41 +0100103 : VideoStreamEncoder(Clock::GetRealTimeClock(),
104 1 /* number_of_cores */,
Yves Gerey665174f2018-06-19 15:03:05 +0200105 stats_proxy,
106 settings,
Yves Gerey665174f2018-06-19 15:03:05 +0200107 std::unique_ptr<OveruseFrameDetector>(
108 overuse_detector_proxy_ =
Sebastian Jansson74682c12019-03-01 11:50:20 +0100109 new CpuOveruseDetectorProxy(stats_proxy)),
110 &GlobalTaskQueueFactory()) {}
perkj803d97f2016-11-01 11:45:46 -0700111
sprangb1ca0732017-02-01 08:38:12 -0800112 void PostTaskAndWait(bool down, AdaptReason reason) {
Niels Möllerc572ff32018-11-07 08:43:50 +0100113 rtc::Event event;
kthelgason876222f2016-11-29 01:44:11 -0800114 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800115 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700116 event.Set();
117 });
perkj070ba852017-02-16 15:46:27 -0800118 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700119 }
120
kthelgason2fc52542017-03-03 00:24:41 -0800121 // This is used as a synchronisation mechanism, to make sure that the
122 // encoder queue is not blocked before we start sending it frames.
123 void WaitUntilTaskQueueIsIdle() {
Niels Möllerc572ff32018-11-07 08:43:50 +0100124 rtc::Event event;
Yves Gerey665174f2018-06-19 15:03:05 +0200125 encoder_queue()->PostTask([&event] { event.Set(); });
kthelgason2fc52542017-03-03 00:24:41 -0800126 ASSERT_TRUE(event.Wait(5000));
127 }
128
sprangb1ca0732017-02-01 08:38:12 -0800129 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800130
sprangb1ca0732017-02-01 08:38:12 -0800131 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800132
sprangb1ca0732017-02-01 08:38:12 -0800133 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800134
sprangb1ca0732017-02-01 08:38:12 -0800135 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700136
Niels Möller7dc26b72017-12-06 10:27:48 +0100137 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700138};
139
asapersson5f7226f2016-11-25 04:37:00 -0800140class VideoStreamFactory
141 : public VideoEncoderConfig::VideoStreamFactoryInterface {
142 public:
sprangfda496a2017-06-15 04:21:07 -0700143 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
144 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800145 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700146 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800147 }
148
149 private:
150 std::vector<VideoStream> CreateEncoderStreams(
151 int width,
152 int height,
153 const VideoEncoderConfig& encoder_config) override {
154 std::vector<VideoStream> streams =
155 test::CreateVideoStreams(width, height, encoder_config);
156 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +0100157 stream.num_temporal_layers = num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700158 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800159 }
160 return streams;
161 }
sprangfda496a2017-06-15 04:21:07 -0700162
asapersson5f7226f2016-11-25 04:37:00 -0800163 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700164 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800165};
166
sprangb1ca0732017-02-01 08:38:12 -0800167class AdaptingFrameForwarder : public test::FrameForwarder {
168 public:
169 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700170 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800171
172 void set_adaptation_enabled(bool enabled) {
173 rtc::CritScope cs(&crit_);
174 adaptation_enabled_ = enabled;
175 }
176
asaperssonfab67072017-04-04 05:51:49 -0700177 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800178 rtc::CritScope cs(&crit_);
179 return adaptation_enabled_;
180 }
181
asapersson09f05612017-05-15 23:40:18 -0700182 rtc::VideoSinkWants last_wants() const {
183 rtc::CritScope cs(&crit_);
184 return last_wants_;
185 }
186
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200187 absl::optional<int> last_sent_width() const { return last_width_; }
188 absl::optional<int> last_sent_height() const { return last_height_; }
Jonathan Yubc771b72017-12-08 17:04:29 -0800189
sprangb1ca0732017-02-01 08:38:12 -0800190 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
191 int cropped_width = 0;
192 int cropped_height = 0;
193 int out_width = 0;
194 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700195 if (adaption_enabled()) {
196 if (adapter_.AdaptFrameResolution(
197 video_frame.width(), video_frame.height(),
198 video_frame.timestamp_us() * 1000, &cropped_width,
199 &cropped_height, &out_width, &out_height)) {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100200 VideoFrame adapted_frame =
201 VideoFrame::Builder()
202 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
203 nullptr, out_width, out_height))
204 .set_timestamp_rtp(99)
205 .set_timestamp_ms(99)
206 .set_rotation(kVideoRotation_0)
207 .build();
sprangc5d62e22017-04-02 23:53:04 -0700208 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
209 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800210 last_width_.emplace(adapted_frame.width());
211 last_height_.emplace(adapted_frame.height());
212 } else {
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200213 last_width_ = absl::nullopt;
214 last_height_ = absl::nullopt;
sprangc5d62e22017-04-02 23:53:04 -0700215 }
sprangb1ca0732017-02-01 08:38:12 -0800216 } else {
217 test::FrameForwarder::IncomingCapturedFrame(video_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800218 last_width_.emplace(video_frame.width());
219 last_height_.emplace(video_frame.height());
sprangb1ca0732017-02-01 08:38:12 -0800220 }
221 }
222
223 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
224 const rtc::VideoSinkWants& wants) override {
225 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700226 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700227 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
228 wants.max_pixel_count,
229 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800230 test::FrameForwarder::AddOrUpdateSink(sink, wants);
231 }
sprangb1ca0732017-02-01 08:38:12 -0800232 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700233 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
234 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200235 absl::optional<int> last_width_;
236 absl::optional<int> last_height_;
sprangb1ca0732017-02-01 08:38:12 -0800237};
sprangc5d62e22017-04-02 23:53:04 -0700238
Niels Möller213618e2018-07-24 09:29:58 +0200239// TODO(nisse): Mock only VideoStreamEncoderObserver.
sprangc5d62e22017-04-02 23:53:04 -0700240class MockableSendStatisticsProxy : public SendStatisticsProxy {
241 public:
242 MockableSendStatisticsProxy(Clock* clock,
243 const VideoSendStream::Config& config,
244 VideoEncoderConfig::ContentType content_type)
245 : SendStatisticsProxy(clock, config, content_type) {}
246
247 VideoSendStream::Stats GetStats() override {
248 rtc::CritScope cs(&lock_);
249 if (mock_stats_)
250 return *mock_stats_;
251 return SendStatisticsProxy::GetStats();
252 }
253
Niels Möller213618e2018-07-24 09:29:58 +0200254 int GetInputFrameRate() const override {
255 rtc::CritScope cs(&lock_);
256 if (mock_stats_)
257 return mock_stats_->input_frame_rate;
258 return SendStatisticsProxy::GetInputFrameRate();
259 }
sprangc5d62e22017-04-02 23:53:04 -0700260 void SetMockStats(const VideoSendStream::Stats& stats) {
261 rtc::CritScope cs(&lock_);
262 mock_stats_.emplace(stats);
263 }
264
265 void ResetMockStats() {
266 rtc::CritScope cs(&lock_);
267 mock_stats_.reset();
268 }
269
270 private:
271 rtc::CriticalSection lock_;
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200272 absl::optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700273};
274
sprang4847ae62017-06-27 07:06:52 -0700275class MockBitrateObserver : public VideoBitrateAllocationObserver {
276 public:
Erik Språng566124a2018-04-23 12:32:22 +0200277 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const VideoBitrateAllocation&));
sprang4847ae62017-06-27 07:06:52 -0700278};
279
perkj803d97f2016-11-01 11:45:46 -0700280} // namespace
281
mflodmancc3d4422017-08-03 08:27:51 -0700282class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700283 public:
284 static const int kDefaultTimeoutMs = 30 * 1000;
285
mflodmancc3d4422017-08-03 08:27:51 -0700286 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700287 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700288 codec_width_(320),
289 codec_height_(240),
Åsa Persson8c1bf952018-09-13 10:42:19 +0200290 max_framerate_(kDefaultFramerate),
perkj26091b12016-09-01 01:17:40 -0700291 fake_encoder_(),
Niels Möller4db138e2018-04-19 09:04:13 +0200292 encoder_factory_(&fake_encoder_),
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800293 bitrate_allocator_factory_(CreateBuiltinVideoBitrateAllocatorFactory()),
sprangc5d62e22017-04-02 23:53:04 -0700294 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700295 Clock::GetRealTimeClock(),
296 video_send_config_,
297 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700298 sink_(&fake_encoder_) {}
299
300 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700301 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700302 video_send_config_ = VideoSendStream::Config(nullptr);
Niels Möller4db138e2018-04-19 09:04:13 +0200303 video_send_config_.encoder_settings.encoder_factory = &encoder_factory_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800304 video_send_config_.encoder_settings.bitrate_allocator_factory =
305 bitrate_allocator_factory_.get();
Niels Möller259a4972018-04-05 15:36:51 +0200306 video_send_config_.rtp.payload_name = "FAKE";
307 video_send_config_.rtp.payload_type = 125;
perkj26091b12016-09-01 01:17:40 -0700308
Per512ecb32016-09-23 15:52:06 +0200309 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200310 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700311 video_encoder_config.video_stream_factory =
312 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100313 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700314
315 // Framerate limit is specified by the VideoStreamFactory.
316 std::vector<VideoStream> streams =
317 video_encoder_config.video_stream_factory->CreateEncoderStreams(
318 codec_width_, codec_height_, video_encoder_config);
319 max_framerate_ = streams[0].max_framerate;
320 fake_clock_.SetTimeMicros(1234);
321
Niels Möllerf1338562018-04-26 09:51:47 +0200322 ConfigureEncoder(std::move(video_encoder_config));
asapersson5f7226f2016-11-25 04:37:00 -0800323 }
324
Niels Möllerf1338562018-04-26 09:51:47 +0200325 void ConfigureEncoder(VideoEncoderConfig video_encoder_config) {
mflodmancc3d4422017-08-03 08:27:51 -0700326 if (video_stream_encoder_)
327 video_stream_encoder_->Stop();
328 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700329 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700330 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
331 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700332 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -0700333 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
334 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200335 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -0700336 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800337 }
338
339 void ResetEncoder(const std::string& payload_name,
340 size_t num_streams,
341 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700342 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700343 bool screenshare) {
Niels Möller259a4972018-04-05 15:36:51 +0200344 video_send_config_.rtp.payload_name = payload_name;
asapersson5f7226f2016-11-25 04:37:00 -0800345
346 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200347 video_encoder_config.codec_type = PayloadStringToCodecType(payload_name);
asapersson5f7226f2016-11-25 04:37:00 -0800348 video_encoder_config.number_of_streams = num_streams;
Erik Språngd7329ca2019-02-21 21:19:53 +0100349 video_encoder_config.max_bitrate_bps =
350 num_streams == 1 ? kTargetBitrateBps : kSimulcastTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800351 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700352 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
353 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700354 video_encoder_config.content_type =
355 screenshare ? VideoEncoderConfig::ContentType::kScreen
356 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700357 if (payload_name == "VP9") {
358 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
359 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
360 video_encoder_config.encoder_specific_settings =
361 new rtc::RefCountedObject<
362 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
363 }
Niels Möllerf1338562018-04-26 09:51:47 +0200364 ConfigureEncoder(std::move(video_encoder_config));
perkj26091b12016-09-01 01:17:40 -0700365 }
366
sprang57c2fff2017-01-16 06:24:02 -0800367 VideoFrame CreateFrame(int64_t ntp_time_ms,
368 rtc::Event* destruction_event) const {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100369 VideoFrame frame =
370 VideoFrame::Builder()
371 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
372 destruction_event, codec_width_, codec_height_))
373 .set_timestamp_rtp(99)
374 .set_timestamp_ms(99)
375 .set_rotation(kVideoRotation_0)
376 .build();
sprang57c2fff2017-01-16 06:24:02 -0800377 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700378 return frame;
379 }
380
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100381 VideoFrame CreateFrameWithUpdatedPixel(int64_t ntp_time_ms,
382 rtc::Event* destruction_event,
383 int offset_x) const {
384 VideoFrame frame =
385 VideoFrame::Builder()
386 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
387 destruction_event, codec_width_, codec_height_))
388 .set_timestamp_rtp(99)
389 .set_timestamp_ms(99)
390 .set_rotation(kVideoRotation_0)
391 .set_update_rect({offset_x, 0, 1, 1})
392 .build();
393 frame.set_ntp_time_ms(ntp_time_ms);
394 return frame;
395 }
396
sprang57c2fff2017-01-16 06:24:02 -0800397 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100398 VideoFrame frame =
399 VideoFrame::Builder()
400 .set_video_frame_buffer(
401 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height))
402 .set_timestamp_rtp(99)
403 .set_timestamp_ms(99)
404 .set_rotation(kVideoRotation_0)
405 .build();
sprang57c2fff2017-01-16 06:24:02 -0800406 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700407 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700408 return frame;
409 }
410
Åsa Perssonc29cb2c2019-03-25 12:06:59 +0100411 void VerifyAllocatedBitrate(const VideoBitrateAllocation& expected_bitrate) {
412 MockBitrateObserver bitrate_observer;
413 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
414
415 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
416 .Times(1);
417 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
418 DataRate::Zero(), 0, 0);
419
420 video_source_.IncomingCapturedFrame(
421 CreateFrame(1, codec_width_, codec_height_));
422 WaitForEncodedFrame(1);
423 }
424
asapersson02465b82017-04-10 01:12:52 -0700425 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700426 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700427 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
428 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700429 }
430
asapersson09f05612017-05-15 23:40:18 -0700431 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
432 const rtc::VideoSinkWants& wants2) {
433 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
434 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
435 }
436
Åsa Persson8c1bf952018-09-13 10:42:19 +0200437 void VerifyFpsMaxResolutionMax(const rtc::VideoSinkWants& wants) {
438 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
439 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
440 EXPECT_FALSE(wants.target_pixel_count);
441 }
442
asapersson09f05612017-05-15 23:40:18 -0700443 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
444 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200445 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700446 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
447 EXPECT_GT(wants1.max_pixel_count, 0);
448 }
449
450 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
451 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200452 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700453 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
454 }
455
asaperssonf7e294d2017-06-13 23:25:22 -0700456 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
457 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200458 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700459 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
460 }
461
462 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
463 const rtc::VideoSinkWants& wants2) {
464 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
465 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
466 }
467
468 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
469 const rtc::VideoSinkWants& wants2) {
470 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
471 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
472 }
473
474 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
475 const rtc::VideoSinkWants& wants2) {
476 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
477 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
478 EXPECT_GT(wants1.max_pixel_count, 0);
479 }
480
481 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
482 const rtc::VideoSinkWants& wants2) {
483 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
484 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
485 }
486
asapersson09f05612017-05-15 23:40:18 -0700487 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
488 int pixel_count) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200489 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700490 EXPECT_LT(wants.max_pixel_count, pixel_count);
491 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700492 }
493
494 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
495 EXPECT_LT(wants.max_framerate_fps, fps);
496 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
497 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700498 }
499
asaperssonf7e294d2017-06-13 23:25:22 -0700500 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
501 int expected_fps) {
502 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
503 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
504 EXPECT_FALSE(wants.target_pixel_count);
505 }
506
Jonathan Yubc771b72017-12-08 17:04:29 -0800507 void VerifyBalancedModeFpsRange(const rtc::VideoSinkWants& wants,
508 int last_frame_pixels) {
509 // Balanced mode should always scale FPS to the desired range before
510 // attempting to scale resolution.
511 int fps_limit = wants.max_framerate_fps;
512 if (last_frame_pixels <= 320 * 240) {
513 EXPECT_TRUE(7 <= fps_limit && fps_limit <= 10);
514 } else if (last_frame_pixels <= 480 * 270) {
515 EXPECT_TRUE(10 <= fps_limit && fps_limit <= 15);
516 } else if (last_frame_pixels <= 640 * 480) {
517 EXPECT_LE(15, fps_limit);
518 } else {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200519 EXPECT_EQ(kDefaultFramerate, fps_limit);
Jonathan Yubc771b72017-12-08 17:04:29 -0800520 }
521 }
522
sprang4847ae62017-06-27 07:06:52 -0700523 void WaitForEncodedFrame(int64_t expected_ntp_time) {
524 sink_.WaitForEncodedFrame(expected_ntp_time);
525 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
526 }
527
528 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
529 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
530 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
531 return ok;
532 }
533
534 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
535 sink_.WaitForEncodedFrame(expected_width, expected_height);
536 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
537 }
538
539 void ExpectDroppedFrame() {
540 sink_.ExpectDroppedFrame();
541 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
542 }
543
544 bool WaitForFrame(int64_t timeout_ms) {
545 bool ok = sink_.WaitForFrame(timeout_ms);
546 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
547 return ok;
548 }
549
perkj26091b12016-09-01 01:17:40 -0700550 class TestEncoder : public test::FakeEncoder {
551 public:
Niels Möllerc572ff32018-11-07 08:43:50 +0100552 TestEncoder() : FakeEncoder(Clock::GetRealTimeClock()) {}
perkj26091b12016-09-01 01:17:40 -0700553
asaperssonfab67072017-04-04 05:51:49 -0700554 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800555 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700556 return config_;
557 }
558
559 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800560 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700561 block_next_encode_ = true;
562 }
563
Erik Språngaed30702018-11-05 12:57:17 +0100564 VideoEncoder::EncoderInfo GetEncoderInfo() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800565 rtc::CritScope lock(&local_crit_sect_);
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100566 EncoderInfo info;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100567 if (initialized_ == EncoderState::kInitialized) {
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100568 if (quality_scaling_) {
569 info.scaling_settings =
570 VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
571 }
572 info.is_hardware_accelerated = is_hardware_accelerated_;
Åsa Perssonc29cb2c2019-03-25 12:06:59 +0100573 for (int i = 0; i < kMaxSpatialLayers; ++i) {
574 if (temporal_layers_supported_[i]) {
575 int num_layers = temporal_layers_supported_[i].value() ? 2 : 1;
576 info.fps_allocation[i].resize(num_layers);
577 }
578 }
Erik Språngaed30702018-11-05 12:57:17 +0100579 }
580 return info;
kthelgason876222f2016-11-29 01:44:11 -0800581 }
582
Erik Språngb7cb7b52019-02-26 15:52:33 +0100583 int32_t RegisterEncodeCompleteCallback(
584 EncodedImageCallback* callback) override {
585 rtc::CritScope lock(&local_crit_sect_);
586 encoded_image_callback_ = callback;
587 return FakeEncoder::RegisterEncodeCompleteCallback(callback);
588 }
589
perkjfa10b552016-10-02 23:45:26 -0700590 void ContinueEncode() { continue_encode_event_.Set(); }
591
592 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
593 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800594 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700595 EXPECT_EQ(timestamp_, timestamp);
596 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
597 }
598
kthelgason2fc52542017-03-03 00:24:41 -0800599 void SetQualityScaling(bool b) {
600 rtc::CritScope lock(&local_crit_sect_);
601 quality_scaling_ = b;
602 }
kthelgasonad9010c2017-02-14 00:46:51 -0800603
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100604 void SetIsHardwareAccelerated(bool is_hardware_accelerated) {
605 rtc::CritScope lock(&local_crit_sect_);
606 is_hardware_accelerated_ = is_hardware_accelerated;
607 }
608
Åsa Perssonc29cb2c2019-03-25 12:06:59 +0100609 void SetTemporalLayersSupported(size_t spatial_idx, bool supported) {
610 RTC_DCHECK_LT(spatial_idx, kMaxSpatialLayers);
611 rtc::CritScope lock(&local_crit_sect_);
612 temporal_layers_supported_[spatial_idx] = supported;
613 }
614
sprangfe627f32017-03-29 08:24:59 -0700615 void ForceInitEncodeFailure(bool force_failure) {
616 rtc::CritScope lock(&local_crit_sect_);
617 force_init_encode_failed_ = force_failure;
618 }
619
Niels Möller6bb5ab92019-01-11 11:11:10 +0100620 void SimulateOvershoot(double rate_factor) {
621 rtc::CritScope lock(&local_crit_sect_);
622 rate_factor_ = rate_factor;
623 }
624
Erik Språngd7329ca2019-02-21 21:19:53 +0100625 uint32_t GetLastFramerate() const {
Niels Möller6bb5ab92019-01-11 11:11:10 +0100626 rtc::CritScope lock(&local_crit_sect_);
627 return last_framerate_;
628 }
629
Erik Språngd7329ca2019-02-21 21:19:53 +0100630 VideoFrame::UpdateRect GetLastUpdateRect() const {
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100631 rtc::CritScope lock(&local_crit_sect_);
632 return last_update_rect_;
633 }
634
Niels Möller87e2d782019-03-07 10:18:23 +0100635 const std::vector<VideoFrameType>& LastFrameTypes() const {
Erik Språngd7329ca2019-02-21 21:19:53 +0100636 rtc::CritScope lock(&local_crit_sect_);
637 return last_frame_types_;
638 }
639
640 void InjectFrame(const VideoFrame& input_image, bool keyframe) {
Niels Möller87e2d782019-03-07 10:18:23 +0100641 const std::vector<VideoFrameType> frame_type = {
Niels Möller8f7ce222019-03-21 15:43:58 +0100642 keyframe ? VideoFrameType::kVideoFrameKey
643 : VideoFrameType::kVideoFrameDelta};
Erik Språngd7329ca2019-02-21 21:19:53 +0100644 {
645 rtc::CritScope lock(&local_crit_sect_);
646 last_frame_types_ = frame_type;
647 }
Niels Möllerb859b322019-03-07 12:40:01 +0100648 FakeEncoder::Encode(input_image, &frame_type);
Erik Språngd7329ca2019-02-21 21:19:53 +0100649 }
650
Erik Språngb7cb7b52019-02-26 15:52:33 +0100651 void InjectEncodedImage(const EncodedImage& image) {
652 rtc::CritScope lock(&local_crit_sect_);
653 encoded_image_callback_->OnEncodedImage(image, nullptr, nullptr);
654 }
655
Erik Språngd7329ca2019-02-21 21:19:53 +0100656 void ExpectNullFrame() {
657 rtc::CritScope lock(&local_crit_sect_);
658 expect_null_frame_ = true;
659 }
660
661 absl::optional<VideoBitrateAllocation> GetAndResetLastBitrateAllocation() {
662 auto allocation = last_bitrate_allocation_;
663 last_bitrate_allocation_.reset();
664 return allocation;
665 }
666
perkjfa10b552016-10-02 23:45:26 -0700667 private:
perkj26091b12016-09-01 01:17:40 -0700668 int32_t Encode(const VideoFrame& input_image,
Niels Möller87e2d782019-03-07 10:18:23 +0100669 const std::vector<VideoFrameType>* frame_types) override {
perkj26091b12016-09-01 01:17:40 -0700670 bool block_encode;
671 {
brandtre78d2662017-01-16 05:57:16 -0800672 rtc::CritScope lock(&local_crit_sect_);
Erik Språngd7329ca2019-02-21 21:19:53 +0100673 if (expect_null_frame_) {
674 EXPECT_EQ(input_image.timestamp(), 0u);
675 EXPECT_EQ(input_image.width(), 1);
676 last_frame_types_ = *frame_types;
677 expect_null_frame_ = false;
678 } else {
679 EXPECT_GT(input_image.timestamp(), timestamp_);
680 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
681 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
682 }
perkj26091b12016-09-01 01:17:40 -0700683
684 timestamp_ = input_image.timestamp();
685 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700686 last_input_width_ = input_image.width();
687 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700688 block_encode = block_next_encode_;
689 block_next_encode_ = false;
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100690 last_update_rect_ = input_image.update_rect();
Erik Språngd7329ca2019-02-21 21:19:53 +0100691 last_frame_types_ = *frame_types;
perkj26091b12016-09-01 01:17:40 -0700692 }
Niels Möllerb859b322019-03-07 12:40:01 +0100693 int32_t result = FakeEncoder::Encode(input_image, frame_types);
perkj26091b12016-09-01 01:17:40 -0700694 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700695 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700696 return result;
697 }
698
sprangfe627f32017-03-29 08:24:59 -0700699 int32_t InitEncode(const VideoCodec* config,
700 int32_t number_of_cores,
701 size_t max_payload_size) override {
702 int res =
703 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
704 rtc::CritScope lock(&local_crit_sect_);
Erik Språngb7cb7b52019-02-26 15:52:33 +0100705 EXPECT_EQ(initialized_, EncoderState::kUninitialized);
Erik Språng82fad3d2018-03-21 09:57:23 +0100706 if (config->codecType == kVideoCodecVP8) {
sprangfe627f32017-03-29 08:24:59 -0700707 // Simulate setting up temporal layers, in order to validate the life
708 // cycle of these objects.
Elad Aloncde8ab22019-03-20 11:56:20 +0100709 Vp8TemporalLayersFactory factory;
710 frame_buffer_controller_ = factory.Create(*config);
sprangfe627f32017-03-29 08:24:59 -0700711 }
Erik Språngb7cb7b52019-02-26 15:52:33 +0100712 if (force_init_encode_failed_) {
713 initialized_ = EncoderState::kInitializationFailed;
sprangfe627f32017-03-29 08:24:59 -0700714 return -1;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100715 }
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100716
Erik Språngb7cb7b52019-02-26 15:52:33 +0100717 initialized_ = EncoderState::kInitialized;
sprangfe627f32017-03-29 08:24:59 -0700718 return res;
719 }
720
Erik Språngb7cb7b52019-02-26 15:52:33 +0100721 int32_t Release() override {
722 rtc::CritScope lock(&local_crit_sect_);
723 EXPECT_NE(initialized_, EncoderState::kUninitialized);
724 initialized_ = EncoderState::kUninitialized;
725 return FakeEncoder::Release();
726 }
727
Niels Möller6bb5ab92019-01-11 11:11:10 +0100728 int32_t SetRateAllocation(const VideoBitrateAllocation& rate_allocation,
729 uint32_t framerate) {
730 rtc::CritScope lock(&local_crit_sect_);
731 VideoBitrateAllocation adjusted_rate_allocation;
732 for (size_t si = 0; si < kMaxSpatialLayers; ++si) {
733 for (size_t ti = 0; ti < kMaxTemporalStreams; ++ti) {
734 if (rate_allocation.HasBitrate(si, ti)) {
735 adjusted_rate_allocation.SetBitrate(
736 si, ti,
737 static_cast<uint32_t>(rate_allocation.GetBitrate(si, ti) *
738 rate_factor_));
739 }
740 }
741 }
742 last_framerate_ = framerate;
Erik Språngd7329ca2019-02-21 21:19:53 +0100743 last_bitrate_allocation_ = rate_allocation;
Niels Möller6bb5ab92019-01-11 11:11:10 +0100744 return FakeEncoder::SetRateAllocation(adjusted_rate_allocation,
745 framerate);
746 }
747
brandtre78d2662017-01-16 05:57:16 -0800748 rtc::CriticalSection local_crit_sect_;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100749 enum class EncoderState {
750 kUninitialized,
751 kInitializationFailed,
752 kInitialized
753 } initialized_ RTC_GUARDED_BY(local_crit_sect_) =
754 EncoderState::kUninitialized;
danilchapa37de392017-09-09 04:17:22 -0700755 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700756 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700757 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
758 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
759 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
760 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
761 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100762 bool is_hardware_accelerated_ RTC_GUARDED_BY(local_crit_sect_) = false;
Elad Aloncde8ab22019-03-20 11:56:20 +0100763 std::unique_ptr<Vp8FrameBufferController> frame_buffer_controller_
danilchapa37de392017-09-09 04:17:22 -0700764 RTC_GUARDED_BY(local_crit_sect_);
Åsa Perssonc29cb2c2019-03-25 12:06:59 +0100765 absl::optional<bool>
766 temporal_layers_supported_[kMaxSpatialLayers] RTC_GUARDED_BY(
767 local_crit_sect_);
danilchapa37de392017-09-09 04:17:22 -0700768 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
Niels Möller6bb5ab92019-01-11 11:11:10 +0100769 double rate_factor_ RTC_GUARDED_BY(local_crit_sect_) = 1.0;
770 uint32_t last_framerate_ RTC_GUARDED_BY(local_crit_sect_) = 0;
Erik Språngd7329ca2019-02-21 21:19:53 +0100771 absl::optional<VideoBitrateAllocation> last_bitrate_allocation_;
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100772 VideoFrame::UpdateRect last_update_rect_
773 RTC_GUARDED_BY(local_crit_sect_) = {0, 0, 0, 0};
Niels Möller87e2d782019-03-07 10:18:23 +0100774 std::vector<VideoFrameType> last_frame_types_;
Erik Språngd7329ca2019-02-21 21:19:53 +0100775 bool expect_null_frame_ = false;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100776 EncodedImageCallback* encoded_image_callback_
777 RTC_GUARDED_BY(local_crit_sect_) = nullptr;
perkj26091b12016-09-01 01:17:40 -0700778 };
779
mflodmancc3d4422017-08-03 08:27:51 -0700780 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700781 public:
782 explicit TestSink(TestEncoder* test_encoder)
Niels Möllerc572ff32018-11-07 08:43:50 +0100783 : test_encoder_(test_encoder) {}
perkj26091b12016-09-01 01:17:40 -0700784
perkj26091b12016-09-01 01:17:40 -0700785 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700786 EXPECT_TRUE(
787 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
788 }
789
790 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
791 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700792 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700793 if (!encoded_frame_event_.Wait(timeout_ms))
794 return false;
perkj26091b12016-09-01 01:17:40 -0700795 {
796 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800797 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700798 }
799 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700800 return true;
perkj26091b12016-09-01 01:17:40 -0700801 }
802
sprangb1ca0732017-02-01 08:38:12 -0800803 void WaitForEncodedFrame(uint32_t expected_width,
804 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700805 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100806 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700807 }
808
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100809 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700810 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800811 uint32_t width = 0;
812 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800813 {
814 rtc::CritScope lock(&crit_);
815 width = last_width_;
816 height = last_height_;
817 }
818 EXPECT_EQ(expected_height, height);
819 EXPECT_EQ(expected_width, width);
820 }
821
kthelgason2fc52542017-03-03 00:24:41 -0800822 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800823
sprangc5d62e22017-04-02 23:53:04 -0700824 bool WaitForFrame(int64_t timeout_ms) {
825 return encoded_frame_event_.Wait(timeout_ms);
826 }
827
perkj26091b12016-09-01 01:17:40 -0700828 void SetExpectNoFrames() {
829 rtc::CritScope lock(&crit_);
830 expect_frames_ = false;
831 }
832
asaperssonfab67072017-04-04 05:51:49 -0700833 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200834 rtc::CritScope lock(&crit_);
835 return number_of_reconfigurations_;
836 }
837
asaperssonfab67072017-04-04 05:51:49 -0700838 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200839 rtc::CritScope lock(&crit_);
840 return min_transmit_bitrate_bps_;
841 }
842
Erik Språngd7329ca2019-02-21 21:19:53 +0100843 void SetNumExpectedLayers(size_t num_layers) {
844 rtc::CritScope lock(&crit_);
845 num_expected_layers_ = num_layers;
846 }
847
Erik Språngb7cb7b52019-02-26 15:52:33 +0100848 int64_t GetLastCaptureTimeMs() const {
849 rtc::CritScope lock(&crit_);
850 return last_capture_time_ms_;
851 }
852
perkj26091b12016-09-01 01:17:40 -0700853 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700854 Result OnEncodedImage(
855 const EncodedImage& encoded_image,
856 const CodecSpecificInfo* codec_specific_info,
857 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200858 rtc::CritScope lock(&crit_);
859 EXPECT_TRUE(expect_frames_);
Erik Språngd7329ca2019-02-21 21:19:53 +0100860 uint32_t timestamp = encoded_image.Timestamp();
861 if (last_timestamp_ != timestamp) {
862 num_received_layers_ = 1;
863 } else {
864 ++num_received_layers_;
865 }
866 last_timestamp_ = timestamp;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100867 last_capture_time_ms_ = encoded_image.capture_time_ms_;
sprangb1ca0732017-02-01 08:38:12 -0800868 last_width_ = encoded_image._encodedWidth;
869 last_height_ = encoded_image._encodedHeight;
Erik Språngd7329ca2019-02-21 21:19:53 +0100870 if (num_received_layers_ == num_expected_layers_) {
871 encoded_frame_event_.Set();
872 }
sprangb1ca0732017-02-01 08:38:12 -0800873 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200874 }
875
Rasmus Brandtc402dbe2019-02-04 11:09:46 +0100876 void OnEncoderConfigurationChanged(
877 std::vector<VideoStream> streams,
878 VideoEncoderConfig::ContentType content_type,
879 int min_transmit_bitrate_bps) override {
Per512ecb32016-09-23 15:52:06 +0200880 rtc::CriticalSection crit_;
881 ++number_of_reconfigurations_;
882 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
883 }
884
perkj26091b12016-09-01 01:17:40 -0700885 rtc::CriticalSection crit_;
886 TestEncoder* test_encoder_;
887 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800888 uint32_t last_timestamp_ = 0;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100889 int64_t last_capture_time_ms_ = 0;
sprangb1ca0732017-02-01 08:38:12 -0800890 uint32_t last_height_ = 0;
891 uint32_t last_width_ = 0;
Erik Språngd7329ca2019-02-21 21:19:53 +0100892 size_t num_expected_layers_ = 1;
893 size_t num_received_layers_ = 0;
perkj26091b12016-09-01 01:17:40 -0700894 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200895 int number_of_reconfigurations_ = 0;
896 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700897 };
898
899 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100900 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200901 int codec_width_;
902 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700903 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700904 TestEncoder fake_encoder_;
Niels Möllercbcbc222018-09-28 09:07:24 +0200905 test::VideoEncoderProxyFactory encoder_factory_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800906 std::unique_ptr<VideoBitrateAllocatorFactory> bitrate_allocator_factory_;
sprangc5d62e22017-04-02 23:53:04 -0700907 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700908 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800909 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700910 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700911 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700912};
913
mflodmancc3d4422017-08-03 08:27:51 -0700914TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
Erik Språng610c7632019-03-06 15:37:33 +0100915 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
916 DataRate::Zero(), 0, 0);
Niels Möllerc572ff32018-11-07 08:43:50 +0100917 rtc::Event frame_destroyed_event;
perkja49cbd32016-09-16 07:53:41 -0700918 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700919 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700920 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700921 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700922}
923
mflodmancc3d4422017-08-03 08:27:51 -0700924TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700925 // Dropped since no target bitrate has been set.
Niels Möllerc572ff32018-11-07 08:43:50 +0100926 rtc::Event frame_destroyed_event;
Sebastian Janssona3177052018-04-10 13:05:49 +0200927 // The encoder will cache up to one frame for a short duration. Adding two
928 // frames means that the first frame will be dropped and the second frame will
929 // be sent when the encoder is enabled.
perkja49cbd32016-09-16 07:53:41 -0700930 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
Sebastian Janssona3177052018-04-10 13:05:49 +0200931 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkja49cbd32016-09-16 07:53:41 -0700932 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700933
Erik Språng610c7632019-03-06 15:37:33 +0100934 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
935 DataRate::Zero(), 0, 0);
perkj26091b12016-09-01 01:17:40 -0700936
Sebastian Janssona3177052018-04-10 13:05:49 +0200937 // The pending frame should be received.
sprang4847ae62017-06-27 07:06:52 -0700938 WaitForEncodedFrame(2);
Sebastian Janssona3177052018-04-10 13:05:49 +0200939 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
940
941 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700942 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700943}
944
mflodmancc3d4422017-08-03 08:27:51 -0700945TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
Erik Språng610c7632019-03-06 15:37:33 +0100946 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
947 DataRate::Zero(), 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700948 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700949 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700950
Erik Språng610c7632019-03-06 15:37:33 +0100951 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(0), DataRate::Zero(), 0,
952 0);
Sebastian Janssona3177052018-04-10 13:05:49 +0200953 // The encoder will cache up to one frame for a short duration. Adding two
954 // frames means that the first frame will be dropped and the second frame will
955 // be sent when the encoder is resumed.
perkja49cbd32016-09-16 07:53:41 -0700956 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Sebastian Janssona3177052018-04-10 13:05:49 +0200957 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700958
Erik Språng610c7632019-03-06 15:37:33 +0100959 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
960 DataRate::Zero(), 0, 0);
sprang4847ae62017-06-27 07:06:52 -0700961 WaitForEncodedFrame(3);
Sebastian Janssona3177052018-04-10 13:05:49 +0200962 video_source_.IncomingCapturedFrame(CreateFrame(4, nullptr));
963 WaitForEncodedFrame(4);
mflodmancc3d4422017-08-03 08:27:51 -0700964 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700965}
966
mflodmancc3d4422017-08-03 08:27:51 -0700967TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
Erik Språng610c7632019-03-06 15:37:33 +0100968 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
969 DataRate::Zero(), 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700970 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700971 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700972
973 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700974 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700975
perkja49cbd32016-09-16 07:53:41 -0700976 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700977 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700978 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700979}
980
mflodmancc3d4422017-08-03 08:27:51 -0700981TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
Erik Språng610c7632019-03-06 15:37:33 +0100982 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
983 DataRate::Zero(), 0, 0);
perkj26091b12016-09-01 01:17:40 -0700984
perkja49cbd32016-09-16 07:53:41 -0700985 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700986 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700987
mflodmancc3d4422017-08-03 08:27:51 -0700988 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700989 sink_.SetExpectNoFrames();
Niels Möllerc572ff32018-11-07 08:43:50 +0100990 rtc::Event frame_destroyed_event;
perkja49cbd32016-09-16 07:53:41 -0700991 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
992 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700993}
994
mflodmancc3d4422017-08-03 08:27:51 -0700995TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
Erik Språng610c7632019-03-06 15:37:33 +0100996 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
997 DataRate::Zero(), 0, 0);
perkj26091b12016-09-01 01:17:40 -0700998
999 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -07001000 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001001 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -07001002 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
1003 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -07001004 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
1005 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -07001006 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -07001007 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -07001008
mflodmancc3d4422017-08-03 08:27:51 -07001009 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -07001010}
1011
mflodmancc3d4422017-08-03 08:27:51 -07001012TEST_F(VideoStreamEncoderTest,
1013 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
Erik Språng610c7632019-03-06 15:37:33 +01001014 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1015 DataRate::Zero(), 0, 0);
Per21d45d22016-10-30 21:37:57 +01001016 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +02001017
1018 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +02001019 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001020 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +01001021 // The encoder will have been configured once when the first frame is
1022 // received.
1023 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +02001024
1025 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02001026 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +02001027 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -07001028 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001029 kMaxPayloadLength);
Per512ecb32016-09-23 15:52:06 +02001030
1031 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +02001032 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001033 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +01001034 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -07001035 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -07001036
mflodmancc3d4422017-08-03 08:27:51 -07001037 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -07001038}
1039
mflodmancc3d4422017-08-03 08:27:51 -07001040TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
Erik Språng610c7632019-03-06 15:37:33 +01001041 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1042 DataRate::Zero(), 0, 0);
perkjfa10b552016-10-02 23:45:26 -07001043
1044 // Capture a frame and wait for it to synchronize with the encoder thread.
1045 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001046 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +01001047 // The encoder will have been configured once.
1048 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -07001049 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
1050 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
1051
1052 codec_width_ *= 2;
1053 codec_height_ *= 2;
1054 // Capture a frame with a higher resolution and wait for it to synchronize
1055 // with the encoder thread.
1056 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001057 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -07001058 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
1059 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +01001060 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -07001061
mflodmancc3d4422017-08-03 08:27:51 -07001062 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -07001063}
1064
mflodmancc3d4422017-08-03 08:27:51 -07001065TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -07001066 EXPECT_TRUE(video_source_.has_sinks());
1067 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001068 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001069 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001070 EXPECT_FALSE(video_source_.has_sinks());
1071 EXPECT_TRUE(new_video_source.has_sinks());
1072
mflodmancc3d4422017-08-03 08:27:51 -07001073 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001074}
1075
mflodmancc3d4422017-08-03 08:27:51 -07001076TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -07001077 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -07001078 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -07001079 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -07001080 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001081}
1082
Jonathan Yubc771b72017-12-08 17:04:29 -08001083TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
1084 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -07001085 const int kWidth = 1280;
1086 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -08001087
1088 // We rely on the automatic resolution adaptation, but we handle framerate
1089 // adaptation manually by mocking the stats proxy.
1090 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -07001091
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001092 // Enable BALANCED preference, no initial limitation.
Erik Språng610c7632019-03-06 15:37:33 +01001093 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1094 DataRate::Zero(), 0, 0);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001095 video_stream_encoder_->SetSource(&video_source_,
1096 webrtc::DegradationPreference::BALANCED);
Jonathan Yubc771b72017-12-08 17:04:29 -08001097 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001098 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001099 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -07001100 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1101
Jonathan Yubc771b72017-12-08 17:04:29 -08001102 // Adapt down as far as possible.
1103 rtc::VideoSinkWants last_wants;
1104 int64_t t = 1;
1105 int loop_count = 0;
1106 do {
1107 ++loop_count;
1108 last_wants = video_source_.sink_wants();
1109
1110 // Simulate the framerate we've been asked to adapt to.
1111 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
1112 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
1113 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1114 mock_stats.input_frame_rate = fps;
1115 stats_proxy_->SetMockStats(mock_stats);
1116
1117 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1118 sink_.WaitForEncodedFrame(t);
1119 t += frame_interval_ms;
1120
mflodmancc3d4422017-08-03 08:27:51 -07001121 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08001122 VerifyBalancedModeFpsRange(
1123 video_source_.sink_wants(),
1124 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1125 } while (video_source_.sink_wants().max_pixel_count <
1126 last_wants.max_pixel_count ||
1127 video_source_.sink_wants().max_framerate_fps <
1128 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001129
Jonathan Yubc771b72017-12-08 17:04:29 -08001130 // Verify that we've adapted all the way down.
1131 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001132 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001133 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
1134 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -07001135 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -08001136 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
1137 *video_source_.last_sent_height());
1138 EXPECT_EQ(kMinBalancedFramerateFps,
1139 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001140
Jonathan Yubc771b72017-12-08 17:04:29 -08001141 // Adapt back up the same number of times we adapted down.
1142 for (int i = 0; i < loop_count - 1; ++i) {
1143 last_wants = video_source_.sink_wants();
1144
1145 // Simulate the framerate we've been asked to adapt to.
1146 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
1147 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
1148 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1149 mock_stats.input_frame_rate = fps;
1150 stats_proxy_->SetMockStats(mock_stats);
1151
1152 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1153 sink_.WaitForEncodedFrame(t);
1154 t += frame_interval_ms;
1155
mflodmancc3d4422017-08-03 08:27:51 -07001156 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -08001157 VerifyBalancedModeFpsRange(
1158 video_source_.sink_wants(),
1159 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1160 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
1161 last_wants.max_pixel_count ||
1162 video_source_.sink_wants().max_framerate_fps >
1163 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001164 }
1165
Åsa Persson8c1bf952018-09-13 10:42:19 +02001166 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001167 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001168 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001169 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1170 EXPECT_EQ((loop_count - 1) * 2,
1171 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -07001172
mflodmancc3d4422017-08-03 08:27:51 -07001173 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001174}
mflodmancc3d4422017-08-03 08:27:51 -07001175TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
Erik Språng610c7632019-03-06 15:37:33 +01001176 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1177 DataRate::Zero(), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001178 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001179
sprangc5d62e22017-04-02 23:53:04 -07001180 const int kFrameWidth = 1280;
1181 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07001182
Åsa Persson8c1bf952018-09-13 10:42:19 +02001183 int64_t frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -07001184
kthelgason5e13d412016-12-01 03:59:51 -08001185 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001186 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001187 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001188 frame_timestamp += kFrameIntervalMs;
1189
perkj803d97f2016-11-01 11:45:46 -07001190 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001191 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001192 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001193 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001194 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001195 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -07001196
asapersson0944a802017-04-07 00:57:58 -07001197 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -07001198 // wanted resolution.
1199 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
1200 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
1201 kFrameWidth * kFrameHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001202 EXPECT_EQ(kDefaultFramerate, video_source_.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001203
1204 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -07001205 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001206 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001207 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001208
sprangc5d62e22017-04-02 23:53:04 -07001209 // Initially no degradation registered.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001210 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001211
sprangc5d62e22017-04-02 23:53:04 -07001212 // Force an input frame rate to be available, or the adaptation call won't
1213 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -07001214 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -07001215 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -07001216 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -07001217 stats_proxy_->SetMockStats(stats);
1218
mflodmancc3d4422017-08-03 08:27:51 -07001219 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001220 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001221 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001222 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001223 frame_timestamp += kFrameIntervalMs;
1224
1225 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001226 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001227 EXPECT_EQ(std::numeric_limits<int>::max(),
1228 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001229 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001230
asapersson02465b82017-04-10 01:12:52 -07001231 // Turn off degradation completely.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001232 video_stream_encoder_->SetSource(&new_video_source,
1233 webrtc::DegradationPreference::DISABLED);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001234 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001235
mflodmancc3d4422017-08-03 08:27:51 -07001236 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001237 new_video_source.IncomingCapturedFrame(
1238 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001239 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001240 frame_timestamp += kFrameIntervalMs;
1241
1242 // Still no degradation.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001243 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001244
1245 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001246 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001247 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
sprangc5d62e22017-04-02 23:53:04 -07001248 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1249 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001250 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001251 EXPECT_EQ(kDefaultFramerate, new_video_source.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001252
1253 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001254 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001255 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001256 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1257 EXPECT_EQ(std::numeric_limits<int>::max(),
1258 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001259 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001260
mflodmancc3d4422017-08-03 08:27:51 -07001261 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001262}
1263
mflodmancc3d4422017-08-03 08:27:51 -07001264TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
Erik Språng610c7632019-03-06 15:37:33 +01001265 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1266 DataRate::Zero(), 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001267
asaperssonfab67072017-04-04 05:51:49 -07001268 const int kWidth = 1280;
1269 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001270 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001271 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001272 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1273 EXPECT_FALSE(stats.bw_limited_resolution);
1274 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1275
1276 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001277 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001278 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001279 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001280
1281 stats = stats_proxy_->GetStats();
1282 EXPECT_TRUE(stats.bw_limited_resolution);
1283 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1284
1285 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001286 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001287 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001288 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001289
1290 stats = stats_proxy_->GetStats();
1291 EXPECT_FALSE(stats.bw_limited_resolution);
1292 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1293 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1294
mflodmancc3d4422017-08-03 08:27:51 -07001295 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001296}
1297
mflodmancc3d4422017-08-03 08:27:51 -07001298TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
Erik Språng610c7632019-03-06 15:37:33 +01001299 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1300 DataRate::Zero(), 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001301
1302 const int kWidth = 1280;
1303 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001304 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001305 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001306 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1307 EXPECT_FALSE(stats.cpu_limited_resolution);
1308 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1309
1310 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001311 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001312 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001313 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001314
1315 stats = stats_proxy_->GetStats();
1316 EXPECT_TRUE(stats.cpu_limited_resolution);
1317 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1318
1319 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001320 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001321 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001322 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001323
1324 stats = stats_proxy_->GetStats();
1325 EXPECT_FALSE(stats.cpu_limited_resolution);
1326 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001327 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001328
mflodmancc3d4422017-08-03 08:27:51 -07001329 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001330}
1331
mflodmancc3d4422017-08-03 08:27:51 -07001332TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
Erik Språng610c7632019-03-06 15:37:33 +01001333 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1334 DataRate::Zero(), 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001335
asaperssonfab67072017-04-04 05:51:49 -07001336 const int kWidth = 1280;
1337 const int kHeight = 720;
1338 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001339 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001340 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001341 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001342 EXPECT_FALSE(stats.cpu_limited_resolution);
1343 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1344
asaperssonfab67072017-04-04 05:51:49 -07001345 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001346 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001347 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001348 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001349 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001350 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001351 EXPECT_TRUE(stats.cpu_limited_resolution);
1352 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1353
1354 // Set new source with adaptation still enabled.
1355 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001356 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001357 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001358
asaperssonfab67072017-04-04 05:51:49 -07001359 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001360 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001361 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001362 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001363 EXPECT_TRUE(stats.cpu_limited_resolution);
1364 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1365
1366 // Set adaptation disabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001367 video_stream_encoder_->SetSource(&new_video_source,
1368 webrtc::DegradationPreference::DISABLED);
kthelgason876222f2016-11-29 01:44:11 -08001369
asaperssonfab67072017-04-04 05:51:49 -07001370 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001371 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001372 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001373 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001374 EXPECT_FALSE(stats.cpu_limited_resolution);
1375 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1376
1377 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001378 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001379 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001380
asaperssonfab67072017-04-04 05:51:49 -07001381 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001382 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001383 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001384 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001385 EXPECT_TRUE(stats.cpu_limited_resolution);
1386 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1387
asaperssonfab67072017-04-04 05:51:49 -07001388 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001389 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001390 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001391 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001392 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001393 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001394 EXPECT_FALSE(stats.cpu_limited_resolution);
1395 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001396 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001397
mflodmancc3d4422017-08-03 08:27:51 -07001398 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001399}
1400
mflodmancc3d4422017-08-03 08:27:51 -07001401TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
Erik Språng610c7632019-03-06 15:37:33 +01001402 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1403 DataRate::Zero(), 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001404
asaperssonfab67072017-04-04 05:51:49 -07001405 const int kWidth = 1280;
1406 const int kHeight = 720;
1407 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001408 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001409 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001410 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001411 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001412 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001413
1414 // Set new source with adaptation still enabled.
1415 test::FrameForwarder new_video_source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001416 video_stream_encoder_->SetSource(&new_video_source,
1417 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001418
asaperssonfab67072017-04-04 05:51:49 -07001419 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001420 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001421 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001422 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001423 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001424 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001425
asaperssonfab67072017-04-04 05:51:49 -07001426 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001427 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001428 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001429 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001430 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001431 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001432 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001433 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001434
asaperssonfab67072017-04-04 05:51:49 -07001435 // Set new source with adaptation still enabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001436 video_stream_encoder_->SetSource(&new_video_source,
1437 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001438
asaperssonfab67072017-04-04 05:51:49 -07001439 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001440 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001441 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001442 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001443 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001444 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001445
asapersson02465b82017-04-10 01:12:52 -07001446 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001447 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001448 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001449
asaperssonfab67072017-04-04 05:51:49 -07001450 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001451 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001452 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001453 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001454 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001455 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1456 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001457
mflodmancc3d4422017-08-03 08:27:51 -07001458 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001459}
1460
mflodmancc3d4422017-08-03 08:27:51 -07001461TEST_F(VideoStreamEncoderTest,
1462 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
Erik Språng610c7632019-03-06 15:37:33 +01001463 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1464 DataRate::Zero(), 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001465
1466 const int kWidth = 1280;
1467 const int kHeight = 720;
Åsa Persson8c1bf952018-09-13 10:42:19 +02001468 int64_t timestamp_ms = kFrameIntervalMs;
asapersson36e9eb42017-03-31 05:29:12 -07001469 video_source_.set_adaptation_enabled(true);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001470 video_source_.IncomingCapturedFrame(
1471 CreateFrame(timestamp_ms, kWidth, kHeight));
1472 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001473 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1474 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1475 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1476
1477 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001478 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001479 timestamp_ms += kFrameIntervalMs;
1480 video_source_.IncomingCapturedFrame(
1481 CreateFrame(timestamp_ms, kWidth, kHeight));
1482 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001483 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1484 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1485 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1486
1487 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001488 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001489 timestamp_ms += kFrameIntervalMs;
1490 video_source_.IncomingCapturedFrame(
1491 CreateFrame(timestamp_ms, kWidth, kHeight));
1492 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001493 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1494 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1495 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1496
Niels Möller4db138e2018-04-19 09:04:13 +02001497 // Leave source unchanged, but disable quality scaler.
asapersson36e9eb42017-03-31 05:29:12 -07001498 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02001499
1500 VideoEncoderConfig video_encoder_config;
1501 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
1502 // Make format different, to force recreation of encoder.
1503 video_encoder_config.video_format.parameters["foo"] = "foo";
1504 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001505 kMaxPayloadLength);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001506 timestamp_ms += kFrameIntervalMs;
1507 video_source_.IncomingCapturedFrame(
1508 CreateFrame(timestamp_ms, kWidth, kHeight));
1509 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001510 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1511 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1512 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1513
mflodmancc3d4422017-08-03 08:27:51 -07001514 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001515}
1516
mflodmancc3d4422017-08-03 08:27:51 -07001517TEST_F(VideoStreamEncoderTest,
1518 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
Erik Språng610c7632019-03-06 15:37:33 +01001519 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1520 DataRate::Zero(), 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001521
asapersson0944a802017-04-07 00:57:58 -07001522 const int kWidth = 1280;
1523 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001524 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001525
asaperssonfab67072017-04-04 05:51:49 -07001526 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001527 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001528 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001529 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001530 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001531 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1532
asapersson02465b82017-04-10 01:12:52 -07001533 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001534 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001535 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001536 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001537 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001538 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001539 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001540 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1541
1542 // Set new source with adaptation still enabled.
1543 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001544 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001545 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001546
1547 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001548 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001549 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001550 stats = stats_proxy_->GetStats();
1551 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001552 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001553 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1554
sprangc5d62e22017-04-02 23:53:04 -07001555 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001556 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001557 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001558 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001559 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001560 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001561 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001562 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001563 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001564 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001565 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1566
sprangc5d62e22017-04-02 23:53:04 -07001567 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001568 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001569 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1570 mock_stats.input_frame_rate = 30;
1571 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001572 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001573 stats_proxy_->ResetMockStats();
1574
1575 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001576 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001577 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001578
1579 // Framerate now adapted.
1580 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001581 EXPECT_FALSE(stats.cpu_limited_resolution);
1582 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001583 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1584
1585 // Disable CPU adaptation.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001586 video_stream_encoder_->SetSource(&new_video_source,
1587 webrtc::DegradationPreference::DISABLED);
sprangc5d62e22017-04-02 23:53:04 -07001588 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001589 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001590 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001591
1592 stats = stats_proxy_->GetStats();
1593 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001594 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001595 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1596
1597 // Try to trigger overuse. Should not succeed.
1598 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001599 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001600 stats_proxy_->ResetMockStats();
1601
1602 stats = stats_proxy_->GetStats();
1603 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001604 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001605 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1606
1607 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001608 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001609 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssonfab67072017-04-04 05:51:49 -07001610 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001611 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001612 stats = stats_proxy_->GetStats();
1613 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001614 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001615 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001616
1617 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001618 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001619 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001620 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001621 stats = stats_proxy_->GetStats();
1622 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001623 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001624 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1625
1626 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001627 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001628 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001629 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001630 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001631 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001632 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001633 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001634 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001635 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001636 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1637
1638 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001639 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001640 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001641 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001642 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001643 stats = stats_proxy_->GetStats();
1644 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001645 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001646 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001647 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001648
mflodmancc3d4422017-08-03 08:27:51 -07001649 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001650}
1651
mflodmancc3d4422017-08-03 08:27:51 -07001652TEST_F(VideoStreamEncoderTest,
1653 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001654 const int kWidth = 1280;
1655 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001656 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1657 DataRate::Zero(), 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001658
asaperssonfab67072017-04-04 05:51:49 -07001659 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001660 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001661
asaperssonfab67072017-04-04 05:51:49 -07001662 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001663 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001664
asaperssonfab67072017-04-04 05:51:49 -07001665 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001666 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001667
asaperssonfab67072017-04-04 05:51:49 -07001668 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001669 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001670
kthelgason876222f2016-11-29 01:44:11 -08001671 // Expect a scale down.
1672 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001673 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001674
asapersson02465b82017-04-10 01:12:52 -07001675 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001676 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001677 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001678 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001679
asaperssonfab67072017-04-04 05:51:49 -07001680 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001681 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001682 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001683 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001684
asaperssonfab67072017-04-04 05:51:49 -07001685 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001686 EXPECT_EQ(std::numeric_limits<int>::max(),
1687 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001688
asaperssonfab67072017-04-04 05:51:49 -07001689 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001690 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001691 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001692 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001693
asapersson02465b82017-04-10 01:12:52 -07001694 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001695 EXPECT_EQ(std::numeric_limits<int>::max(),
1696 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001697
mflodmancc3d4422017-08-03 08:27:51 -07001698 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001699}
1700
mflodmancc3d4422017-08-03 08:27:51 -07001701TEST_F(VideoStreamEncoderTest,
1702 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001703 const int kWidth = 1280;
1704 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001705 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1706 DataRate::Zero(), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001707
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001708 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001709 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001710 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001711 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001712
1713 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001714 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001715 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001716 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1717 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1718
1719 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001720 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001721 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001722 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1723 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1724 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1725
1726 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001727 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001728 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1729 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1730 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1731
mflodmancc3d4422017-08-03 08:27:51 -07001732 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001733}
1734
mflodmancc3d4422017-08-03 08:27:51 -07001735TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001736 const int kWidth = 1280;
1737 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001738 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1739 DataRate::Zero(), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001740
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001741 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001742 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001743 video_stream_encoder_->SetSource(&source,
1744 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001745 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1746 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001747 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001748
1749 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001750 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001751 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1752 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1753 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1754 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1755
1756 // Trigger adapt down for same input resolution, expect no change.
1757 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1758 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001759 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001760 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1761 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1762 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1763
1764 // Trigger adapt down for larger input resolution, expect no change.
1765 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1766 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001767 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001768 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1769 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1770 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1771
mflodmancc3d4422017-08-03 08:27:51 -07001772 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001773}
1774
mflodmancc3d4422017-08-03 08:27:51 -07001775TEST_F(VideoStreamEncoderTest,
1776 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001777 const int kWidth = 1280;
1778 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001779 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1780 DataRate::Zero(), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001781
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001782 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001783 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001784 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001785 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001786
1787 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001788 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001789 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001790 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1791 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1792
1793 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001794 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001795 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001796 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1797 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1798
mflodmancc3d4422017-08-03 08:27:51 -07001799 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001800}
1801
mflodmancc3d4422017-08-03 08:27:51 -07001802TEST_F(VideoStreamEncoderTest,
1803 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001804 const int kWidth = 1280;
1805 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001806 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1807 DataRate::Zero(), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001808
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001809 // Enable MAINTAIN_RESOLUTION preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001810 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001811 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001812 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
asapersson02465b82017-04-10 01:12:52 -07001813
1814 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001815 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001816 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001817 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001818 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1819
1820 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001821 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001822 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001823 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001824 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1825
mflodmancc3d4422017-08-03 08:27:51 -07001826 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001827}
1828
mflodmancc3d4422017-08-03 08:27:51 -07001829TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001830 const int kWidth = 1280;
1831 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001832 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1833 DataRate::Zero(), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001834
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001835 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001836 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001837 video_stream_encoder_->SetSource(&source,
1838 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001839
1840 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1841 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001842 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001843 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1844 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1845 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1846
1847 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001848 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001849 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001850 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1851 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1852 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1853
mflodmancc3d4422017-08-03 08:27:51 -07001854 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001855}
1856
mflodmancc3d4422017-08-03 08:27:51 -07001857TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001858 const int kWidth = 1280;
1859 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001860 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1861 DataRate::Zero(), 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001862
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001863 // Enable DISABLED preference, no initial limitation.
asapersson09f05612017-05-15 23:40:18 -07001864 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001865 video_stream_encoder_->SetSource(&source,
1866 webrtc::DegradationPreference::DISABLED);
asapersson09f05612017-05-15 23:40:18 -07001867
1868 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1869 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001870 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001871 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1872 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1873 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1874
1875 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001876 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001877 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001878 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1879 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1880 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1881
mflodmancc3d4422017-08-03 08:27:51 -07001882 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001883}
1884
mflodmancc3d4422017-08-03 08:27:51 -07001885TEST_F(VideoStreamEncoderTest,
1886 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001887 const int kWidth = 1280;
1888 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001889 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1890 DataRate::Zero(), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001891
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001892 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001893 AdaptingFrameForwarder source;
1894 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001895 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001896 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001897
1898 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001899 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001900 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001901 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1902 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1903
1904 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001905 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001906 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001907 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001908 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001909 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1910 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1911
1912 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001913 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001914 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001915 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1916 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1917 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1918
mflodmancc3d4422017-08-03 08:27:51 -07001919 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001920}
1921
mflodmancc3d4422017-08-03 08:27:51 -07001922TEST_F(VideoStreamEncoderTest,
1923 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001924 const int kWidth = 1280;
1925 const int kHeight = 720;
1926 const int kInputFps = 30;
Erik Språng610c7632019-03-06 15:37:33 +01001927 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1928 DataRate::Zero(), 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001929
1930 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1931 stats.input_frame_rate = kInputFps;
1932 stats_proxy_->SetMockStats(stats);
1933
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001934 // Expect no scaling to begin with (preference: MAINTAIN_FRAMERATE).
asapersson09f05612017-05-15 23:40:18 -07001935 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1936 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001937 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001938
1939 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001940 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001941 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1942 sink_.WaitForEncodedFrame(2);
1943 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1944
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001945 // Enable MAINTAIN_RESOLUTION preference.
asapersson09f05612017-05-15 23:40:18 -07001946 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001947 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001948 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001949 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001950
1951 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001952 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001953 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1954 sink_.WaitForEncodedFrame(3);
1955 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1956
1957 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001958 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001959 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001960
mflodmancc3d4422017-08-03 08:27:51 -07001961 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001962}
1963
mflodmancc3d4422017-08-03 08:27:51 -07001964TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001965 const int kWidth = 1280;
1966 const int kHeight = 720;
1967 const size_t kNumFrames = 10;
1968
Erik Språng610c7632019-03-06 15:37:33 +01001969 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1970 DataRate::Zero(), 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001971
asaperssond0de2952017-04-21 01:47:31 -07001972 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001973 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001974 video_source_.set_adaptation_enabled(true);
1975
1976 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1977 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1978
1979 int downscales = 0;
1980 for (size_t i = 1; i <= kNumFrames; i++) {
Åsa Persson8c1bf952018-09-13 10:42:19 +02001981 video_source_.IncomingCapturedFrame(
1982 CreateFrame(i * kFrameIntervalMs, kWidth, kHeight));
1983 WaitForEncodedFrame(i * kFrameIntervalMs);
asaperssond0de2952017-04-21 01:47:31 -07001984
asaperssonfab67072017-04-04 05:51:49 -07001985 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001986 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001987 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001988 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001989
1990 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1991 ++downscales;
1992
1993 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1994 EXPECT_EQ(downscales,
1995 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1996 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001997 }
mflodmancc3d4422017-08-03 08:27:51 -07001998 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001999}
2000
mflodmancc3d4422017-08-03 08:27:51 -07002001TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002002 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
2003 const int kWidth = 1280;
2004 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01002005 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2006 DataRate::Zero(), 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002007
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002008 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002009 AdaptingFrameForwarder source;
2010 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002011 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002012 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002013
Åsa Persson8c1bf952018-09-13 10:42:19 +02002014 int64_t timestamp_ms = kFrameIntervalMs;
2015 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002016 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002017 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002018 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2019 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2020
2021 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002022 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002023 timestamp_ms += kFrameIntervalMs;
2024 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2025 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002026 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002027 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2028 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2029
2030 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002031 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002032 timestamp_ms += kFrameIntervalMs;
2033 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002034 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002035 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002036 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2037 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2038
2039 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002040 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002041 timestamp_ms += kFrameIntervalMs;
2042 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2043 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002044 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002045 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2046 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2047
2048 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002049 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002050 timestamp_ms += kFrameIntervalMs;
2051 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asapersson09f05612017-05-15 23:40:18 -07002052 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002053 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002054 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2055 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2056
mflodmancc3d4422017-08-03 08:27:51 -07002057 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002058}
2059
mflodmancc3d4422017-08-03 08:27:51 -07002060TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07002061 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
2062 const int kWidth = 1280;
2063 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01002064 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2065 DataRate::Zero(), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002066
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002067 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002068 AdaptingFrameForwarder source;
2069 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002070 video_stream_encoder_->SetSource(&source,
2071 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002072
Åsa Persson8c1bf952018-09-13 10:42:19 +02002073 int64_t timestamp_ms = kFrameIntervalMs;
2074 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07002075 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002076 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002077 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2078 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2079
2080 // Trigger adapt down, expect scaled down resolution.
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 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002085 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2086 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2087 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2088
2089 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002090 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002091 timestamp_ms += kFrameIntervalMs;
2092 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07002093 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002094 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002095 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2096 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2097
2098 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002099 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002100 timestamp_ms += kFrameIntervalMs;
2101 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2102 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002103 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2104 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2105 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2106
2107 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002108 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002109 timestamp_ms += kFrameIntervalMs;
2110 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07002111 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002112 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002113 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2114 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2115
mflodmancc3d4422017-08-03 08:27:51 -07002116 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002117}
2118
mflodmancc3d4422017-08-03 08:27:51 -07002119TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002120 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
2121 const int kWidth = 1280;
2122 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01002123 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2124 DataRate::Zero(), 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002125
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002126 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002127 AdaptingFrameForwarder source;
2128 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002129 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002130 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002131
Åsa Persson8c1bf952018-09-13 10:42:19 +02002132 int64_t timestamp_ms = kFrameIntervalMs;
2133 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002134 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002135 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002136 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2137 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2138 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2139 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2140
2141 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002142 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002143 timestamp_ms += kFrameIntervalMs;
2144 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2145 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002146 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002147 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2148 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2149 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2150 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2151
2152 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07002153 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002154 timestamp_ms += kFrameIntervalMs;
2155 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2156 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002157 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002158 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2159 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2160 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2161 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2162
Jonathan Yubc771b72017-12-08 17:04:29 -08002163 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002164 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002165 timestamp_ms += kFrameIntervalMs;
2166 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2167 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002168 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002169 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2170 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002171 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002172 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2173
Jonathan Yubc771b72017-12-08 17:04:29 -08002174 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07002175 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002176 timestamp_ms += kFrameIntervalMs;
2177 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2178 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002179 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002180 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07002181 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2182 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2183 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2184 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2185
Jonathan Yubc771b72017-12-08 17:04:29 -08002186 // Trigger quality adapt down, expect no change (min resolution reached).
2187 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002188 timestamp_ms += kFrameIntervalMs;
2189 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2190 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002191 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
2192 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2193 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2194 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2195 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2196
2197 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002198 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002199 timestamp_ms += kFrameIntervalMs;
2200 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2201 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002202 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002203 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2204 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2205 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2206 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2207
2208 // Trigger cpu adapt up, expect upscaled resolution (640x360).
2209 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002210 timestamp_ms += kFrameIntervalMs;
2211 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2212 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002213 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2214 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2215 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2216 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2217 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2218
2219 // Trigger cpu adapt up, expect upscaled resolution (960x540).
2220 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002221 timestamp_ms += kFrameIntervalMs;
2222 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2223 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002224 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002225 last_wants = source.sink_wants();
2226 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2227 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002228 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002229 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2230
2231 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002232 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002233 timestamp_ms += kFrameIntervalMs;
2234 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2235 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002236 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002237 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2238 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002239 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002240 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2241
2242 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002243 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002244 timestamp_ms += kFrameIntervalMs;
2245 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002246 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002247 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002248 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002249 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2250 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002251 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002252 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002253
mflodmancc3d4422017-08-03 08:27:51 -07002254 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002255}
2256
mflodmancc3d4422017-08-03 08:27:51 -07002257TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002258 const int kWidth = 640;
2259 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002260
Erik Språng610c7632019-03-06 15:37:33 +01002261 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2262 DataRate::Zero(), 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002263
perkj803d97f2016-11-01 11:45:46 -07002264 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002265 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002266 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002267 }
2268
mflodmancc3d4422017-08-03 08:27:51 -07002269 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002270 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002271 video_source_.IncomingCapturedFrame(CreateFrame(
2272 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002273 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002274 }
2275
mflodmancc3d4422017-08-03 08:27:51 -07002276 video_stream_encoder_->Stop();
2277 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002278 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002279
perkj803d97f2016-11-01 11:45:46 -07002280 EXPECT_EQ(1,
2281 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2282 EXPECT_EQ(
2283 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2284}
2285
mflodmancc3d4422017-08-03 08:27:51 -07002286TEST_F(VideoStreamEncoderTest,
2287 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
Erik Språng610c7632019-03-06 15:37:33 +01002288 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2289 DataRate::Zero(), 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002290 const int kWidth = 640;
2291 const int kHeight = 360;
2292
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002293 video_stream_encoder_->SetSource(&video_source_,
2294 webrtc::DegradationPreference::DISABLED);
asaperssonf4e44af2017-04-19 02:01:06 -07002295
2296 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2297 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002298 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002299 }
2300
mflodmancc3d4422017-08-03 08:27:51 -07002301 video_stream_encoder_->Stop();
2302 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002303 stats_proxy_.reset();
2304
2305 EXPECT_EQ(0,
2306 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2307}
2308
mflodmancc3d4422017-08-03 08:27:51 -07002309TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002310 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02002311 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002312
2313 const int kDefaultFps = 30;
Erik Språng566124a2018-04-23 12:32:22 +02002314 const VideoBitrateAllocation expected_bitrate =
sprang57c2fff2017-01-16 06:24:02 -08002315 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002316 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002317
sprang57c2fff2017-01-16 06:24:02 -08002318 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
Niels Möller6bb5ab92019-01-11 11:11:10 +01002319 .Times(1);
Erik Språng610c7632019-03-06 15:37:33 +01002320 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kLowTargetBitrateBps),
2321 DataRate::Zero(), 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002322
sprang57c2fff2017-01-16 06:24:02 -08002323 video_source_.IncomingCapturedFrame(
Erik Språngd7329ca2019-02-21 21:19:53 +01002324 CreateFrame(rtc::TimeMillis(), codec_width_, codec_height_));
2325 WaitForEncodedFrame(rtc::TimeMillis());
2326 absl::optional<VideoBitrateAllocation> bitrate_allocation =
2327 fake_encoder_.GetAndResetLastBitrateAllocation();
2328 // Check that encoder has been updated too, not just allocation observer.
2329 EXPECT_EQ(bitrate_allocation->get_sum_bps(), kLowTargetBitrateBps);
2330 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec / kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002331
2332 // Not called on second frame.
2333 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2334 .Times(0);
2335 video_source_.IncomingCapturedFrame(
Erik Språngd7329ca2019-02-21 21:19:53 +01002336 CreateFrame(rtc::TimeMillis(), codec_width_, codec_height_));
2337 WaitForEncodedFrame(rtc::TimeMillis());
2338 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec / kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002339
2340 // Called after a process interval.
2341 const int64_t kProcessIntervalMs =
2342 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang57c2fff2017-01-16 06:24:02 -08002343 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2344 .Times(1);
Erik Språngd7329ca2019-02-21 21:19:53 +01002345 const int64_t start_time_ms = rtc::TimeMillis();
2346 while (rtc::TimeMillis() - start_time_ms < kProcessIntervalMs) {
2347 video_source_.IncomingCapturedFrame(
2348 CreateFrame(rtc::TimeMillis(), codec_width_, codec_height_));
2349 WaitForEncodedFrame(rtc::TimeMillis());
2350 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec / kDefaultFps);
2351 }
2352
2353 // Since rates are unchanged, encoder should not be reconfigured.
2354 EXPECT_FALSE(fake_encoder_.GetAndResetLastBitrateAllocation().has_value());
sprang57c2fff2017-01-16 06:24:02 -08002355
mflodmancc3d4422017-08-03 08:27:51 -07002356 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002357}
2358
Åsa Perssonc29cb2c2019-03-25 12:06:59 +01002359TEST_F(VideoStreamEncoderTest, TemporalLayersNotDisabledIfSupported) {
2360 // 2 TLs configured, temporal layers supported by encoder.
2361 const int kNumTemporalLayers = 2;
2362 ResetEncoder("VP8", 1, kNumTemporalLayers, 1, /*screenshare*/ false);
2363 fake_encoder_.SetTemporalLayersSupported(0, true);
2364
2365 // Bitrate allocated across temporal layers.
2366 const int kTl0Bps = kTargetBitrateBps *
2367 webrtc::SimulcastRateAllocator::GetTemporalRateAllocation(
2368 kNumTemporalLayers, /*temporal_id*/ 0);
2369 const int kTl1Bps = kTargetBitrateBps *
2370 webrtc::SimulcastRateAllocator::GetTemporalRateAllocation(
2371 kNumTemporalLayers, /*temporal_id*/ 1);
2372 VideoBitrateAllocation expected_bitrate;
2373 expected_bitrate.SetBitrate(/*si*/ 0, /*ti*/ 0, kTl0Bps);
2374 expected_bitrate.SetBitrate(/*si*/ 0, /*ti*/ 1, kTl1Bps - kTl0Bps);
2375
2376 VerifyAllocatedBitrate(expected_bitrate);
2377 video_stream_encoder_->Stop();
2378}
2379
2380TEST_F(VideoStreamEncoderTest, TemporalLayersDisabledIfNotSupported) {
2381 // 2 TLs configured, temporal layers not supported by encoder.
2382 ResetEncoder("VP8", 1, /*num_temporal_layers*/ 2, 1, /*screenshare*/ false);
2383 fake_encoder_.SetTemporalLayersSupported(0, false);
2384
2385 // Temporal layers not supported by the encoder.
2386 // Total bitrate should be at ti:0.
2387 VideoBitrateAllocation expected_bitrate;
2388 expected_bitrate.SetBitrate(/*si*/ 0, /*ti*/ 0, kTargetBitrateBps);
2389
2390 VerifyAllocatedBitrate(expected_bitrate);
2391 video_stream_encoder_->Stop();
2392}
2393
2394TEST_F(VideoStreamEncoderTest, VerifyBitrateAllocationForTwoStreams) {
2395 // 2 TLs configured, temporal layers only supported for first stream.
2396 ResetEncoder("VP8", 2, /*num_temporal_layers*/ 2, 1, /*screenshare*/ false);
2397 fake_encoder_.SetTemporalLayersSupported(0, true);
2398 fake_encoder_.SetTemporalLayersSupported(1, false);
2399
2400 const int kS0Bps = 150000;
2401 const int kS0Tl0Bps =
2402 kS0Bps * webrtc::SimulcastRateAllocator::GetTemporalRateAllocation(
2403 /*num_layers*/ 2, /*temporal_id*/ 0);
2404 const int kS0Tl1Bps =
2405 kS0Bps * webrtc::SimulcastRateAllocator::GetTemporalRateAllocation(
2406 /*num_layers*/ 2, /*temporal_id*/ 1);
2407 const int kS1Bps = kTargetBitrateBps - kS0Tl1Bps;
2408 // Temporal layers not supported by si:1.
2409 VideoBitrateAllocation expected_bitrate;
2410 expected_bitrate.SetBitrate(/*si*/ 0, /*ti*/ 0, kS0Tl0Bps);
2411 expected_bitrate.SetBitrate(/*si*/ 0, /*ti*/ 1, kS0Tl1Bps - kS0Tl0Bps);
2412 expected_bitrate.SetBitrate(/*si*/ 1, /*ti*/ 0, kS1Bps);
2413
2414 VerifyAllocatedBitrate(expected_bitrate);
2415 video_stream_encoder_->Stop();
2416}
2417
Niels Möller7dc26b72017-12-06 10:27:48 +01002418TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2419 const int kFrameWidth = 1280;
2420 const int kFrameHeight = 720;
2421 const int kFramerate = 24;
2422
Erik Språng610c7632019-03-06 15:37:33 +01002423 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2424 DataRate::Zero(), 0, 0);
Niels Möller7dc26b72017-12-06 10:27:48 +01002425 test::FrameForwarder source;
2426 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002427 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002428
2429 // Insert a single frame, triggering initial configuration.
2430 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2431 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2432
2433 EXPECT_EQ(
2434 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2435 kDefaultFramerate);
2436
2437 // Trigger reconfigure encoder (without resetting the entire instance).
2438 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002439 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002440 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2441 video_encoder_config.number_of_streams = 1;
2442 video_encoder_config.video_stream_factory =
2443 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2444 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002445 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002446 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2447
2448 // Detector should be updated with fps limit from codec config.
2449 EXPECT_EQ(
2450 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2451 kFramerate);
2452
2453 // Trigger overuse, max framerate should be reduced.
2454 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2455 stats.input_frame_rate = kFramerate;
2456 stats_proxy_->SetMockStats(stats);
2457 video_stream_encoder_->TriggerCpuOveruse();
2458 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2459 int adapted_framerate =
2460 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2461 EXPECT_LT(adapted_framerate, kFramerate);
2462
2463 // Trigger underuse, max framerate should go back to codec configured fps.
2464 // Set extra low fps, to make sure it's actually reset, not just incremented.
2465 stats = stats_proxy_->GetStats();
2466 stats.input_frame_rate = adapted_framerate / 2;
2467 stats_proxy_->SetMockStats(stats);
2468 video_stream_encoder_->TriggerCpuNormalUsage();
2469 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2470 EXPECT_EQ(
2471 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2472 kFramerate);
2473
2474 video_stream_encoder_->Stop();
2475}
2476
2477TEST_F(VideoStreamEncoderTest,
2478 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2479 const int kFrameWidth = 1280;
2480 const int kFrameHeight = 720;
2481 const int kLowFramerate = 15;
2482 const int kHighFramerate = 25;
2483
Erik Språng610c7632019-03-06 15:37:33 +01002484 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2485 DataRate::Zero(), 0, 0);
Niels Möller7dc26b72017-12-06 10:27:48 +01002486 test::FrameForwarder source;
2487 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002488 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002489
2490 // Trigger initial configuration.
2491 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002492 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002493 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2494 video_encoder_config.number_of_streams = 1;
2495 video_encoder_config.video_stream_factory =
2496 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2497 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2498 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002499 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002500 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2501
2502 EXPECT_EQ(
2503 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2504 kLowFramerate);
2505
2506 // Trigger overuse, max framerate should be reduced.
2507 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2508 stats.input_frame_rate = kLowFramerate;
2509 stats_proxy_->SetMockStats(stats);
2510 video_stream_encoder_->TriggerCpuOveruse();
2511 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2512 int adapted_framerate =
2513 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2514 EXPECT_LT(adapted_framerate, kLowFramerate);
2515
2516 // Reconfigure the encoder with a new (higher max framerate), max fps should
2517 // still respect the adaptation.
2518 video_encoder_config.video_stream_factory =
2519 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2520 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2521 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002522 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002523 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2524
2525 EXPECT_EQ(
2526 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2527 adapted_framerate);
2528
2529 // Trigger underuse, max framerate should go back to codec configured fps.
2530 stats = stats_proxy_->GetStats();
2531 stats.input_frame_rate = adapted_framerate;
2532 stats_proxy_->SetMockStats(stats);
2533 video_stream_encoder_->TriggerCpuNormalUsage();
2534 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2535 EXPECT_EQ(
2536 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2537 kHighFramerate);
2538
2539 video_stream_encoder_->Stop();
2540}
2541
mflodmancc3d4422017-08-03 08:27:51 -07002542TEST_F(VideoStreamEncoderTest,
2543 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002544 const int kFrameWidth = 1280;
2545 const int kFrameHeight = 720;
2546 const int kFramerate = 24;
2547
Erik Språng610c7632019-03-06 15:37:33 +01002548 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2549 DataRate::Zero(), 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002550 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002551 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002552 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangfda496a2017-06-15 04:21:07 -07002553
2554 // Trigger initial configuration.
2555 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002556 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002557 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2558 video_encoder_config.number_of_streams = 1;
2559 video_encoder_config.video_stream_factory =
2560 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2561 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002562 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002563 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002564 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002565
Niels Möller7dc26b72017-12-06 10:27:48 +01002566 EXPECT_EQ(
2567 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2568 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002569
2570 // Trigger overuse, max framerate should be reduced.
2571 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2572 stats.input_frame_rate = kFramerate;
2573 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002574 video_stream_encoder_->TriggerCpuOveruse();
2575 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002576 int adapted_framerate =
2577 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002578 EXPECT_LT(adapted_framerate, kFramerate);
2579
2580 // Change degradation preference to not enable framerate scaling. Target
2581 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002582 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002583 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -07002584 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002585 EXPECT_EQ(
2586 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2587 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002588
mflodmancc3d4422017-08-03 08:27:51 -07002589 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002590}
2591
mflodmancc3d4422017-08-03 08:27:51 -07002592TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002593 const int kTooLowBitrateForFrameSizeBps = 10000;
Erik Språng610c7632019-03-06 15:37:33 +01002594 video_stream_encoder_->OnBitrateUpdated(
2595 DataRate::bps(kTooLowBitrateForFrameSizeBps), DataRate::Zero(), 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002596 const int kWidth = 640;
2597 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002598
asaperssonfab67072017-04-04 05:51:49 -07002599 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002600
2601 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002602 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002603
2604 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002605 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002606
sprangc5d62e22017-04-02 23:53:04 -07002607 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002608
asaperssonfab67072017-04-04 05:51:49 -07002609 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002610 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002611 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002612
2613 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002614 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002615
sprangc5d62e22017-04-02 23:53:04 -07002616 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002617
mflodmancc3d4422017-08-03 08:27:51 -07002618 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002619}
2620
mflodmancc3d4422017-08-03 08:27:51 -07002621TEST_F(VideoStreamEncoderTest,
2622 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002623 const int kTooLowBitrateForFrameSizeBps = 10000;
Erik Språng610c7632019-03-06 15:37:33 +01002624 video_stream_encoder_->OnBitrateUpdated(
2625 DataRate::bps(kTooLowBitrateForFrameSizeBps), DataRate::Zero(), 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002626 const int kWidth = 640;
2627 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002628
2629 // We expect the n initial frames to get dropped.
2630 int i;
2631 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002632 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002633 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002634 }
2635 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002636 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002637 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002638
2639 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002640 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002641
mflodmancc3d4422017-08-03 08:27:51 -07002642 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002643}
2644
mflodmancc3d4422017-08-03 08:27:51 -07002645TEST_F(VideoStreamEncoderTest,
2646 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002647 const int kWidth = 640;
2648 const int kHeight = 360;
Erik Språng610c7632019-03-06 15:37:33 +01002649 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kLowTargetBitrateBps),
2650 DataRate::Zero(), 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002651
2652 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002653 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002654 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason2bc68642017-02-07 07:02:22 -08002655
asaperssonfab67072017-04-04 05:51:49 -07002656 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002657 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002658 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002659
mflodmancc3d4422017-08-03 08:27:51 -07002660 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002661}
2662
mflodmancc3d4422017-08-03 08:27:51 -07002663TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002664 const int kWidth = 640;
2665 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002666 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02002667
2668 VideoEncoderConfig video_encoder_config;
2669 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
2670 // Make format different, to force recreation of encoder.
2671 video_encoder_config.video_format.parameters["foo"] = "foo";
2672 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002673 kMaxPayloadLength);
Erik Språng610c7632019-03-06 15:37:33 +01002674 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kLowTargetBitrateBps),
2675 DataRate::Zero(), 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002676
kthelgasonb83797b2017-02-14 11:57:25 -08002677 // Force quality scaler reconfiguration by resetting the source.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002678 video_stream_encoder_->SetSource(&video_source_,
2679 webrtc::DegradationPreference::BALANCED);
kthelgasonad9010c2017-02-14 00:46:51 -08002680
asaperssonfab67072017-04-04 05:51:49 -07002681 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002682 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002683 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002684
mflodmancc3d4422017-08-03 08:27:51 -07002685 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002686 fake_encoder_.SetQualityScaling(true);
2687}
2688
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002689TEST_F(VideoStreamEncoderTest, InitialFrameDropActivatesWhenBWEstimateReady) {
2690 webrtc::test::ScopedFieldTrials field_trials(
2691 "WebRTC-InitialFramedrop/Enabled/");
2692 // Reset encoder for field trials to take effect.
2693 ConfigureEncoder(video_encoder_config_.Copy());
2694 const int kTooLowBitrateForFrameSizeBps = 10000;
2695 const int kWidth = 640;
2696 const int kHeight = 360;
2697
Erik Språng610c7632019-03-06 15:37:33 +01002698 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2699 DataRate::Zero(), 0, 0);
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002700 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2701 // Frame should not be dropped.
2702 WaitForEncodedFrame(1);
2703
Erik Språng610c7632019-03-06 15:37:33 +01002704 video_stream_encoder_->OnBitrateUpdated(
2705 DataRate::bps(kTooLowBitrateForFrameSizeBps), DataRate::Zero(), 0, 0);
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002706 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
2707 // Expect to drop this frame, the wait should time out.
2708 ExpectDroppedFrame();
2709
2710 // Expect the sink_wants to specify a scaled frame.
2711 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
2712 video_stream_encoder_->Stop();
2713}
2714
mflodmancc3d4422017-08-03 08:27:51 -07002715TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002716 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2717 const int kTooSmallWidth = 10;
2718 const int kTooSmallHeight = 10;
Erik Språng610c7632019-03-06 15:37:33 +01002719 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2720 DataRate::Zero(), 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002721
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002722 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002723 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002724 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002725 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002726 VerifyNoLimitation(source.sink_wants());
2727 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2728
2729 // Trigger adapt down, too small frame, expect no change.
2730 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002731 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002732 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002733 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002734 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2735 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2736
mflodmancc3d4422017-08-03 08:27:51 -07002737 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002738}
2739
mflodmancc3d4422017-08-03 08:27:51 -07002740TEST_F(VideoStreamEncoderTest,
2741 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002742 const int kTooSmallWidth = 10;
2743 const int kTooSmallHeight = 10;
2744 const int kFpsLimit = 7;
Erik Språng610c7632019-03-06 15:37:33 +01002745 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2746 DataRate::Zero(), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002747
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002748 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002749 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002750 video_stream_encoder_->SetSource(&source,
2751 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002752 VerifyNoLimitation(source.sink_wants());
2753 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2754 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2755
2756 // Trigger adapt down, expect limited framerate.
2757 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002758 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002759 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002760 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2761 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2762 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2763 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2764
2765 // Trigger adapt down, too small frame, expect no change.
2766 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002767 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002768 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002769 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2770 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2771 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2772 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2773
mflodmancc3d4422017-08-03 08:27:51 -07002774 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002775}
2776
mflodmancc3d4422017-08-03 08:27:51 -07002777TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002778 fake_encoder_.ForceInitEncodeFailure(true);
Erik Språng610c7632019-03-06 15:37:33 +01002779 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2780 DataRate::Zero(), 0, 0);
Niels Möllerf1338562018-04-26 09:51:47 +02002781 ResetEncoder("VP8", 2, 1, 1, false);
asapersson02465b82017-04-10 01:12:52 -07002782 const int kFrameWidth = 1280;
2783 const int kFrameHeight = 720;
2784 video_source_.IncomingCapturedFrame(
2785 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002786 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002787 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002788}
2789
sprangb1ca0732017-02-01 08:38:12 -08002790// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002791TEST_F(VideoStreamEncoderTest,
2792 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
Erik Språng610c7632019-03-06 15:37:33 +01002793 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2794 DataRate::Zero(), 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002795
2796 const int kFrameWidth = 1280;
2797 const int kFrameHeight = 720;
2798 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002799 // requested by
2800 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002801 video_source_.set_adaptation_enabled(true);
2802
2803 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002804 CreateFrame(1 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002805 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002806
2807 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002808 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002809 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002810 CreateFrame(2 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002811 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002812
asaperssonfab67072017-04-04 05:51:49 -07002813 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002814 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002815 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002816 CreateFrame(3 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002817 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002818
mflodmancc3d4422017-08-03 08:27:51 -07002819 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002820}
sprangfe627f32017-03-29 08:24:59 -07002821
mflodmancc3d4422017-08-03 08:27:51 -07002822TEST_F(VideoStreamEncoderTest,
2823 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002824 const int kFrameWidth = 1280;
2825 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07002826
Erik Språng610c7632019-03-06 15:37:33 +01002827 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2828 DataRate::Zero(), 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -07002829 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002830 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002831 video_source_.set_adaptation_enabled(true);
2832
sprang4847ae62017-06-27 07:06:52 -07002833 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002834
2835 video_source_.IncomingCapturedFrame(
2836 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002837 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002838
2839 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002840 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002841
2842 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002843 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002844 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002845 video_source_.IncomingCapturedFrame(
2846 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002847 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002848 }
2849
2850 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002851 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002852 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002853 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002854 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002855 video_source_.IncomingCapturedFrame(
2856 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002857 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002858 ++num_frames_dropped;
2859 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002860 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002861 }
2862 }
2863
sprang4847ae62017-06-27 07:06:52 -07002864 // Add some slack to account for frames dropped by the frame dropper.
2865 const int kErrorMargin = 1;
2866 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002867 kErrorMargin);
2868
2869 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002870 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002871 num_frames_dropped = 0;
Åsa Persson8c1bf952018-09-13 10:42:19 +02002872 for (int i = 0; i <= max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002873 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002874 video_source_.IncomingCapturedFrame(
2875 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002876 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002877 ++num_frames_dropped;
2878 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002879 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002880 }
2881 }
sprang4847ae62017-06-27 07:06:52 -07002882 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002883 kErrorMargin);
2884
2885 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002886 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002887 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002888 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002889 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002890 video_source_.IncomingCapturedFrame(
2891 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002892 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002893 ++num_frames_dropped;
2894 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002895 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002896 }
2897 }
sprang4847ae62017-06-27 07:06:52 -07002898 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002899 kErrorMargin);
2900
2901 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002902 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002903 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002904 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002905 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002906 video_source_.IncomingCapturedFrame(
2907 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002908 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002909 ++num_frames_dropped;
2910 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002911 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002912 }
2913 }
2914 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2915
mflodmancc3d4422017-08-03 08:27:51 -07002916 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002917}
2918
mflodmancc3d4422017-08-03 08:27:51 -07002919TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002920 const int kFramerateFps = 5;
2921 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002922 const int kFrameWidth = 1280;
2923 const int kFrameHeight = 720;
2924
sprang4847ae62017-06-27 07:06:52 -07002925 // Reconfigure encoder with two temporal layers and screensharing, which will
2926 // disable frame dropping and make testing easier.
Niels Möllerf1338562018-04-26 09:51:47 +02002927 ResetEncoder("VP8", 1, 2, 1, true);
sprang4847ae62017-06-27 07:06:52 -07002928
Erik Språng610c7632019-03-06 15:37:33 +01002929 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2930 DataRate::Zero(), 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -07002931 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002932 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002933 video_source_.set_adaptation_enabled(true);
2934
sprang4847ae62017-06-27 07:06:52 -07002935 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002936
2937 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08002938 rtc::VideoSinkWants last_wants;
2939 do {
2940 last_wants = video_source_.sink_wants();
2941
sprangc5d62e22017-04-02 23:53:04 -07002942 // Insert frames to get a new fps estimate...
2943 for (int j = 0; j < kFramerateFps; ++j) {
2944 video_source_.IncomingCapturedFrame(
2945 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08002946 if (video_source_.last_sent_width()) {
2947 sink_.WaitForEncodedFrame(timestamp_ms);
2948 }
sprangc5d62e22017-04-02 23:53:04 -07002949 timestamp_ms += kFrameIntervalMs;
Yves Gerey665174f2018-06-19 15:03:05 +02002950 fake_clock_.AdvanceTimeMicros(kFrameIntervalMs *
2951 rtc::kNumMicrosecsPerMillisec);
sprangc5d62e22017-04-02 23:53:04 -07002952 }
2953 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002954 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08002955 } while (video_source_.sink_wants().max_framerate_fps <
2956 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07002957
Jonathan Yubc771b72017-12-08 17:04:29 -08002958 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07002959
mflodmancc3d4422017-08-03 08:27:51 -07002960 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002961}
asaperssonf7e294d2017-06-13 23:25:22 -07002962
mflodmancc3d4422017-08-03 08:27:51 -07002963TEST_F(VideoStreamEncoderTest,
2964 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002965 const int kWidth = 1280;
2966 const int kHeight = 720;
2967 const int64_t kFrameIntervalMs = 150;
2968 int64_t timestamp_ms = kFrameIntervalMs;
Erik Språng610c7632019-03-06 15:37:33 +01002969 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2970 DataRate::Zero(), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002971
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002972 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002973 AdaptingFrameForwarder source;
2974 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002975 video_stream_encoder_->SetSource(&source,
2976 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002977 timestamp_ms += kFrameIntervalMs;
2978 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002979 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002980 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002981 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2982 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2983 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2984
2985 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002986 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002987 timestamp_ms += kFrameIntervalMs;
2988 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002989 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002990 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2991 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2992 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2993 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2994
2995 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002996 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002997 timestamp_ms += kFrameIntervalMs;
2998 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002999 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003000 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
3001 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3002 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3003 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3004
3005 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003006 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003007 timestamp_ms += kFrameIntervalMs;
3008 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003009 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003010 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
3011 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3012 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3013 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3014
3015 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003016 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003017 timestamp_ms += kFrameIntervalMs;
3018 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003019 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003020 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
3021 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3022 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3023 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3024
3025 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07003026 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003027 timestamp_ms += kFrameIntervalMs;
3028 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003029 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003030 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
3031 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3032 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3033 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3034
3035 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07003036 video_stream_encoder_->TriggerQualityLow();
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 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
3041 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3042 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3043 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3044
3045 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07003046 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003047 timestamp_ms += kFrameIntervalMs;
3048 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003049 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003050 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
3051 rtc::VideoSinkWants last_wants = source.sink_wants();
3052 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3053 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3054 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3055
3056 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003057 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003058 timestamp_ms += kFrameIntervalMs;
3059 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003060 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003061 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
3062 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3063 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3064 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3065
3066 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07003067 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003068 timestamp_ms += kFrameIntervalMs;
3069 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003070 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003071 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
3072 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3073 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3074 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3075
3076 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07003077 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003078 timestamp_ms += kFrameIntervalMs;
3079 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003080 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003081 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3082 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3083 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3084 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3085
3086 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003087 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003088 timestamp_ms += kFrameIntervalMs;
3089 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003090 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003091 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
3092 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3093 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3094 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3095
3096 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003097 video_stream_encoder_->TriggerQualityHigh();
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(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003101 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3102 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3103 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3104 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3105
3106 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003107 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003108 timestamp_ms += kFrameIntervalMs;
3109 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003110 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003111 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
3112 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3113 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3114 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3115
3116 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003117 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003118 timestamp_ms += kFrameIntervalMs;
3119 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003120 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003121 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3122 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3123 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3124 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3125
3126 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003127 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003128 timestamp_ms += kFrameIntervalMs;
3129 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003130 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003131 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02003132 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003133 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3134 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3135 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3136
3137 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003138 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003139 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003140 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3141
mflodmancc3d4422017-08-03 08:27:51 -07003142 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003143}
3144
mflodmancc3d4422017-08-03 08:27:51 -07003145TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07003146 const int kWidth = 1280;
3147 const int kHeight = 720;
3148 const int64_t kFrameIntervalMs = 150;
3149 int64_t timestamp_ms = kFrameIntervalMs;
Erik Språng610c7632019-03-06 15:37:33 +01003150 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3151 DataRate::Zero(), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07003152
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003153 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07003154 AdaptingFrameForwarder source;
3155 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003156 video_stream_encoder_->SetSource(&source,
3157 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07003158 timestamp_ms += kFrameIntervalMs;
3159 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003160 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003161 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003162 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3163 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3164 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3165 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3166 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3167 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3168
3169 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003170 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003171 timestamp_ms += kFrameIntervalMs;
3172 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003173 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003174 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
3175 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3176 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3177 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3178 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3179 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3180 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3181
3182 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003183 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003184 timestamp_ms += kFrameIntervalMs;
3185 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003186 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003187 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
3188 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3189 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3190 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3191 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3192 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3193 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3194
3195 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003196 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003197 timestamp_ms += kFrameIntervalMs;
3198 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003199 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003200 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
3201 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3202 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3203 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3204 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3205 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3206 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3207
3208 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003209 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003210 timestamp_ms += kFrameIntervalMs;
3211 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003212 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003213 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
3214 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3215 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3216 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3217 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3218 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3219 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3220
3221 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003222 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003223 timestamp_ms += kFrameIntervalMs;
3224 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003225 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003226 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3227 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3228 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3229 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3230 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3231 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3232 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3233
3234 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003235 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003236 timestamp_ms += kFrameIntervalMs;
3237 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003238 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003239 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02003240 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003241 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3242 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3243 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3244 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3245 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3246 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3247
3248 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003249 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003250 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003251 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3252 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3253
mflodmancc3d4422017-08-03 08:27:51 -07003254 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003255}
3256
mflodmancc3d4422017-08-03 08:27:51 -07003257TEST_F(VideoStreamEncoderTest,
3258 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07003259 const int kWidth = 640;
3260 const int kHeight = 360;
3261 const int kFpsLimit = 15;
3262 const int64_t kFrameIntervalMs = 150;
3263 int64_t timestamp_ms = kFrameIntervalMs;
Erik Språng610c7632019-03-06 15:37:33 +01003264 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3265 DataRate::Zero(), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07003266
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003267 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07003268 AdaptingFrameForwarder source;
3269 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003270 video_stream_encoder_->SetSource(&source,
3271 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07003272 timestamp_ms += kFrameIntervalMs;
3273 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003274 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003275 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003276 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3277 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3278 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3279 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3280 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3281 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3282
3283 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003284 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003285 timestamp_ms += kFrameIntervalMs;
3286 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003287 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003288 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
3289 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3290 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3291 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3292 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3293 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3294 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3295
3296 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003297 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003298 timestamp_ms += kFrameIntervalMs;
3299 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003300 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003301 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
3302 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3303 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3304 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3305 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3306 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3307 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3308
3309 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003310 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003311 timestamp_ms += kFrameIntervalMs;
3312 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003313 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003314 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3315 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3316 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3317 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3318 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3319 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3320 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3321
3322 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003323 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003324 timestamp_ms += kFrameIntervalMs;
3325 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003326 WaitForEncodedFrame(timestamp_ms);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003327 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003328 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3329 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3330 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3331 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3332 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3333 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3334
3335 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003336 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003337 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003338 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3339 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3340
mflodmancc3d4422017-08-03 08:27:51 -07003341 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003342}
3343
mflodmancc3d4422017-08-03 08:27:51 -07003344TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003345 // Simulates simulcast behavior and makes highest stream resolutions divisible
3346 // by 4.
3347 class CroppingVideoStreamFactory
3348 : public VideoEncoderConfig::VideoStreamFactoryInterface {
3349 public:
3350 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
3351 int framerate)
3352 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
3353 EXPECT_GT(num_temporal_layers, 0u);
3354 EXPECT_GT(framerate, 0);
3355 }
3356
3357 private:
3358 std::vector<VideoStream> CreateEncoderStreams(
3359 int width,
3360 int height,
3361 const VideoEncoderConfig& encoder_config) override {
Yves Gerey665174f2018-06-19 15:03:05 +02003362 std::vector<VideoStream> streams = test::CreateVideoStreams(
3363 width - width % 4, height - height % 4, encoder_config);
ilnik6b826ef2017-06-16 06:53:48 -07003364 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +01003365 stream.num_temporal_layers = num_temporal_layers_;
ilnik6b826ef2017-06-16 06:53:48 -07003366 stream.max_framerate = framerate_;
3367 }
3368 return streams;
3369 }
3370
3371 const size_t num_temporal_layers_;
3372 const int framerate_;
3373 };
3374
3375 const int kFrameWidth = 1920;
3376 const int kFrameHeight = 1080;
3377 // 3/4 of 1920.
3378 const int kAdaptedFrameWidth = 1440;
3379 // 3/4 of 1080 rounded down to multiple of 4.
3380 const int kAdaptedFrameHeight = 808;
3381 const int kFramerate = 24;
3382
Erik Språng610c7632019-03-06 15:37:33 +01003383 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3384 DataRate::Zero(), 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003385 // Trigger reconfigure encoder (without resetting the entire instance).
3386 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02003387 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07003388 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3389 video_encoder_config.number_of_streams = 1;
3390 video_encoder_config.video_stream_factory =
3391 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003392 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02003393 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07003394 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003395
3396 video_source_.set_adaptation_enabled(true);
3397
3398 video_source_.IncomingCapturedFrame(
3399 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003400 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003401
3402 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003403 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003404 video_source_.IncomingCapturedFrame(
3405 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003406 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003407
mflodmancc3d4422017-08-03 08:27:51 -07003408 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003409}
3410
mflodmancc3d4422017-08-03 08:27:51 -07003411TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003412 const int kFrameWidth = 1280;
3413 const int kFrameHeight = 720;
3414 const int kLowFps = 2;
3415 const int kHighFps = 30;
3416
Erik Språng610c7632019-03-06 15:37:33 +01003417 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3418 DataRate::Zero(), 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003419
3420 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3421 max_framerate_ = kLowFps;
3422
3423 // Insert 2 seconds of 2fps video.
3424 for (int i = 0; i < kLowFps * 2; ++i) {
3425 video_source_.IncomingCapturedFrame(
3426 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3427 WaitForEncodedFrame(timestamp_ms);
3428 timestamp_ms += 1000 / kLowFps;
3429 }
3430
3431 // Make sure encoder is updated with new target.
Erik Språng610c7632019-03-06 15:37:33 +01003432 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3433 DataRate::Zero(), 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003434 video_source_.IncomingCapturedFrame(
3435 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3436 WaitForEncodedFrame(timestamp_ms);
3437 timestamp_ms += 1000 / kLowFps;
3438
3439 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3440
3441 // Insert 30fps frames for just a little more than the forced update period.
3442 const int kVcmTimerIntervalFrames =
3443 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3444 const int kFrameIntervalMs = 1000 / kHighFps;
3445 max_framerate_ = kHighFps;
3446 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3447 video_source_.IncomingCapturedFrame(
3448 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3449 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3450 // be dropped if the encoder hans't been updated with the new higher target
3451 // framerate yet, causing it to overshoot the target bitrate and then
3452 // suffering the wrath of the media optimizer.
3453 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3454 timestamp_ms += kFrameIntervalMs;
3455 }
3456
3457 // Don expect correct measurement just yet, but it should be higher than
3458 // before.
3459 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3460
mflodmancc3d4422017-08-03 08:27:51 -07003461 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003462}
3463
mflodmancc3d4422017-08-03 08:27:51 -07003464TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003465 const int kFrameWidth = 1280;
3466 const int kFrameHeight = 720;
3467 const int kTargetBitrateBps = 1000000;
3468
3469 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02003470 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
Erik Språng610c7632019-03-06 15:37:33 +01003471 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3472 DataRate::Zero(), 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -07003473 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003474
3475 // Insert a first video frame, causes another bitrate update.
3476 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3477 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3478 video_source_.IncomingCapturedFrame(
3479 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3480 WaitForEncodedFrame(timestamp_ms);
3481
3482 // Next, simulate video suspension due to pacer queue overrun.
Erik Språng610c7632019-03-06 15:37:33 +01003483 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(0), DataRate::Zero(), 0,
3484 1);
sprang4847ae62017-06-27 07:06:52 -07003485
3486 // Skip ahead until a new periodic parameter update should have occured.
3487 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3488 fake_clock_.AdvanceTimeMicros(
3489 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3490 rtc::kNumMicrosecsPerMillisec);
3491
3492 // Bitrate observer should not be called.
3493 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3494 video_source_.IncomingCapturedFrame(
3495 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3496 ExpectDroppedFrame();
3497
mflodmancc3d4422017-08-03 08:27:51 -07003498 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003499}
ilnik6b826ef2017-06-16 06:53:48 -07003500
Niels Möller4db138e2018-04-19 09:04:13 +02003501TEST_F(VideoStreamEncoderTest,
3502 DefaultCpuAdaptationThresholdsForSoftwareEncoder) {
3503 const int kFrameWidth = 1280;
3504 const int kFrameHeight = 720;
3505 const CpuOveruseOptions default_options;
Erik Språng610c7632019-03-06 15:37:33 +01003506 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3507 DataRate::Zero(), 0, 0);
Niels Möller4db138e2018-04-19 09:04:13 +02003508 video_source_.IncomingCapturedFrame(
3509 CreateFrame(1, kFrameWidth, kFrameHeight));
3510 WaitForEncodedFrame(1);
3511 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3512 .low_encode_usage_threshold_percent,
3513 default_options.low_encode_usage_threshold_percent);
3514 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3515 .high_encode_usage_threshold_percent,
3516 default_options.high_encode_usage_threshold_percent);
3517 video_stream_encoder_->Stop();
3518}
3519
3520TEST_F(VideoStreamEncoderTest,
3521 HigherCpuAdaptationThresholdsForHardwareEncoder) {
3522 const int kFrameWidth = 1280;
3523 const int kFrameHeight = 720;
3524 CpuOveruseOptions hardware_options;
3525 hardware_options.low_encode_usage_threshold_percent = 150;
3526 hardware_options.high_encode_usage_threshold_percent = 200;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +01003527 fake_encoder_.SetIsHardwareAccelerated(true);
Niels Möller4db138e2018-04-19 09:04:13 +02003528
Erik Språng610c7632019-03-06 15:37:33 +01003529 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3530 DataRate::Zero(), 0, 0);
Niels Möller4db138e2018-04-19 09:04:13 +02003531 video_source_.IncomingCapturedFrame(
3532 CreateFrame(1, kFrameWidth, kFrameHeight));
3533 WaitForEncodedFrame(1);
3534 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3535 .low_encode_usage_threshold_percent,
3536 hardware_options.low_encode_usage_threshold_percent);
3537 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3538 .high_encode_usage_threshold_percent,
3539 hardware_options.high_encode_usage_threshold_percent);
3540 video_stream_encoder_->Stop();
3541}
3542
Niels Möller6bb5ab92019-01-11 11:11:10 +01003543TEST_F(VideoStreamEncoderTest, DropsFramesWhenEncoderOvershoots) {
3544 const int kFrameWidth = 320;
3545 const int kFrameHeight = 240;
3546 const int kFps = 30;
3547 const int kTargetBitrateBps = 120000;
3548 const int kNumFramesInRun = kFps * 5; // Runs of five seconds.
3549
Erik Språng610c7632019-03-06 15:37:33 +01003550 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3551 DataRate::Zero(), 0, 0);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003552
3553 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3554 max_framerate_ = kFps;
3555
3556 // Insert 3 seconds of video, verify number of drops with normal bitrate.
3557 fake_encoder_.SimulateOvershoot(1.0);
3558 int num_dropped = 0;
3559 for (int i = 0; i < kNumFramesInRun; ++i) {
3560 video_source_.IncomingCapturedFrame(
3561 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3562 // Wait up to two frame durations for a frame to arrive.
3563 if (!TimedWaitForEncodedFrame(timestamp_ms, 2 * 1000 / kFps)) {
3564 ++num_dropped;
3565 }
3566 timestamp_ms += 1000 / kFps;
3567 }
3568
Erik Språnga8d48ab2019-02-08 14:17:40 +01003569 // Framerate should be measured to be near the expected target rate.
3570 EXPECT_NEAR(fake_encoder_.GetLastFramerate(), kFps, 1);
3571
3572 // Frame drops should be within 5% of expected 0%.
3573 EXPECT_NEAR(num_dropped, 0, 5 * kNumFramesInRun / 100);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003574
3575 // Make encoder produce frames at double the expected bitrate during 3 seconds
3576 // of video, verify number of drops. Rate needs to be slightly changed in
3577 // order to force the rate to be reconfigured.
Erik Språng7ca375c2019-02-06 16:20:17 +01003578 double overshoot_factor = 2.0;
3579 if (RateControlSettings::ParseFromFieldTrials().UseEncoderBitrateAdjuster()) {
3580 // With bitrate adjuster, when need to overshoot even more to trigger
3581 // frame dropping.
3582 overshoot_factor *= 2;
3583 }
3584 fake_encoder_.SimulateOvershoot(overshoot_factor);
Erik Språng610c7632019-03-06 15:37:33 +01003585 video_stream_encoder_->OnBitrateUpdated(
3586 DataRate::bps(kTargetBitrateBps + 1000), DataRate::Zero(), 0, 0);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003587 num_dropped = 0;
3588 for (int i = 0; i < kNumFramesInRun; ++i) {
3589 video_source_.IncomingCapturedFrame(
3590 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3591 // Wait up to two frame durations for a frame to arrive.
3592 if (!TimedWaitForEncodedFrame(timestamp_ms, 2 * 1000 / kFps)) {
3593 ++num_dropped;
3594 }
3595 timestamp_ms += 1000 / kFps;
3596 }
3597
Erik Språng610c7632019-03-06 15:37:33 +01003598 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3599 DataRate::Zero(), 0, 0);
Erik Språnga8d48ab2019-02-08 14:17:40 +01003600
3601 // Target framerate should be still be near the expected target, despite
3602 // the frame drops.
3603 EXPECT_NEAR(fake_encoder_.GetLastFramerate(), kFps, 1);
3604
3605 // Frame drops should be within 5% of expected 50%.
3606 EXPECT_NEAR(num_dropped, kNumFramesInRun / 2, 5 * kNumFramesInRun / 100);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003607
3608 video_stream_encoder_->Stop();
3609}
3610
3611TEST_F(VideoStreamEncoderTest, ConfiguresCorrectFrameRate) {
3612 const int kFrameWidth = 320;
3613 const int kFrameHeight = 240;
3614 const int kActualInputFps = 24;
3615 const int kTargetBitrateBps = 120000;
3616
3617 ASSERT_GT(max_framerate_, kActualInputFps);
3618
3619 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3620 max_framerate_ = kActualInputFps;
Erik Språng610c7632019-03-06 15:37:33 +01003621 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3622 DataRate::Zero(), 0, 0);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003623
3624 // Insert 3 seconds of video, with an input fps lower than configured max.
3625 for (int i = 0; i < kActualInputFps * 3; ++i) {
3626 video_source_.IncomingCapturedFrame(
3627 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3628 // Wait up to two frame durations for a frame to arrive.
3629 WaitForEncodedFrame(timestamp_ms);
3630 timestamp_ms += 1000 / kActualInputFps;
3631 }
3632
3633 EXPECT_NEAR(kActualInputFps, fake_encoder_.GetLastFramerate(), 1);
3634
3635 video_stream_encoder_->Stop();
3636}
3637
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01003638TEST_F(VideoStreamEncoderTest, AccumulatesUpdateRectOnDroppedFrames) {
3639 VideoFrame::UpdateRect rect;
Erik Språng610c7632019-03-06 15:37:33 +01003640 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3641 DataRate::Zero(), 0, 0);
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01003642
3643 fake_encoder_.BlockNextEncode();
3644 video_source_.IncomingCapturedFrame(
3645 CreateFrameWithUpdatedPixel(1, nullptr, 0));
3646 WaitForEncodedFrame(1);
3647 // On the very first frame full update should be forced.
3648 rect = fake_encoder_.GetLastUpdateRect();
3649 EXPECT_EQ(rect.offset_x, 0);
3650 EXPECT_EQ(rect.offset_y, 0);
3651 EXPECT_EQ(rect.height, codec_height_);
3652 EXPECT_EQ(rect.width, codec_width_);
3653 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
3654 // call to ContinueEncode.
3655 video_source_.IncomingCapturedFrame(
3656 CreateFrameWithUpdatedPixel(2, nullptr, 1));
3657 ExpectDroppedFrame();
3658 video_source_.IncomingCapturedFrame(
3659 CreateFrameWithUpdatedPixel(3, nullptr, 10));
3660 ExpectDroppedFrame();
3661 fake_encoder_.ContinueEncode();
3662 WaitForEncodedFrame(3);
3663 // Updates to pixels 1 and 10 should be accumulated to one 10x1 rect.
3664 rect = fake_encoder_.GetLastUpdateRect();
3665 EXPECT_EQ(rect.offset_x, 1);
3666 EXPECT_EQ(rect.offset_y, 0);
3667 EXPECT_EQ(rect.width, 10);
3668 EXPECT_EQ(rect.height, 1);
3669
3670 video_source_.IncomingCapturedFrame(
3671 CreateFrameWithUpdatedPixel(4, nullptr, 0));
3672 WaitForEncodedFrame(4);
3673 // Previous frame was encoded, so no accumulation should happen.
3674 rect = fake_encoder_.GetLastUpdateRect();
3675 EXPECT_EQ(rect.offset_x, 0);
3676 EXPECT_EQ(rect.offset_y, 0);
3677 EXPECT_EQ(rect.width, 1);
3678 EXPECT_EQ(rect.height, 1);
3679
3680 video_stream_encoder_->Stop();
3681}
3682
Erik Språngd7329ca2019-02-21 21:19:53 +01003683TEST_F(VideoStreamEncoderTest, SetsFrameTypes) {
Erik Språng610c7632019-03-06 15:37:33 +01003684 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3685 DataRate::Zero(), 0, 0);
Erik Språngd7329ca2019-02-21 21:19:53 +01003686
3687 // First frame is always keyframe.
3688 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
3689 WaitForEncodedFrame(1);
Niels Möller8f7ce222019-03-21 15:43:58 +01003690 EXPECT_THAT(
3691 fake_encoder_.LastFrameTypes(),
3692 testing::ElementsAre(VideoFrameType{VideoFrameType::kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003693
3694 // Insert delta frame.
3695 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
3696 WaitForEncodedFrame(2);
Niels Möller8f7ce222019-03-21 15:43:58 +01003697 EXPECT_THAT(
3698 fake_encoder_.LastFrameTypes(),
3699 testing::ElementsAre(VideoFrameType{VideoFrameType::kVideoFrameDelta}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003700
3701 // Request next frame be a key-frame.
3702 video_stream_encoder_->SendKeyFrame();
3703 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
3704 WaitForEncodedFrame(3);
Niels Möller8f7ce222019-03-21 15:43:58 +01003705 EXPECT_THAT(
3706 fake_encoder_.LastFrameTypes(),
3707 testing::ElementsAre(VideoFrameType{VideoFrameType::kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003708
3709 video_stream_encoder_->Stop();
3710}
3711
3712TEST_F(VideoStreamEncoderTest, SetsFrameTypesSimulcast) {
3713 // Setup simulcast with three streams.
3714 ResetEncoder("VP8", 3, 1, 1, false);
Erik Språng610c7632019-03-06 15:37:33 +01003715 video_stream_encoder_->OnBitrateUpdated(
3716 DataRate::bps(kSimulcastTargetBitrateBps), DataRate::Zero(), 0, 0);
Erik Språngd7329ca2019-02-21 21:19:53 +01003717 // Wait for all three layers before triggering event.
3718 sink_.SetNumExpectedLayers(3);
3719
3720 // First frame is always keyframe.
3721 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
3722 WaitForEncodedFrame(1);
3723 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
Niels Möller8f7ce222019-03-21 15:43:58 +01003724 testing::ElementsAreArray({VideoFrameType::kVideoFrameKey,
3725 VideoFrameType::kVideoFrameKey,
3726 VideoFrameType::kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003727
3728 // Insert delta frame.
3729 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
3730 WaitForEncodedFrame(2);
3731 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
Niels Möller8f7ce222019-03-21 15:43:58 +01003732 testing::ElementsAreArray({VideoFrameType::kVideoFrameDelta,
3733 VideoFrameType::kVideoFrameDelta,
3734 VideoFrameType::kVideoFrameDelta}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003735
3736 // Request next frame be a key-frame.
3737 // Only first stream is configured to produce key-frame.
3738 video_stream_encoder_->SendKeyFrame();
3739 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
3740 WaitForEncodedFrame(3);
3741 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
Niels Möller8f7ce222019-03-21 15:43:58 +01003742 testing::ElementsAreArray({VideoFrameType::kVideoFrameKey,
3743 VideoFrameType::kVideoFrameDelta,
3744 VideoFrameType::kVideoFrameDelta}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003745
3746 video_stream_encoder_->Stop();
3747}
3748
3749TEST_F(VideoStreamEncoderTest, RequestKeyframeInternalSource) {
3750 // Configure internal source factory and setup test again.
3751 encoder_factory_.SetHasInternalSource(true);
3752 ResetEncoder("VP8", 1, 1, 1, false);
Erik Språng610c7632019-03-06 15:37:33 +01003753 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3754 DataRate::Zero(), 0, 0);
Erik Språngd7329ca2019-02-21 21:19:53 +01003755
3756 // Call encoder directly, simulating internal source where encoded frame
3757 // callback in VideoStreamEncoder is called despite no OnFrame().
3758 fake_encoder_.InjectFrame(CreateFrame(1, nullptr), true);
3759 EXPECT_TRUE(WaitForFrame(kDefaultTimeoutMs));
Niels Möller8f7ce222019-03-21 15:43:58 +01003760 EXPECT_THAT(
3761 fake_encoder_.LastFrameTypes(),
3762 testing::ElementsAre(VideoFrameType{VideoFrameType::kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003763
Niels Möller8f7ce222019-03-21 15:43:58 +01003764 const std::vector<VideoFrameType> kDeltaFrame = {
3765 VideoFrameType::kVideoFrameDelta};
Erik Språngd7329ca2019-02-21 21:19:53 +01003766 // Need to set timestamp manually since manually for injected frame.
3767 VideoFrame frame = CreateFrame(101, nullptr);
3768 frame.set_timestamp(101);
3769 fake_encoder_.InjectFrame(frame, false);
3770 EXPECT_TRUE(WaitForFrame(kDefaultTimeoutMs));
Niels Möller8f7ce222019-03-21 15:43:58 +01003771 EXPECT_THAT(
3772 fake_encoder_.LastFrameTypes(),
3773 testing::ElementsAre(VideoFrameType{VideoFrameType::kVideoFrameDelta}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003774
3775 // Request key-frame. The forces a dummy frame down into the encoder.
3776 fake_encoder_.ExpectNullFrame();
3777 video_stream_encoder_->SendKeyFrame();
3778 EXPECT_TRUE(WaitForFrame(kDefaultTimeoutMs));
Niels Möller8f7ce222019-03-21 15:43:58 +01003779 EXPECT_THAT(
3780 fake_encoder_.LastFrameTypes(),
3781 testing::ElementsAre(VideoFrameType{VideoFrameType::kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003782
3783 video_stream_encoder_->Stop();
3784}
Erik Språngb7cb7b52019-02-26 15:52:33 +01003785
3786TEST_F(VideoStreamEncoderTest, AdjustsTimestampInternalSource) {
3787 // Configure internal source factory and setup test again.
3788 encoder_factory_.SetHasInternalSource(true);
3789 ResetEncoder("VP8", 1, 1, 1, false);
Erik Språng610c7632019-03-06 15:37:33 +01003790 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3791 DataRate::Zero(), 0, 0);
Erik Språngb7cb7b52019-02-26 15:52:33 +01003792
3793 int64_t timestamp = 1;
3794 EncodedImage image;
3795 image.Allocate(kTargetBitrateBps / kDefaultFramerate / 8);
3796 image.capture_time_ms_ = ++timestamp;
3797 image.SetTimestamp(static_cast<uint32_t>(timestamp * 90));
3798 const int64_t kEncodeFinishDelayMs = 10;
3799 image.timing_.encode_start_ms = timestamp;
3800 image.timing_.encode_finish_ms = timestamp + kEncodeFinishDelayMs;
3801 fake_encoder_.InjectEncodedImage(image);
3802 // Wait for frame without incrementing clock.
3803 EXPECT_TRUE(sink_.WaitForFrame(kDefaultTimeoutMs));
3804 // Frame is captured kEncodeFinishDelayMs before it's encoded, so restored
3805 // capture timestamp should be kEncodeFinishDelayMs in the past.
3806 EXPECT_EQ(sink_.GetLastCaptureTimeMs(),
3807 fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec -
3808 kEncodeFinishDelayMs);
3809
3810 video_stream_encoder_->Stop();
3811}
perkj26091b12016-09-01 01:17:40 -07003812} // namespace webrtc