blob: fba99fe8db334f03cef9e39aab037ff08ca428a4 [file] [log] [blame]
perkj26091b12016-09-01 01:17:40 -07001/*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Erik Språng4529fbc2018-10-12 10:30:31 +020011#include "video/video_stream_encoder.h"
12
sprangfe627f32017-03-29 08:24:59 -070013#include <algorithm>
perkj803d97f2016-11-01 11:45:46 -070014#include <limits>
Per512ecb32016-09-23 15:52:06 +020015#include <utility>
16
Jiawei Ouc2ebe212018-11-08 10:02:56 -080017#include "api/video/builtin_video_bitrate_allocator_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "api/video/i420_buffer.h"
Erik Språngf93eda12019-01-16 17:10:57 +010019#include "api/video/video_bitrate_allocation.h"
Erik Språng4529fbc2018-10-12 10:30:31 +020020#include "api/video_codecs/create_vp8_temporal_layers.h"
21#include "api/video_codecs/vp8_temporal_layers.h"
Steve Anton10542f22019-01-11 09:11:00 -080022#include "media/base/video_adapter.h"
Sergey Silkin86684962018-03-28 19:32:37 +020023#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
Steve Anton10542f22019-01-11 09:11:00 -080025#include "rtc_base/fake_clock.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020026#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080027#include "rtc_base/ref_counted_object.h"
Mirko Bonadei17f48782018-09-28 08:51:10 +020028#include "system_wrappers/include/metrics.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020029#include "system_wrappers/include/sleep.h"
30#include "test/encoder_settings.h"
31#include "test/fake_encoder.h"
Kári Tristan Helgason639602a2018-08-02 10:51:40 +020032#include "test/field_trial.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020033#include "test/frame_generator.h"
34#include "test/gmock.h"
35#include "test/gtest.h"
Niels Möllercbcbc222018-09-28 09:07:24 +020036#include "test/video_encoder_proxy_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020037#include "video/send_statistics_proxy.h"
perkj26091b12016-09-01 01:17:40 -070038
39namespace webrtc {
40
sprangb1ca0732017-02-01 08:38:12 -080041using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080042using ::testing::_;
43using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080044
perkj803d97f2016-11-01 11:45:46 -070045namespace {
Åsa Persson8c1bf952018-09-13 10:42:19 +020046const int kMinPixelsPerFrame = 320 * 180;
47const int kMinFramerateFps = 2;
48const int kMinBalancedFramerateFps = 7;
49const int64_t kFrameTimeoutMs = 100;
asapersson5f7226f2016-11-25 04:37:00 -080050const size_t kMaxPayloadLength = 1440;
kthelgason2bc68642017-02-07 07:02:22 -080051const int kTargetBitrateBps = 1000000;
52const int kLowTargetBitrateBps = kTargetBitrateBps / 10;
53const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070054const int kDefaultFramerate = 30;
Åsa Persson8c1bf952018-09-13 10:42:19 +020055const int64_t kFrameIntervalMs = rtc::kNumMillisecsPerSec / kDefaultFramerate;
asapersson5f7226f2016-11-25 04:37:00 -080056
perkj803d97f2016-11-01 11:45:46 -070057class TestBuffer : public webrtc::I420Buffer {
58 public:
59 TestBuffer(rtc::Event* event, int width, int height)
60 : I420Buffer(width, height), event_(event) {}
61
62 private:
63 friend class rtc::RefCountedObject<TestBuffer>;
64 ~TestBuffer() override {
65 if (event_)
66 event_->Set();
67 }
68 rtc::Event* const event_;
69};
70
Niels Möller7dc26b72017-12-06 10:27:48 +010071class CpuOveruseDetectorProxy : public OveruseFrameDetector {
72 public:
Niels Möllerd1f7eb62018-03-28 16:40:58 +020073 explicit CpuOveruseDetectorProxy(CpuOveruseMetricsObserver* metrics_observer)
74 : OveruseFrameDetector(metrics_observer),
Niels Möller7dc26b72017-12-06 10:27:48 +010075 last_target_framerate_fps_(-1) {}
76 virtual ~CpuOveruseDetectorProxy() {}
77
78 void OnTargetFramerateUpdated(int framerate_fps) override {
79 rtc::CritScope cs(&lock_);
80 last_target_framerate_fps_ = framerate_fps;
81 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
82 }
83
84 int GetLastTargetFramerate() {
85 rtc::CritScope cs(&lock_);
86 return last_target_framerate_fps_;
87 }
88
Niels Möller4db138e2018-04-19 09:04:13 +020089 CpuOveruseOptions GetOptions() { return options_; }
90
Niels Möller7dc26b72017-12-06 10:27:48 +010091 private:
92 rtc::CriticalSection lock_;
93 int last_target_framerate_fps_ RTC_GUARDED_BY(lock_);
94};
95
mflodmancc3d4422017-08-03 08:27:51 -070096class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -070097 public:
Niels Möller213618e2018-07-24 09:29:58 +020098 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
99 const VideoStreamEncoderSettings& settings)
Yves Gerey665174f2018-06-19 15:03:05 +0200100 : VideoStreamEncoder(1 /* number_of_cores */,
101 stats_proxy,
102 settings,
Yves Gerey665174f2018-06-19 15:03:05 +0200103 std::unique_ptr<OveruseFrameDetector>(
104 overuse_detector_proxy_ =
105 new CpuOveruseDetectorProxy(stats_proxy))) {}
perkj803d97f2016-11-01 11:45:46 -0700106
sprangb1ca0732017-02-01 08:38:12 -0800107 void PostTaskAndWait(bool down, AdaptReason reason) {
Niels Möllerc572ff32018-11-07 08:43:50 +0100108 rtc::Event event;
kthelgason876222f2016-11-29 01:44:11 -0800109 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800110 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700111 event.Set();
112 });
perkj070ba852017-02-16 15:46:27 -0800113 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700114 }
115
kthelgason2fc52542017-03-03 00:24:41 -0800116 // This is used as a synchronisation mechanism, to make sure that the
117 // encoder queue is not blocked before we start sending it frames.
118 void WaitUntilTaskQueueIsIdle() {
Niels Möllerc572ff32018-11-07 08:43:50 +0100119 rtc::Event event;
Yves Gerey665174f2018-06-19 15:03:05 +0200120 encoder_queue()->PostTask([&event] { event.Set(); });
kthelgason2fc52542017-03-03 00:24:41 -0800121 ASSERT_TRUE(event.Wait(5000));
122 }
123
sprangb1ca0732017-02-01 08:38:12 -0800124 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800125
sprangb1ca0732017-02-01 08:38:12 -0800126 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800127
sprangb1ca0732017-02-01 08:38:12 -0800128 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800129
sprangb1ca0732017-02-01 08:38:12 -0800130 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700131
Niels Möller7dc26b72017-12-06 10:27:48 +0100132 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700133};
134
asapersson5f7226f2016-11-25 04:37:00 -0800135class VideoStreamFactory
136 : public VideoEncoderConfig::VideoStreamFactoryInterface {
137 public:
sprangfda496a2017-06-15 04:21:07 -0700138 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
139 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800140 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700141 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800142 }
143
144 private:
145 std::vector<VideoStream> CreateEncoderStreams(
146 int width,
147 int height,
148 const VideoEncoderConfig& encoder_config) override {
149 std::vector<VideoStream> streams =
150 test::CreateVideoStreams(width, height, encoder_config);
151 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +0100152 stream.num_temporal_layers = num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700153 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800154 }
155 return streams;
156 }
sprangfda496a2017-06-15 04:21:07 -0700157
asapersson5f7226f2016-11-25 04:37:00 -0800158 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700159 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800160};
161
sprangb1ca0732017-02-01 08:38:12 -0800162class AdaptingFrameForwarder : public test::FrameForwarder {
163 public:
164 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700165 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800166
167 void set_adaptation_enabled(bool enabled) {
168 rtc::CritScope cs(&crit_);
169 adaptation_enabled_ = enabled;
170 }
171
asaperssonfab67072017-04-04 05:51:49 -0700172 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800173 rtc::CritScope cs(&crit_);
174 return adaptation_enabled_;
175 }
176
asapersson09f05612017-05-15 23:40:18 -0700177 rtc::VideoSinkWants last_wants() const {
178 rtc::CritScope cs(&crit_);
179 return last_wants_;
180 }
181
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200182 absl::optional<int> last_sent_width() const { return last_width_; }
183 absl::optional<int> last_sent_height() const { return last_height_; }
Jonathan Yubc771b72017-12-08 17:04:29 -0800184
sprangb1ca0732017-02-01 08:38:12 -0800185 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
186 int cropped_width = 0;
187 int cropped_height = 0;
188 int out_width = 0;
189 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700190 if (adaption_enabled()) {
191 if (adapter_.AdaptFrameResolution(
192 video_frame.width(), video_frame.height(),
193 video_frame.timestamp_us() * 1000, &cropped_width,
194 &cropped_height, &out_width, &out_height)) {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100195 VideoFrame adapted_frame =
196 VideoFrame::Builder()
197 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
198 nullptr, out_width, out_height))
199 .set_timestamp_rtp(99)
200 .set_timestamp_ms(99)
201 .set_rotation(kVideoRotation_0)
202 .build();
sprangc5d62e22017-04-02 23:53:04 -0700203 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
204 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800205 last_width_.emplace(adapted_frame.width());
206 last_height_.emplace(adapted_frame.height());
207 } else {
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200208 last_width_ = absl::nullopt;
209 last_height_ = absl::nullopt;
sprangc5d62e22017-04-02 23:53:04 -0700210 }
sprangb1ca0732017-02-01 08:38:12 -0800211 } else {
212 test::FrameForwarder::IncomingCapturedFrame(video_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800213 last_width_.emplace(video_frame.width());
214 last_height_.emplace(video_frame.height());
sprangb1ca0732017-02-01 08:38:12 -0800215 }
216 }
217
218 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
219 const rtc::VideoSinkWants& wants) override {
220 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700221 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700222 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
223 wants.max_pixel_count,
224 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800225 test::FrameForwarder::AddOrUpdateSink(sink, wants);
226 }
sprangb1ca0732017-02-01 08:38:12 -0800227 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700228 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
229 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200230 absl::optional<int> last_width_;
231 absl::optional<int> last_height_;
sprangb1ca0732017-02-01 08:38:12 -0800232};
sprangc5d62e22017-04-02 23:53:04 -0700233
Niels Möller213618e2018-07-24 09:29:58 +0200234// TODO(nisse): Mock only VideoStreamEncoderObserver.
sprangc5d62e22017-04-02 23:53:04 -0700235class MockableSendStatisticsProxy : public SendStatisticsProxy {
236 public:
237 MockableSendStatisticsProxy(Clock* clock,
238 const VideoSendStream::Config& config,
239 VideoEncoderConfig::ContentType content_type)
240 : SendStatisticsProxy(clock, config, content_type) {}
241
242 VideoSendStream::Stats GetStats() override {
243 rtc::CritScope cs(&lock_);
244 if (mock_stats_)
245 return *mock_stats_;
246 return SendStatisticsProxy::GetStats();
247 }
248
Niels Möller213618e2018-07-24 09:29:58 +0200249 int GetInputFrameRate() const override {
250 rtc::CritScope cs(&lock_);
251 if (mock_stats_)
252 return mock_stats_->input_frame_rate;
253 return SendStatisticsProxy::GetInputFrameRate();
254 }
sprangc5d62e22017-04-02 23:53:04 -0700255 void SetMockStats(const VideoSendStream::Stats& stats) {
256 rtc::CritScope cs(&lock_);
257 mock_stats_.emplace(stats);
258 }
259
260 void ResetMockStats() {
261 rtc::CritScope cs(&lock_);
262 mock_stats_.reset();
263 }
264
265 private:
266 rtc::CriticalSection lock_;
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200267 absl::optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700268};
269
sprang4847ae62017-06-27 07:06:52 -0700270class MockBitrateObserver : public VideoBitrateAllocationObserver {
271 public:
Erik Språng566124a2018-04-23 12:32:22 +0200272 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const VideoBitrateAllocation&));
sprang4847ae62017-06-27 07:06:52 -0700273};
274
perkj803d97f2016-11-01 11:45:46 -0700275} // namespace
276
mflodmancc3d4422017-08-03 08:27:51 -0700277class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700278 public:
279 static const int kDefaultTimeoutMs = 30 * 1000;
280
mflodmancc3d4422017-08-03 08:27:51 -0700281 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700282 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700283 codec_width_(320),
284 codec_height_(240),
Åsa Persson8c1bf952018-09-13 10:42:19 +0200285 max_framerate_(kDefaultFramerate),
perkj26091b12016-09-01 01:17:40 -0700286 fake_encoder_(),
Niels Möller4db138e2018-04-19 09:04:13 +0200287 encoder_factory_(&fake_encoder_),
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800288 bitrate_allocator_factory_(CreateBuiltinVideoBitrateAllocatorFactory()),
sprangc5d62e22017-04-02 23:53:04 -0700289 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700290 Clock::GetRealTimeClock(),
291 video_send_config_,
292 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700293 sink_(&fake_encoder_) {}
294
295 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700296 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700297 video_send_config_ = VideoSendStream::Config(nullptr);
Niels Möller4db138e2018-04-19 09:04:13 +0200298 video_send_config_.encoder_settings.encoder_factory = &encoder_factory_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800299 video_send_config_.encoder_settings.bitrate_allocator_factory =
300 bitrate_allocator_factory_.get();
Niels Möller259a4972018-04-05 15:36:51 +0200301 video_send_config_.rtp.payload_name = "FAKE";
302 video_send_config_.rtp.payload_type = 125;
perkj26091b12016-09-01 01:17:40 -0700303
Per512ecb32016-09-23 15:52:06 +0200304 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200305 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700306 video_encoder_config.video_stream_factory =
307 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100308 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700309
310 // Framerate limit is specified by the VideoStreamFactory.
311 std::vector<VideoStream> streams =
312 video_encoder_config.video_stream_factory->CreateEncoderStreams(
313 codec_width_, codec_height_, video_encoder_config);
314 max_framerate_ = streams[0].max_framerate;
315 fake_clock_.SetTimeMicros(1234);
316
Niels Möllerf1338562018-04-26 09:51:47 +0200317 ConfigureEncoder(std::move(video_encoder_config));
asapersson5f7226f2016-11-25 04:37:00 -0800318 }
319
Niels Möllerf1338562018-04-26 09:51:47 +0200320 void ConfigureEncoder(VideoEncoderConfig video_encoder_config) {
mflodmancc3d4422017-08-03 08:27:51 -0700321 if (video_stream_encoder_)
322 video_stream_encoder_->Stop();
323 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700324 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700325 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
326 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700327 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -0700328 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
329 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200330 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -0700331 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800332 }
333
334 void ResetEncoder(const std::string& payload_name,
335 size_t num_streams,
336 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700337 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700338 bool screenshare) {
Niels Möller259a4972018-04-05 15:36:51 +0200339 video_send_config_.rtp.payload_name = payload_name;
asapersson5f7226f2016-11-25 04:37:00 -0800340
341 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200342 video_encoder_config.codec_type = PayloadStringToCodecType(payload_name);
asapersson5f7226f2016-11-25 04:37:00 -0800343 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800344 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800345 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700346 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
347 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700348 video_encoder_config.content_type =
349 screenshare ? VideoEncoderConfig::ContentType::kScreen
350 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700351 if (payload_name == "VP9") {
352 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
353 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
354 video_encoder_config.encoder_specific_settings =
355 new rtc::RefCountedObject<
356 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
357 }
Niels Möllerf1338562018-04-26 09:51:47 +0200358 ConfigureEncoder(std::move(video_encoder_config));
perkj26091b12016-09-01 01:17:40 -0700359 }
360
sprang57c2fff2017-01-16 06:24:02 -0800361 VideoFrame CreateFrame(int64_t ntp_time_ms,
362 rtc::Event* destruction_event) const {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100363 VideoFrame frame =
364 VideoFrame::Builder()
365 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
366 destruction_event, codec_width_, codec_height_))
367 .set_timestamp_rtp(99)
368 .set_timestamp_ms(99)
369 .set_rotation(kVideoRotation_0)
370 .build();
sprang57c2fff2017-01-16 06:24:02 -0800371 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700372 return frame;
373 }
374
sprang57c2fff2017-01-16 06:24:02 -0800375 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100376 VideoFrame frame =
377 VideoFrame::Builder()
378 .set_video_frame_buffer(
379 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height))
380 .set_timestamp_rtp(99)
381 .set_timestamp_ms(99)
382 .set_rotation(kVideoRotation_0)
383 .build();
sprang57c2fff2017-01-16 06:24:02 -0800384 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700385 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700386 return frame;
387 }
388
asapersson02465b82017-04-10 01:12:52 -0700389 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700390 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700391 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
392 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700393 }
394
asapersson09f05612017-05-15 23:40:18 -0700395 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
396 const rtc::VideoSinkWants& wants2) {
397 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
398 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
399 }
400
Åsa Persson8c1bf952018-09-13 10:42:19 +0200401 void VerifyFpsMaxResolutionMax(const rtc::VideoSinkWants& wants) {
402 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
403 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
404 EXPECT_FALSE(wants.target_pixel_count);
405 }
406
asapersson09f05612017-05-15 23:40:18 -0700407 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
408 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200409 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700410 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
411 EXPECT_GT(wants1.max_pixel_count, 0);
412 }
413
414 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
415 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200416 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700417 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
418 }
419
asaperssonf7e294d2017-06-13 23:25:22 -0700420 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
421 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200422 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700423 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
424 }
425
426 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
427 const rtc::VideoSinkWants& wants2) {
428 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
429 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
430 }
431
432 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
433 const rtc::VideoSinkWants& wants2) {
434 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
435 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
436 }
437
438 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
439 const rtc::VideoSinkWants& wants2) {
440 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
441 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
442 EXPECT_GT(wants1.max_pixel_count, 0);
443 }
444
445 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
446 const rtc::VideoSinkWants& wants2) {
447 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
448 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
449 }
450
asapersson09f05612017-05-15 23:40:18 -0700451 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
452 int pixel_count) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200453 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700454 EXPECT_LT(wants.max_pixel_count, pixel_count);
455 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700456 }
457
458 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
459 EXPECT_LT(wants.max_framerate_fps, fps);
460 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
461 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700462 }
463
asaperssonf7e294d2017-06-13 23:25:22 -0700464 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
465 int expected_fps) {
466 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
467 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
468 EXPECT_FALSE(wants.target_pixel_count);
469 }
470
Jonathan Yubc771b72017-12-08 17:04:29 -0800471 void VerifyBalancedModeFpsRange(const rtc::VideoSinkWants& wants,
472 int last_frame_pixels) {
473 // Balanced mode should always scale FPS to the desired range before
474 // attempting to scale resolution.
475 int fps_limit = wants.max_framerate_fps;
476 if (last_frame_pixels <= 320 * 240) {
477 EXPECT_TRUE(7 <= fps_limit && fps_limit <= 10);
478 } else if (last_frame_pixels <= 480 * 270) {
479 EXPECT_TRUE(10 <= fps_limit && fps_limit <= 15);
480 } else if (last_frame_pixels <= 640 * 480) {
481 EXPECT_LE(15, fps_limit);
482 } else {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200483 EXPECT_EQ(kDefaultFramerate, fps_limit);
Jonathan Yubc771b72017-12-08 17:04:29 -0800484 }
485 }
486
sprang4847ae62017-06-27 07:06:52 -0700487 void WaitForEncodedFrame(int64_t expected_ntp_time) {
488 sink_.WaitForEncodedFrame(expected_ntp_time);
489 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
490 }
491
492 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
493 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
494 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
495 return ok;
496 }
497
498 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
499 sink_.WaitForEncodedFrame(expected_width, expected_height);
500 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
501 }
502
503 void ExpectDroppedFrame() {
504 sink_.ExpectDroppedFrame();
505 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
506 }
507
508 bool WaitForFrame(int64_t timeout_ms) {
509 bool ok = sink_.WaitForFrame(timeout_ms);
510 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
511 return ok;
512 }
513
perkj26091b12016-09-01 01:17:40 -0700514 class TestEncoder : public test::FakeEncoder {
515 public:
Niels Möllerc572ff32018-11-07 08:43:50 +0100516 TestEncoder() : FakeEncoder(Clock::GetRealTimeClock()) {}
perkj26091b12016-09-01 01:17:40 -0700517
asaperssonfab67072017-04-04 05:51:49 -0700518 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800519 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700520 return config_;
521 }
522
523 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800524 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700525 block_next_encode_ = true;
526 }
527
Erik Språngaed30702018-11-05 12:57:17 +0100528 VideoEncoder::EncoderInfo GetEncoderInfo() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800529 rtc::CritScope lock(&local_crit_sect_);
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100530 EncoderInfo info;
531 if (initialized_) {
532 if (quality_scaling_) {
533 info.scaling_settings =
534 VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
535 }
536 info.is_hardware_accelerated = is_hardware_accelerated_;
Erik Språngaed30702018-11-05 12:57:17 +0100537 }
538 return info;
kthelgason876222f2016-11-29 01:44:11 -0800539 }
540
perkjfa10b552016-10-02 23:45:26 -0700541 void ContinueEncode() { continue_encode_event_.Set(); }
542
543 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
544 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800545 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700546 EXPECT_EQ(timestamp_, timestamp);
547 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
548 }
549
kthelgason2fc52542017-03-03 00:24:41 -0800550 void SetQualityScaling(bool b) {
551 rtc::CritScope lock(&local_crit_sect_);
552 quality_scaling_ = b;
553 }
kthelgasonad9010c2017-02-14 00:46:51 -0800554
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100555 void SetIsHardwareAccelerated(bool is_hardware_accelerated) {
556 rtc::CritScope lock(&local_crit_sect_);
557 is_hardware_accelerated_ = is_hardware_accelerated;
558 }
559
sprangfe627f32017-03-29 08:24:59 -0700560 void ForceInitEncodeFailure(bool force_failure) {
561 rtc::CritScope lock(&local_crit_sect_);
562 force_init_encode_failed_ = force_failure;
563 }
564
Niels Möller6bb5ab92019-01-11 11:11:10 +0100565 void SimulateOvershoot(double rate_factor) {
566 rtc::CritScope lock(&local_crit_sect_);
567 rate_factor_ = rate_factor;
568 }
569
570 uint32_t GetLastFramerate() {
571 rtc::CritScope lock(&local_crit_sect_);
572 return last_framerate_;
573 }
574
perkjfa10b552016-10-02 23:45:26 -0700575 private:
perkj26091b12016-09-01 01:17:40 -0700576 int32_t Encode(const VideoFrame& input_image,
577 const CodecSpecificInfo* codec_specific_info,
578 const std::vector<FrameType>* frame_types) override {
579 bool block_encode;
580 {
brandtre78d2662017-01-16 05:57:16 -0800581 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700582 EXPECT_GT(input_image.timestamp(), timestamp_);
583 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
584 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
585
586 timestamp_ = input_image.timestamp();
587 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700588 last_input_width_ = input_image.width();
589 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700590 block_encode = block_next_encode_;
591 block_next_encode_ = false;
592 }
593 int32_t result =
594 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
595 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700596 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700597 return result;
598 }
599
sprangfe627f32017-03-29 08:24:59 -0700600 int32_t InitEncode(const VideoCodec* config,
601 int32_t number_of_cores,
602 size_t max_payload_size) override {
603 int res =
604 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
605 rtc::CritScope lock(&local_crit_sect_);
Erik Språng82fad3d2018-03-21 09:57:23 +0100606 if (config->codecType == kVideoCodecVP8) {
sprangfe627f32017-03-29 08:24:59 -0700607 // Simulate setting up temporal layers, in order to validate the life
608 // cycle of these objects.
609 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
sprangfe627f32017-03-29 08:24:59 -0700610 for (int i = 0; i < num_streams; ++i) {
611 allocated_temporal_layers_.emplace_back(
Erik Språng4529fbc2018-10-12 10:30:31 +0200612 CreateVp8TemporalLayers(Vp8TemporalLayersType::kFixedPattern,
613 config->VP8().numberOfTemporalLayers));
sprangfe627f32017-03-29 08:24:59 -0700614 }
615 }
616 if (force_init_encode_failed_)
617 return -1;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100618
619 initialized_ = true;
sprangfe627f32017-03-29 08:24:59 -0700620 return res;
621 }
622
Niels Möller6bb5ab92019-01-11 11:11:10 +0100623 int32_t SetRateAllocation(const VideoBitrateAllocation& rate_allocation,
624 uint32_t framerate) {
625 rtc::CritScope lock(&local_crit_sect_);
626 VideoBitrateAllocation adjusted_rate_allocation;
627 for (size_t si = 0; si < kMaxSpatialLayers; ++si) {
628 for (size_t ti = 0; ti < kMaxTemporalStreams; ++ti) {
629 if (rate_allocation.HasBitrate(si, ti)) {
630 adjusted_rate_allocation.SetBitrate(
631 si, ti,
632 static_cast<uint32_t>(rate_allocation.GetBitrate(si, ti) *
633 rate_factor_));
634 }
635 }
636 }
637 last_framerate_ = framerate;
638 return FakeEncoder::SetRateAllocation(adjusted_rate_allocation,
639 framerate);
640 }
641
brandtre78d2662017-01-16 05:57:16 -0800642 rtc::CriticalSection local_crit_sect_;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100643 bool initialized_ RTC_GUARDED_BY(local_crit_sect_) = false;
danilchapa37de392017-09-09 04:17:22 -0700644 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700645 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700646 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
647 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
648 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
649 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
650 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100651 bool is_hardware_accelerated_ RTC_GUARDED_BY(local_crit_sect_) = false;
Erik Språng4529fbc2018-10-12 10:30:31 +0200652 std::vector<std::unique_ptr<Vp8TemporalLayers>> allocated_temporal_layers_
danilchapa37de392017-09-09 04:17:22 -0700653 RTC_GUARDED_BY(local_crit_sect_);
654 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
Niels Möller6bb5ab92019-01-11 11:11:10 +0100655 double rate_factor_ RTC_GUARDED_BY(local_crit_sect_) = 1.0;
656 uint32_t last_framerate_ RTC_GUARDED_BY(local_crit_sect_) = 0;
perkj26091b12016-09-01 01:17:40 -0700657 };
658
mflodmancc3d4422017-08-03 08:27:51 -0700659 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700660 public:
661 explicit TestSink(TestEncoder* test_encoder)
Niels Möllerc572ff32018-11-07 08:43:50 +0100662 : test_encoder_(test_encoder) {}
perkj26091b12016-09-01 01:17:40 -0700663
perkj26091b12016-09-01 01:17:40 -0700664 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700665 EXPECT_TRUE(
666 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
667 }
668
669 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
670 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700671 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700672 if (!encoded_frame_event_.Wait(timeout_ms))
673 return false;
perkj26091b12016-09-01 01:17:40 -0700674 {
675 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800676 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700677 }
678 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700679 return true;
perkj26091b12016-09-01 01:17:40 -0700680 }
681
sprangb1ca0732017-02-01 08:38:12 -0800682 void WaitForEncodedFrame(uint32_t expected_width,
683 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700684 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100685 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700686 }
687
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100688 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700689 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800690 uint32_t width = 0;
691 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800692 {
693 rtc::CritScope lock(&crit_);
694 width = last_width_;
695 height = last_height_;
696 }
697 EXPECT_EQ(expected_height, height);
698 EXPECT_EQ(expected_width, width);
699 }
700
kthelgason2fc52542017-03-03 00:24:41 -0800701 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800702
sprangc5d62e22017-04-02 23:53:04 -0700703 bool WaitForFrame(int64_t timeout_ms) {
704 return encoded_frame_event_.Wait(timeout_ms);
705 }
706
perkj26091b12016-09-01 01:17:40 -0700707 void SetExpectNoFrames() {
708 rtc::CritScope lock(&crit_);
709 expect_frames_ = false;
710 }
711
asaperssonfab67072017-04-04 05:51:49 -0700712 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200713 rtc::CritScope lock(&crit_);
714 return number_of_reconfigurations_;
715 }
716
asaperssonfab67072017-04-04 05:51:49 -0700717 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200718 rtc::CritScope lock(&crit_);
719 return min_transmit_bitrate_bps_;
720 }
721
perkj26091b12016-09-01 01:17:40 -0700722 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700723 Result OnEncodedImage(
724 const EncodedImage& encoded_image,
725 const CodecSpecificInfo* codec_specific_info,
726 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200727 rtc::CritScope lock(&crit_);
728 EXPECT_TRUE(expect_frames_);
Niels Möller23775882018-08-16 10:24:12 +0200729 last_timestamp_ = encoded_image.Timestamp();
sprangb1ca0732017-02-01 08:38:12 -0800730 last_width_ = encoded_image._encodedWidth;
731 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200732 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800733 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200734 }
735
Rasmus Brandtc402dbe2019-02-04 11:09:46 +0100736 void OnEncoderConfigurationChanged(
737 std::vector<VideoStream> streams,
738 VideoEncoderConfig::ContentType content_type,
739 int min_transmit_bitrate_bps) override {
Per512ecb32016-09-23 15:52:06 +0200740 rtc::CriticalSection crit_;
741 ++number_of_reconfigurations_;
742 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
743 }
744
perkj26091b12016-09-01 01:17:40 -0700745 rtc::CriticalSection crit_;
746 TestEncoder* test_encoder_;
747 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800748 uint32_t last_timestamp_ = 0;
749 uint32_t last_height_ = 0;
750 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700751 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200752 int number_of_reconfigurations_ = 0;
753 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700754 };
755
756 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100757 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200758 int codec_width_;
759 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700760 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700761 TestEncoder fake_encoder_;
Niels Möllercbcbc222018-09-28 09:07:24 +0200762 test::VideoEncoderProxyFactory encoder_factory_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800763 std::unique_ptr<VideoBitrateAllocatorFactory> bitrate_allocator_factory_;
sprangc5d62e22017-04-02 23:53:04 -0700764 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700765 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800766 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700767 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700768 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700769};
770
mflodmancc3d4422017-08-03 08:27:51 -0700771TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
772 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Niels Möllerc572ff32018-11-07 08:43:50 +0100773 rtc::Event frame_destroyed_event;
perkja49cbd32016-09-16 07:53:41 -0700774 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700775 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700776 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700777 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700778}
779
mflodmancc3d4422017-08-03 08:27:51 -0700780TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700781 // Dropped since no target bitrate has been set.
Niels Möllerc572ff32018-11-07 08:43:50 +0100782 rtc::Event frame_destroyed_event;
Sebastian Janssona3177052018-04-10 13:05:49 +0200783 // The encoder will cache up to one frame for a short duration. Adding two
784 // frames means that the first frame will be dropped and the second frame will
785 // be sent when the encoder is enabled.
perkja49cbd32016-09-16 07:53:41 -0700786 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
Sebastian Janssona3177052018-04-10 13:05:49 +0200787 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkja49cbd32016-09-16 07:53:41 -0700788 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700789
mflodmancc3d4422017-08-03 08:27:51 -0700790 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700791
Sebastian Janssona3177052018-04-10 13:05:49 +0200792 // The pending frame should be received.
sprang4847ae62017-06-27 07:06:52 -0700793 WaitForEncodedFrame(2);
Sebastian Janssona3177052018-04-10 13:05:49 +0200794 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
795
796 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700797 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700798}
799
mflodmancc3d4422017-08-03 08:27:51 -0700800TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
801 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700802 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700803 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700804
mflodmancc3d4422017-08-03 08:27:51 -0700805 video_stream_encoder_->OnBitrateUpdated(0, 0, 0);
Sebastian Janssona3177052018-04-10 13:05:49 +0200806 // The encoder will cache up to one frame for a short duration. Adding two
807 // frames means that the first frame will be dropped and the second frame will
808 // be sent when the encoder is resumed.
perkja49cbd32016-09-16 07:53:41 -0700809 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Sebastian Janssona3177052018-04-10 13:05:49 +0200810 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700811
mflodmancc3d4422017-08-03 08:27:51 -0700812 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -0700813 WaitForEncodedFrame(3);
Sebastian Janssona3177052018-04-10 13:05:49 +0200814 video_source_.IncomingCapturedFrame(CreateFrame(4, nullptr));
815 WaitForEncodedFrame(4);
mflodmancc3d4422017-08-03 08:27:51 -0700816 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700817}
818
mflodmancc3d4422017-08-03 08:27:51 -0700819TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
820 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700821 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700822 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700823
824 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700825 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700826
perkja49cbd32016-09-16 07:53:41 -0700827 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700828 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700829 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700830}
831
mflodmancc3d4422017-08-03 08:27:51 -0700832TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
833 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700834
perkja49cbd32016-09-16 07:53:41 -0700835 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700836 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700837
mflodmancc3d4422017-08-03 08:27:51 -0700838 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700839 sink_.SetExpectNoFrames();
Niels Möllerc572ff32018-11-07 08:43:50 +0100840 rtc::Event frame_destroyed_event;
perkja49cbd32016-09-16 07:53:41 -0700841 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
842 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700843}
844
mflodmancc3d4422017-08-03 08:27:51 -0700845TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
846 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700847
848 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700849 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700850 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700851 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
852 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700853 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
854 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700855 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700856 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700857
mflodmancc3d4422017-08-03 08:27:51 -0700858 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700859}
860
mflodmancc3d4422017-08-03 08:27:51 -0700861TEST_F(VideoStreamEncoderTest,
862 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
863 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100864 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200865
866 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200867 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700868 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100869 // The encoder will have been configured once when the first frame is
870 // received.
871 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200872
873 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200874 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200875 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -0700876 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200877 kMaxPayloadLength);
Per512ecb32016-09-23 15:52:06 +0200878
879 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200880 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700881 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100882 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700883 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700884
mflodmancc3d4422017-08-03 08:27:51 -0700885 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -0700886}
887
mflodmancc3d4422017-08-03 08:27:51 -0700888TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
889 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkjfa10b552016-10-02 23:45:26 -0700890
891 // Capture a frame and wait for it to synchronize with the encoder thread.
892 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700893 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100894 // The encoder will have been configured once.
895 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700896 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
897 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
898
899 codec_width_ *= 2;
900 codec_height_ *= 2;
901 // Capture a frame with a higher resolution and wait for it to synchronize
902 // with the encoder thread.
903 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700904 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700905 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
906 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100907 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700908
mflodmancc3d4422017-08-03 08:27:51 -0700909 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -0700910}
911
mflodmancc3d4422017-08-03 08:27:51 -0700912TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -0700913 EXPECT_TRUE(video_source_.has_sinks());
914 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700915 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700916 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -0700917 EXPECT_FALSE(video_source_.has_sinks());
918 EXPECT_TRUE(new_video_source.has_sinks());
919
mflodmancc3d4422017-08-03 08:27:51 -0700920 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700921}
922
mflodmancc3d4422017-08-03 08:27:51 -0700923TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -0700924 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700925 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -0700926 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700927 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700928}
929
Jonathan Yubc771b72017-12-08 17:04:29 -0800930TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
931 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -0700932 const int kWidth = 1280;
933 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -0800934
935 // We rely on the automatic resolution adaptation, but we handle framerate
936 // adaptation manually by mocking the stats proxy.
937 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -0700938
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700939 // Enable BALANCED preference, no initial limitation.
Jonathan Yubc771b72017-12-08 17:04:29 -0800940 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700941 video_stream_encoder_->SetSource(&video_source_,
942 webrtc::DegradationPreference::BALANCED);
Jonathan Yubc771b72017-12-08 17:04:29 -0800943 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -0700944 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800945 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -0700946 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
947
Jonathan Yubc771b72017-12-08 17:04:29 -0800948 // Adapt down as far as possible.
949 rtc::VideoSinkWants last_wants;
950 int64_t t = 1;
951 int loop_count = 0;
952 do {
953 ++loop_count;
954 last_wants = video_source_.sink_wants();
955
956 // Simulate the framerate we've been asked to adapt to.
957 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
958 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
959 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
960 mock_stats.input_frame_rate = fps;
961 stats_proxy_->SetMockStats(mock_stats);
962
963 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
964 sink_.WaitForEncodedFrame(t);
965 t += frame_interval_ms;
966
mflodmancc3d4422017-08-03 08:27:51 -0700967 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -0800968 VerifyBalancedModeFpsRange(
969 video_source_.sink_wants(),
970 *video_source_.last_sent_width() * *video_source_.last_sent_height());
971 } while (video_source_.sink_wants().max_pixel_count <
972 last_wants.max_pixel_count ||
973 video_source_.sink_wants().max_framerate_fps <
974 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700975
Jonathan Yubc771b72017-12-08 17:04:29 -0800976 // Verify that we've adapted all the way down.
977 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700978 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800979 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
980 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -0700981 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -0800982 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
983 *video_source_.last_sent_height());
984 EXPECT_EQ(kMinBalancedFramerateFps,
985 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700986
Jonathan Yubc771b72017-12-08 17:04:29 -0800987 // Adapt back up the same number of times we adapted down.
988 for (int i = 0; i < loop_count - 1; ++i) {
989 last_wants = video_source_.sink_wants();
990
991 // Simulate the framerate we've been asked to adapt to.
992 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
993 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
994 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
995 mock_stats.input_frame_rate = fps;
996 stats_proxy_->SetMockStats(mock_stats);
997
998 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
999 sink_.WaitForEncodedFrame(t);
1000 t += frame_interval_ms;
1001
mflodmancc3d4422017-08-03 08:27:51 -07001002 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -08001003 VerifyBalancedModeFpsRange(
1004 video_source_.sink_wants(),
1005 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1006 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
1007 last_wants.max_pixel_count ||
1008 video_source_.sink_wants().max_framerate_fps >
1009 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001010 }
1011
Åsa Persson8c1bf952018-09-13 10:42:19 +02001012 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001013 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001014 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001015 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1016 EXPECT_EQ((loop_count - 1) * 2,
1017 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -07001018
mflodmancc3d4422017-08-03 08:27:51 -07001019 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001020}
mflodmancc3d4422017-08-03 08:27:51 -07001021TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
1022 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001023 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001024
sprangc5d62e22017-04-02 23:53:04 -07001025 const int kFrameWidth = 1280;
1026 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07001027
Åsa Persson8c1bf952018-09-13 10:42:19 +02001028 int64_t frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -07001029
kthelgason5e13d412016-12-01 03:59:51 -08001030 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001031 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001032 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001033 frame_timestamp += kFrameIntervalMs;
1034
perkj803d97f2016-11-01 11:45:46 -07001035 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001036 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001037 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001038 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001039 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001040 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -07001041
asapersson0944a802017-04-07 00:57:58 -07001042 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -07001043 // wanted resolution.
1044 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
1045 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
1046 kFrameWidth * kFrameHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001047 EXPECT_EQ(kDefaultFramerate, video_source_.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001048
1049 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -07001050 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001051 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001052 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001053
sprangc5d62e22017-04-02 23:53:04 -07001054 // Initially no degradation registered.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001055 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001056
sprangc5d62e22017-04-02 23:53:04 -07001057 // Force an input frame rate to be available, or the adaptation call won't
1058 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -07001059 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -07001060 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -07001061 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -07001062 stats_proxy_->SetMockStats(stats);
1063
mflodmancc3d4422017-08-03 08:27:51 -07001064 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001065 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001066 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001067 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001068 frame_timestamp += kFrameIntervalMs;
1069
1070 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001071 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001072 EXPECT_EQ(std::numeric_limits<int>::max(),
1073 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001074 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001075
asapersson02465b82017-04-10 01:12:52 -07001076 // Turn off degradation completely.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001077 video_stream_encoder_->SetSource(&new_video_source,
1078 webrtc::DegradationPreference::DISABLED);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001079 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001080
mflodmancc3d4422017-08-03 08:27:51 -07001081 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001082 new_video_source.IncomingCapturedFrame(
1083 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001084 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001085 frame_timestamp += kFrameIntervalMs;
1086
1087 // Still no degradation.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001088 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001089
1090 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001091 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001092 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
sprangc5d62e22017-04-02 23:53:04 -07001093 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1094 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001095 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001096 EXPECT_EQ(kDefaultFramerate, new_video_source.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001097
1098 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001099 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001100 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001101 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1102 EXPECT_EQ(std::numeric_limits<int>::max(),
1103 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001104 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001105
mflodmancc3d4422017-08-03 08:27:51 -07001106 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001107}
1108
mflodmancc3d4422017-08-03 08:27:51 -07001109TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
1110 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001111
asaperssonfab67072017-04-04 05:51:49 -07001112 const int kWidth = 1280;
1113 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001114 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001115 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001116 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1117 EXPECT_FALSE(stats.bw_limited_resolution);
1118 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1119
1120 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001121 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001122 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001123 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001124
1125 stats = stats_proxy_->GetStats();
1126 EXPECT_TRUE(stats.bw_limited_resolution);
1127 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1128
1129 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001130 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001131 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001132 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001133
1134 stats = stats_proxy_->GetStats();
1135 EXPECT_FALSE(stats.bw_limited_resolution);
1136 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1137 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1138
mflodmancc3d4422017-08-03 08:27:51 -07001139 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001140}
1141
mflodmancc3d4422017-08-03 08:27:51 -07001142TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
1143 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001144
1145 const int kWidth = 1280;
1146 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001147 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001148 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001149 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1150 EXPECT_FALSE(stats.cpu_limited_resolution);
1151 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1152
1153 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001154 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001155 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001156 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001157
1158 stats = stats_proxy_->GetStats();
1159 EXPECT_TRUE(stats.cpu_limited_resolution);
1160 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1161
1162 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001163 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001164 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001165 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001166
1167 stats = stats_proxy_->GetStats();
1168 EXPECT_FALSE(stats.cpu_limited_resolution);
1169 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001170 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001171
mflodmancc3d4422017-08-03 08:27:51 -07001172 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001173}
1174
mflodmancc3d4422017-08-03 08:27:51 -07001175TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
1176 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001177
asaperssonfab67072017-04-04 05:51:49 -07001178 const int kWidth = 1280;
1179 const int kHeight = 720;
1180 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001181 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001182 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001183 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001184 EXPECT_FALSE(stats.cpu_limited_resolution);
1185 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1186
asaperssonfab67072017-04-04 05:51:49 -07001187 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001188 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001189 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001190 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001191 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001192 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001193 EXPECT_TRUE(stats.cpu_limited_resolution);
1194 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1195
1196 // Set new source with adaptation still enabled.
1197 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001198 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001199 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001200
asaperssonfab67072017-04-04 05:51:49 -07001201 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001202 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001203 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001204 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001205 EXPECT_TRUE(stats.cpu_limited_resolution);
1206 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1207
1208 // Set adaptation disabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001209 video_stream_encoder_->SetSource(&new_video_source,
1210 webrtc::DegradationPreference::DISABLED);
kthelgason876222f2016-11-29 01:44:11 -08001211
asaperssonfab67072017-04-04 05:51:49 -07001212 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001213 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001214 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001215 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001216 EXPECT_FALSE(stats.cpu_limited_resolution);
1217 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1218
1219 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001220 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001221 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001222
asaperssonfab67072017-04-04 05:51:49 -07001223 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001224 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001225 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001226 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001227 EXPECT_TRUE(stats.cpu_limited_resolution);
1228 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1229
asaperssonfab67072017-04-04 05:51:49 -07001230 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001231 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001232 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001233 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001234 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001235 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001236 EXPECT_FALSE(stats.cpu_limited_resolution);
1237 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001238 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001239
mflodmancc3d4422017-08-03 08:27:51 -07001240 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001241}
1242
mflodmancc3d4422017-08-03 08:27:51 -07001243TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
1244 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001245
asaperssonfab67072017-04-04 05:51:49 -07001246 const int kWidth = 1280;
1247 const int kHeight = 720;
1248 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001249 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001250 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001251 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001252 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001253 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001254
1255 // Set new source with adaptation still enabled.
1256 test::FrameForwarder new_video_source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001257 video_stream_encoder_->SetSource(&new_video_source,
1258 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001259
asaperssonfab67072017-04-04 05:51:49 -07001260 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001261 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001262 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001263 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001264 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001265 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001266
asaperssonfab67072017-04-04 05:51:49 -07001267 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001268 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001269 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001270 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001271 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001272 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001273 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001274 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001275
asaperssonfab67072017-04-04 05:51:49 -07001276 // Set new source with adaptation still enabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001277 video_stream_encoder_->SetSource(&new_video_source,
1278 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001279
asaperssonfab67072017-04-04 05:51:49 -07001280 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001281 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001282 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001283 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001284 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001285 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001286
asapersson02465b82017-04-10 01:12:52 -07001287 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001288 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001289 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001290
asaperssonfab67072017-04-04 05:51:49 -07001291 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001292 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001293 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001294 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001295 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001296 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1297 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001298
mflodmancc3d4422017-08-03 08:27:51 -07001299 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001300}
1301
mflodmancc3d4422017-08-03 08:27:51 -07001302TEST_F(VideoStreamEncoderTest,
1303 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1304 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001305
1306 const int kWidth = 1280;
1307 const int kHeight = 720;
Åsa Persson8c1bf952018-09-13 10:42:19 +02001308 int64_t timestamp_ms = kFrameIntervalMs;
asapersson36e9eb42017-03-31 05:29:12 -07001309 video_source_.set_adaptation_enabled(true);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001310 video_source_.IncomingCapturedFrame(
1311 CreateFrame(timestamp_ms, kWidth, kHeight));
1312 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001313 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1314 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1315 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1316
1317 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001318 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001319 timestamp_ms += kFrameIntervalMs;
1320 video_source_.IncomingCapturedFrame(
1321 CreateFrame(timestamp_ms, kWidth, kHeight));
1322 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001323 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1324 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1325 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1326
1327 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001328 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001329 timestamp_ms += kFrameIntervalMs;
1330 video_source_.IncomingCapturedFrame(
1331 CreateFrame(timestamp_ms, kWidth, kHeight));
1332 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001333 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1334 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1335 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1336
Niels Möller4db138e2018-04-19 09:04:13 +02001337 // Leave source unchanged, but disable quality scaler.
asapersson36e9eb42017-03-31 05:29:12 -07001338 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02001339
1340 VideoEncoderConfig video_encoder_config;
1341 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
1342 // Make format different, to force recreation of encoder.
1343 video_encoder_config.video_format.parameters["foo"] = "foo";
1344 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001345 kMaxPayloadLength);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001346 timestamp_ms += kFrameIntervalMs;
1347 video_source_.IncomingCapturedFrame(
1348 CreateFrame(timestamp_ms, kWidth, kHeight));
1349 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001350 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1351 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1352 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1353
mflodmancc3d4422017-08-03 08:27:51 -07001354 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001355}
1356
mflodmancc3d4422017-08-03 08:27:51 -07001357TEST_F(VideoStreamEncoderTest,
1358 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
1359 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001360
asapersson0944a802017-04-07 00:57:58 -07001361 const int kWidth = 1280;
1362 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001363 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001364
asaperssonfab67072017-04-04 05:51:49 -07001365 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001366 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001367 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001368 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001369 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001370 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1371
asapersson02465b82017-04-10 01:12:52 -07001372 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001373 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001374 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001375 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001376 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001377 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001378 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001379 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1380
1381 // Set new source with adaptation still enabled.
1382 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001383 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001384 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001385
1386 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001387 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001388 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001389 stats = stats_proxy_->GetStats();
1390 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001391 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001392 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1393
sprangc5d62e22017-04-02 23:53:04 -07001394 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001395 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001396 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001397 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001398 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001399 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001400 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001401 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001402 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001403 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001404 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1405
sprangc5d62e22017-04-02 23:53:04 -07001406 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001407 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001408 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1409 mock_stats.input_frame_rate = 30;
1410 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001411 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001412 stats_proxy_->ResetMockStats();
1413
1414 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001415 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001416 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001417
1418 // Framerate now adapted.
1419 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001420 EXPECT_FALSE(stats.cpu_limited_resolution);
1421 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001422 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1423
1424 // Disable CPU adaptation.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001425 video_stream_encoder_->SetSource(&new_video_source,
1426 webrtc::DegradationPreference::DISABLED);
sprangc5d62e22017-04-02 23:53:04 -07001427 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001428 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001429 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001430
1431 stats = stats_proxy_->GetStats();
1432 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001433 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001434 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1435
1436 // Try to trigger overuse. Should not succeed.
1437 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001438 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001439 stats_proxy_->ResetMockStats();
1440
1441 stats = stats_proxy_->GetStats();
1442 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001443 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001444 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1445
1446 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001447 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001448 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssonfab67072017-04-04 05:51:49 -07001449 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001450 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001451 stats = stats_proxy_->GetStats();
1452 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001453 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001454 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001455
1456 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001457 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001458 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001459 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001460 stats = stats_proxy_->GetStats();
1461 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001462 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001463 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1464
1465 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001466 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001467 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001468 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001469 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001470 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001471 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001472 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001473 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001474 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001475 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1476
1477 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001478 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001479 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001480 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001481 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001482 stats = stats_proxy_->GetStats();
1483 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001484 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001485 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001486 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001487
mflodmancc3d4422017-08-03 08:27:51 -07001488 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001489}
1490
mflodmancc3d4422017-08-03 08:27:51 -07001491TEST_F(VideoStreamEncoderTest,
1492 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001493 const int kWidth = 1280;
1494 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001495 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001496
asaperssonfab67072017-04-04 05:51:49 -07001497 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001498 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001499
asaperssonfab67072017-04-04 05:51:49 -07001500 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001501 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001502
asaperssonfab67072017-04-04 05:51:49 -07001503 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001504 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001505
asaperssonfab67072017-04-04 05:51:49 -07001506 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001507 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001508
kthelgason876222f2016-11-29 01:44:11 -08001509 // Expect a scale down.
1510 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001511 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001512
asapersson02465b82017-04-10 01:12:52 -07001513 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001514 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001515 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001516 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001517
asaperssonfab67072017-04-04 05:51:49 -07001518 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001519 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001520 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001521 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001522
asaperssonfab67072017-04-04 05:51:49 -07001523 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001524 EXPECT_EQ(std::numeric_limits<int>::max(),
1525 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001526
asaperssonfab67072017-04-04 05:51:49 -07001527 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001528 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001529 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001530 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001531
asapersson02465b82017-04-10 01:12:52 -07001532 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001533 EXPECT_EQ(std::numeric_limits<int>::max(),
1534 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001535
mflodmancc3d4422017-08-03 08:27:51 -07001536 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001537}
1538
mflodmancc3d4422017-08-03 08:27:51 -07001539TEST_F(VideoStreamEncoderTest,
1540 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001541 const int kWidth = 1280;
1542 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001543 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001544
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001545 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001546 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001547 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001548 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001549
1550 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001551 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001552 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001553 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1554 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1555
1556 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001557 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001558 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001559 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1560 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1561 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1562
1563 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001564 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001565 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1566 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1567 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1568
mflodmancc3d4422017-08-03 08:27:51 -07001569 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001570}
1571
mflodmancc3d4422017-08-03 08:27:51 -07001572TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001573 const int kWidth = 1280;
1574 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001575 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001576
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001577 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001578 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001579 video_stream_encoder_->SetSource(&source,
1580 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001581 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1582 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001583 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001584
1585 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001586 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001587 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1588 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1589 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1590 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1591
1592 // Trigger adapt down for same input resolution, expect no change.
1593 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1594 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001595 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001596 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1597 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1598 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1599
1600 // Trigger adapt down for larger input resolution, expect no change.
1601 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1602 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001603 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001604 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1605 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1606 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1607
mflodmancc3d4422017-08-03 08:27:51 -07001608 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001609}
1610
mflodmancc3d4422017-08-03 08:27:51 -07001611TEST_F(VideoStreamEncoderTest,
1612 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001613 const int kWidth = 1280;
1614 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001615 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001616
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001617 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001618 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001619 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001620 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001621
1622 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001623 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001624 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001625 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1626 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1627
1628 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001629 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001630 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001631 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1632 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1633
mflodmancc3d4422017-08-03 08:27:51 -07001634 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001635}
1636
mflodmancc3d4422017-08-03 08:27:51 -07001637TEST_F(VideoStreamEncoderTest,
1638 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001639 const int kWidth = 1280;
1640 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001641 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001642
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001643 // Enable MAINTAIN_RESOLUTION preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001644 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001645 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001646 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
asapersson02465b82017-04-10 01:12:52 -07001647
1648 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001649 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001650 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001651 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001652 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1653
1654 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001655 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001656 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001657 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001658 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1659
mflodmancc3d4422017-08-03 08:27:51 -07001660 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001661}
1662
mflodmancc3d4422017-08-03 08:27:51 -07001663TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001664 const int kWidth = 1280;
1665 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001666 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001667
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001668 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001669 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001670 video_stream_encoder_->SetSource(&source,
1671 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001672
1673 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1674 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001675 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001676 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1677 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1678 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1679
1680 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001681 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001682 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001683 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1684 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1685 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1686
mflodmancc3d4422017-08-03 08:27:51 -07001687 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001688}
1689
mflodmancc3d4422017-08-03 08:27:51 -07001690TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001691 const int kWidth = 1280;
1692 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001693 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001694
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001695 // Enable DISABLED preference, no initial limitation.
asapersson09f05612017-05-15 23:40:18 -07001696 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001697 video_stream_encoder_->SetSource(&source,
1698 webrtc::DegradationPreference::DISABLED);
asapersson09f05612017-05-15 23:40:18 -07001699
1700 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1701 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001702 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001703 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1704 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1705 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1706
1707 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001708 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001709 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001710 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1711 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1712 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1713
mflodmancc3d4422017-08-03 08:27:51 -07001714 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001715}
1716
mflodmancc3d4422017-08-03 08:27:51 -07001717TEST_F(VideoStreamEncoderTest,
1718 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001719 const int kWidth = 1280;
1720 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001721 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001722
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001723 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001724 AdaptingFrameForwarder source;
1725 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001726 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001727 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001728
1729 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001730 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001731 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001732 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1733 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1734
1735 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001736 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001737 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001738 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001739 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001740 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1741 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1742
1743 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001744 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001745 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001746 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1747 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1748 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1749
mflodmancc3d4422017-08-03 08:27:51 -07001750 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001751}
1752
mflodmancc3d4422017-08-03 08:27:51 -07001753TEST_F(VideoStreamEncoderTest,
1754 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001755 const int kWidth = 1280;
1756 const int kHeight = 720;
1757 const int kInputFps = 30;
mflodmancc3d4422017-08-03 08:27:51 -07001758 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001759
1760 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1761 stats.input_frame_rate = kInputFps;
1762 stats_proxy_->SetMockStats(stats);
1763
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001764 // Expect no scaling to begin with (preference: MAINTAIN_FRAMERATE).
asapersson09f05612017-05-15 23:40:18 -07001765 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1766 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001767 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001768
1769 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001770 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001771 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1772 sink_.WaitForEncodedFrame(2);
1773 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1774
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001775 // Enable MAINTAIN_RESOLUTION preference.
asapersson09f05612017-05-15 23:40:18 -07001776 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001777 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001778 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001779 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001780
1781 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001782 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001783 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1784 sink_.WaitForEncodedFrame(3);
1785 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1786
1787 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001788 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001789 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001790
mflodmancc3d4422017-08-03 08:27:51 -07001791 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001792}
1793
mflodmancc3d4422017-08-03 08:27:51 -07001794TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001795 const int kWidth = 1280;
1796 const int kHeight = 720;
1797 const size_t kNumFrames = 10;
1798
mflodmancc3d4422017-08-03 08:27:51 -07001799 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001800
asaperssond0de2952017-04-21 01:47:31 -07001801 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001802 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001803 video_source_.set_adaptation_enabled(true);
1804
1805 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1806 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1807
1808 int downscales = 0;
1809 for (size_t i = 1; i <= kNumFrames; i++) {
Åsa Persson8c1bf952018-09-13 10:42:19 +02001810 video_source_.IncomingCapturedFrame(
1811 CreateFrame(i * kFrameIntervalMs, kWidth, kHeight));
1812 WaitForEncodedFrame(i * kFrameIntervalMs);
asaperssond0de2952017-04-21 01:47:31 -07001813
asaperssonfab67072017-04-04 05:51:49 -07001814 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001815 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001816 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001817 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001818
1819 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1820 ++downscales;
1821
1822 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1823 EXPECT_EQ(downscales,
1824 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1825 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001826 }
mflodmancc3d4422017-08-03 08:27:51 -07001827 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001828}
1829
mflodmancc3d4422017-08-03 08:27:51 -07001830TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001831 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1832 const int kWidth = 1280;
1833 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001834 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001835
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001836 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001837 AdaptingFrameForwarder source;
1838 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001839 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001840 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001841
Åsa Persson8c1bf952018-09-13 10:42:19 +02001842 int64_t timestamp_ms = kFrameIntervalMs;
1843 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001844 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001845 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001846 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1847 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1848
1849 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001850 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001851 timestamp_ms += kFrameIntervalMs;
1852 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1853 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001854 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001855 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1856 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1857
1858 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001859 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001860 timestamp_ms += kFrameIntervalMs;
1861 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001862 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001863 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001864 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1865 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1866
1867 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001868 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001869 timestamp_ms += kFrameIntervalMs;
1870 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1871 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001872 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001873 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1874 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1875
1876 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001877 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001878 timestamp_ms += kFrameIntervalMs;
1879 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asapersson09f05612017-05-15 23:40:18 -07001880 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001881 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001882 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1883 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1884
mflodmancc3d4422017-08-03 08:27:51 -07001885 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001886}
1887
mflodmancc3d4422017-08-03 08:27:51 -07001888TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07001889 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
1890 const int kWidth = 1280;
1891 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001892 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001893
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001894 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001895 AdaptingFrameForwarder source;
1896 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001897 video_stream_encoder_->SetSource(&source,
1898 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001899
Åsa Persson8c1bf952018-09-13 10:42:19 +02001900 int64_t timestamp_ms = kFrameIntervalMs;
1901 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001902 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001903 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001904 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1905 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1906
1907 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001908 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001909 timestamp_ms += kFrameIntervalMs;
1910 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1911 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07001912 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1913 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1914 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1915
1916 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001917 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001918 timestamp_ms += kFrameIntervalMs;
1919 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001920 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001921 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001922 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1923 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1924
1925 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001926 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001927 timestamp_ms += kFrameIntervalMs;
1928 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1929 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07001930 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1931 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1932 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1933
1934 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001935 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001936 timestamp_ms += kFrameIntervalMs;
1937 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001938 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001939 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001940 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1941 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1942
mflodmancc3d4422017-08-03 08:27:51 -07001943 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001944}
1945
mflodmancc3d4422017-08-03 08:27:51 -07001946TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001947 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
1948 const int kWidth = 1280;
1949 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001950 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001951
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001952 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001953 AdaptingFrameForwarder source;
1954 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001955 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001956 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001957
Åsa Persson8c1bf952018-09-13 10:42:19 +02001958 int64_t timestamp_ms = kFrameIntervalMs;
1959 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001960 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001961 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001962 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1963 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1964 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1965 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1966
1967 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001968 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001969 timestamp_ms += kFrameIntervalMs;
1970 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1971 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001972 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001973 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1974 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1975 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1976 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1977
1978 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07001979 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001980 timestamp_ms += kFrameIntervalMs;
1981 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1982 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001983 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001984 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1985 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1986 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1987 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1988
Jonathan Yubc771b72017-12-08 17:04:29 -08001989 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001990 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001991 timestamp_ms += kFrameIntervalMs;
1992 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1993 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001994 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001995 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1996 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001997 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001998 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1999
Jonathan Yubc771b72017-12-08 17:04:29 -08002000 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07002001 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002002 timestamp_ms += kFrameIntervalMs;
2003 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2004 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002005 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002006 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07002007 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2008 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2009 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2010 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2011
Jonathan Yubc771b72017-12-08 17:04:29 -08002012 // Trigger quality adapt down, expect no change (min resolution reached).
2013 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002014 timestamp_ms += kFrameIntervalMs;
2015 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2016 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002017 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
2018 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2019 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2020 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2021 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2022
2023 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002024 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002025 timestamp_ms += kFrameIntervalMs;
2026 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2027 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002028 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002029 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2030 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2031 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2032 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2033
2034 // Trigger cpu adapt up, expect upscaled resolution (640x360).
2035 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002036 timestamp_ms += kFrameIntervalMs;
2037 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2038 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002039 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2040 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2041 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2042 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2043 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2044
2045 // Trigger cpu adapt up, expect upscaled resolution (960x540).
2046 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002047 timestamp_ms += kFrameIntervalMs;
2048 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2049 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002050 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002051 last_wants = source.sink_wants();
2052 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2053 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002054 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002055 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2056
2057 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002058 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002059 timestamp_ms += kFrameIntervalMs;
2060 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2061 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002062 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002063 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2064 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002065 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002066 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2067
2068 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002069 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002070 timestamp_ms += kFrameIntervalMs;
2071 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002072 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002073 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002074 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002075 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2076 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002077 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002078 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002079
mflodmancc3d4422017-08-03 08:27:51 -07002080 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002081}
2082
mflodmancc3d4422017-08-03 08:27:51 -07002083TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002084 const int kWidth = 640;
2085 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002086
mflodmancc3d4422017-08-03 08:27:51 -07002087 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002088
perkj803d97f2016-11-01 11:45:46 -07002089 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002090 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002091 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002092 }
2093
mflodmancc3d4422017-08-03 08:27:51 -07002094 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002095 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002096 video_source_.IncomingCapturedFrame(CreateFrame(
2097 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002098 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002099 }
2100
mflodmancc3d4422017-08-03 08:27:51 -07002101 video_stream_encoder_->Stop();
2102 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002103 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002104
perkj803d97f2016-11-01 11:45:46 -07002105 EXPECT_EQ(1,
2106 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2107 EXPECT_EQ(
2108 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2109}
2110
mflodmancc3d4422017-08-03 08:27:51 -07002111TEST_F(VideoStreamEncoderTest,
2112 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2113 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002114 const int kWidth = 640;
2115 const int kHeight = 360;
2116
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002117 video_stream_encoder_->SetSource(&video_source_,
2118 webrtc::DegradationPreference::DISABLED);
asaperssonf4e44af2017-04-19 02:01:06 -07002119
2120 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2121 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002122 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002123 }
2124
mflodmancc3d4422017-08-03 08:27:51 -07002125 video_stream_encoder_->Stop();
2126 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002127 stats_proxy_.reset();
2128
2129 EXPECT_EQ(0,
2130 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2131}
2132
mflodmancc3d4422017-08-03 08:27:51 -07002133TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002134 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02002135 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002136
2137 const int kDefaultFps = 30;
Erik Språng566124a2018-04-23 12:32:22 +02002138 const VideoBitrateAllocation expected_bitrate =
sprang57c2fff2017-01-16 06:24:02 -08002139 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002140 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002141
sprang57c2fff2017-01-16 06:24:02 -08002142 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
Niels Möller6bb5ab92019-01-11 11:11:10 +01002143 .Times(1);
mflodmancc3d4422017-08-03 08:27:51 -07002144 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002145
2146 const int64_t kStartTimeMs = 1;
2147 video_source_.IncomingCapturedFrame(
2148 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002149 WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002150
2151 // Not called on second frame.
2152 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2153 .Times(0);
2154 video_source_.IncomingCapturedFrame(
2155 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002156 WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002157
2158 // Called after a process interval.
2159 const int64_t kProcessIntervalMs =
2160 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang4847ae62017-06-27 07:06:52 -07002161 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec *
2162 (kProcessIntervalMs + (1000 / kDefaultFps)));
sprang57c2fff2017-01-16 06:24:02 -08002163 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2164 .Times(1);
2165 video_source_.IncomingCapturedFrame(CreateFrame(
2166 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002167 WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002168
mflodmancc3d4422017-08-03 08:27:51 -07002169 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002170}
2171
Niels Möller7dc26b72017-12-06 10:27:48 +01002172TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2173 const int kFrameWidth = 1280;
2174 const int kFrameHeight = 720;
2175 const int kFramerate = 24;
2176
2177 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2178 test::FrameForwarder source;
2179 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002180 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002181
2182 // Insert a single frame, triggering initial configuration.
2183 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2184 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2185
2186 EXPECT_EQ(
2187 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2188 kDefaultFramerate);
2189
2190 // Trigger reconfigure encoder (without resetting the entire instance).
2191 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002192 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002193 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2194 video_encoder_config.number_of_streams = 1;
2195 video_encoder_config.video_stream_factory =
2196 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2197 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002198 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002199 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2200
2201 // Detector should be updated with fps limit from codec config.
2202 EXPECT_EQ(
2203 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2204 kFramerate);
2205
2206 // Trigger overuse, max framerate should be reduced.
2207 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2208 stats.input_frame_rate = kFramerate;
2209 stats_proxy_->SetMockStats(stats);
2210 video_stream_encoder_->TriggerCpuOveruse();
2211 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2212 int adapted_framerate =
2213 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2214 EXPECT_LT(adapted_framerate, kFramerate);
2215
2216 // Trigger underuse, max framerate should go back to codec configured fps.
2217 // Set extra low fps, to make sure it's actually reset, not just incremented.
2218 stats = stats_proxy_->GetStats();
2219 stats.input_frame_rate = adapted_framerate / 2;
2220 stats_proxy_->SetMockStats(stats);
2221 video_stream_encoder_->TriggerCpuNormalUsage();
2222 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2223 EXPECT_EQ(
2224 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2225 kFramerate);
2226
2227 video_stream_encoder_->Stop();
2228}
2229
2230TEST_F(VideoStreamEncoderTest,
2231 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2232 const int kFrameWidth = 1280;
2233 const int kFrameHeight = 720;
2234 const int kLowFramerate = 15;
2235 const int kHighFramerate = 25;
2236
2237 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2238 test::FrameForwarder source;
2239 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002240 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002241
2242 // Trigger initial configuration.
2243 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002244 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002245 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2246 video_encoder_config.number_of_streams = 1;
2247 video_encoder_config.video_stream_factory =
2248 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2249 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2250 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002251 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002252 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2253
2254 EXPECT_EQ(
2255 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2256 kLowFramerate);
2257
2258 // Trigger overuse, max framerate should be reduced.
2259 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2260 stats.input_frame_rate = kLowFramerate;
2261 stats_proxy_->SetMockStats(stats);
2262 video_stream_encoder_->TriggerCpuOveruse();
2263 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2264 int adapted_framerate =
2265 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2266 EXPECT_LT(adapted_framerate, kLowFramerate);
2267
2268 // Reconfigure the encoder with a new (higher max framerate), max fps should
2269 // still respect the adaptation.
2270 video_encoder_config.video_stream_factory =
2271 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2272 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2273 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002274 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002275 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2276
2277 EXPECT_EQ(
2278 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2279 adapted_framerate);
2280
2281 // Trigger underuse, max framerate should go back to codec configured fps.
2282 stats = stats_proxy_->GetStats();
2283 stats.input_frame_rate = adapted_framerate;
2284 stats_proxy_->SetMockStats(stats);
2285 video_stream_encoder_->TriggerCpuNormalUsage();
2286 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2287 EXPECT_EQ(
2288 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2289 kHighFramerate);
2290
2291 video_stream_encoder_->Stop();
2292}
2293
mflodmancc3d4422017-08-03 08:27:51 -07002294TEST_F(VideoStreamEncoderTest,
2295 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002296 const int kFrameWidth = 1280;
2297 const int kFrameHeight = 720;
2298 const int kFramerate = 24;
2299
mflodmancc3d4422017-08-03 08:27:51 -07002300 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002301 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002302 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002303 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangfda496a2017-06-15 04:21:07 -07002304
2305 // Trigger initial configuration.
2306 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002307 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002308 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2309 video_encoder_config.number_of_streams = 1;
2310 video_encoder_config.video_stream_factory =
2311 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2312 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002313 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002314 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002315 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002316
Niels Möller7dc26b72017-12-06 10:27:48 +01002317 EXPECT_EQ(
2318 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2319 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002320
2321 // Trigger overuse, max framerate should be reduced.
2322 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2323 stats.input_frame_rate = kFramerate;
2324 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002325 video_stream_encoder_->TriggerCpuOveruse();
2326 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002327 int adapted_framerate =
2328 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002329 EXPECT_LT(adapted_framerate, kFramerate);
2330
2331 // Change degradation preference to not enable framerate scaling. Target
2332 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002333 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002334 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -07002335 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002336 EXPECT_EQ(
2337 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2338 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002339
mflodmancc3d4422017-08-03 08:27:51 -07002340 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002341}
2342
mflodmancc3d4422017-08-03 08:27:51 -07002343TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002344 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002345 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002346 const int kWidth = 640;
2347 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002348
asaperssonfab67072017-04-04 05:51:49 -07002349 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002350
2351 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002352 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002353
2354 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002355 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002356
sprangc5d62e22017-04-02 23:53:04 -07002357 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002358
asaperssonfab67072017-04-04 05:51:49 -07002359 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002360 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002361 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002362
2363 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002364 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002365
sprangc5d62e22017-04-02 23:53:04 -07002366 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002367
mflodmancc3d4422017-08-03 08:27:51 -07002368 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002369}
2370
mflodmancc3d4422017-08-03 08:27:51 -07002371TEST_F(VideoStreamEncoderTest,
2372 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002373 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002374 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002375 const int kWidth = 640;
2376 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002377
2378 // We expect the n initial frames to get dropped.
2379 int i;
2380 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002381 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002382 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002383 }
2384 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002385 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002386 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002387
2388 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002389 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002390
mflodmancc3d4422017-08-03 08:27:51 -07002391 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002392}
2393
mflodmancc3d4422017-08-03 08:27:51 -07002394TEST_F(VideoStreamEncoderTest,
2395 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002396 const int kWidth = 640;
2397 const int kHeight = 360;
mflodmancc3d4422017-08-03 08:27:51 -07002398 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002399
2400 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002401 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002402 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason2bc68642017-02-07 07:02:22 -08002403
asaperssonfab67072017-04-04 05:51:49 -07002404 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002405 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002406 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002407
mflodmancc3d4422017-08-03 08:27:51 -07002408 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002409}
2410
mflodmancc3d4422017-08-03 08:27:51 -07002411TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002412 const int kWidth = 640;
2413 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002414 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02002415
2416 VideoEncoderConfig video_encoder_config;
2417 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
2418 // Make format different, to force recreation of encoder.
2419 video_encoder_config.video_format.parameters["foo"] = "foo";
2420 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002421 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002422 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002423
kthelgasonb83797b2017-02-14 11:57:25 -08002424 // Force quality scaler reconfiguration by resetting the source.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002425 video_stream_encoder_->SetSource(&video_source_,
2426 webrtc::DegradationPreference::BALANCED);
kthelgasonad9010c2017-02-14 00:46:51 -08002427
asaperssonfab67072017-04-04 05:51:49 -07002428 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002429 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002430 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002431
mflodmancc3d4422017-08-03 08:27:51 -07002432 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002433 fake_encoder_.SetQualityScaling(true);
2434}
2435
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002436TEST_F(VideoStreamEncoderTest, InitialFrameDropActivatesWhenBWEstimateReady) {
2437 webrtc::test::ScopedFieldTrials field_trials(
2438 "WebRTC-InitialFramedrop/Enabled/");
2439 // Reset encoder for field trials to take effect.
2440 ConfigureEncoder(video_encoder_config_.Copy());
2441 const int kTooLowBitrateForFrameSizeBps = 10000;
2442 const int kWidth = 640;
2443 const int kHeight = 360;
2444
2445 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2446 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2447 // Frame should not be dropped.
2448 WaitForEncodedFrame(1);
2449
2450 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
2451 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
2452 // Expect to drop this frame, the wait should time out.
2453 ExpectDroppedFrame();
2454
2455 // Expect the sink_wants to specify a scaled frame.
2456 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
2457 video_stream_encoder_->Stop();
2458}
2459
mflodmancc3d4422017-08-03 08:27:51 -07002460TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002461 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2462 const int kTooSmallWidth = 10;
2463 const int kTooSmallHeight = 10;
mflodmancc3d4422017-08-03 08:27:51 -07002464 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002465
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002466 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002467 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002468 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002469 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002470 VerifyNoLimitation(source.sink_wants());
2471 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2472
2473 // Trigger adapt down, too small frame, expect no change.
2474 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002475 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002476 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002477 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002478 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2479 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2480
mflodmancc3d4422017-08-03 08:27:51 -07002481 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002482}
2483
mflodmancc3d4422017-08-03 08:27:51 -07002484TEST_F(VideoStreamEncoderTest,
2485 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002486 const int kTooSmallWidth = 10;
2487 const int kTooSmallHeight = 10;
2488 const int kFpsLimit = 7;
mflodmancc3d4422017-08-03 08:27:51 -07002489 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002490
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002491 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002492 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002493 video_stream_encoder_->SetSource(&source,
2494 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002495 VerifyNoLimitation(source.sink_wants());
2496 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2497 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2498
2499 // Trigger adapt down, expect limited framerate.
2500 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002501 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002502 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002503 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2504 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2505 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2506 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2507
2508 // Trigger adapt down, too small frame, expect no change.
2509 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002510 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002511 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002512 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2513 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2514 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2515 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2516
mflodmancc3d4422017-08-03 08:27:51 -07002517 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002518}
2519
mflodmancc3d4422017-08-03 08:27:51 -07002520TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002521 fake_encoder_.ForceInitEncodeFailure(true);
mflodmancc3d4422017-08-03 08:27:51 -07002522 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Niels Möllerf1338562018-04-26 09:51:47 +02002523 ResetEncoder("VP8", 2, 1, 1, false);
asapersson02465b82017-04-10 01:12:52 -07002524 const int kFrameWidth = 1280;
2525 const int kFrameHeight = 720;
2526 video_source_.IncomingCapturedFrame(
2527 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002528 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002529 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002530}
2531
sprangb1ca0732017-02-01 08:38:12 -08002532// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002533TEST_F(VideoStreamEncoderTest,
2534 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
2535 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002536
2537 const int kFrameWidth = 1280;
2538 const int kFrameHeight = 720;
2539 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002540 // requested by
2541 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002542 video_source_.set_adaptation_enabled(true);
2543
2544 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002545 CreateFrame(1 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002546 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002547
2548 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002549 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002550 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002551 CreateFrame(2 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002552 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002553
asaperssonfab67072017-04-04 05:51:49 -07002554 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002555 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002556 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002557 CreateFrame(3 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002558 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002559
mflodmancc3d4422017-08-03 08:27:51 -07002560 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002561}
sprangfe627f32017-03-29 08:24:59 -07002562
mflodmancc3d4422017-08-03 08:27:51 -07002563TEST_F(VideoStreamEncoderTest,
2564 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002565 const int kFrameWidth = 1280;
2566 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07002567
mflodmancc3d4422017-08-03 08:27:51 -07002568 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2569 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002570 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002571 video_source_.set_adaptation_enabled(true);
2572
sprang4847ae62017-06-27 07:06:52 -07002573 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002574
2575 video_source_.IncomingCapturedFrame(
2576 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002577 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002578
2579 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002580 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002581
2582 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002583 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002584 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002585 video_source_.IncomingCapturedFrame(
2586 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002587 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002588 }
2589
2590 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002591 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002592 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002593 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002594 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002595 video_source_.IncomingCapturedFrame(
2596 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002597 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002598 ++num_frames_dropped;
2599 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002600 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002601 }
2602 }
2603
sprang4847ae62017-06-27 07:06:52 -07002604 // Add some slack to account for frames dropped by the frame dropper.
2605 const int kErrorMargin = 1;
2606 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002607 kErrorMargin);
2608
2609 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002610 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002611 num_frames_dropped = 0;
Åsa Persson8c1bf952018-09-13 10:42:19 +02002612 for (int i = 0; i <= max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002613 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002614 video_source_.IncomingCapturedFrame(
2615 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002616 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002617 ++num_frames_dropped;
2618 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002619 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002620 }
2621 }
sprang4847ae62017-06-27 07:06:52 -07002622 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002623 kErrorMargin);
2624
2625 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002626 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002627 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002628 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002629 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002630 video_source_.IncomingCapturedFrame(
2631 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002632 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002633 ++num_frames_dropped;
2634 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002635 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002636 }
2637 }
sprang4847ae62017-06-27 07:06:52 -07002638 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002639 kErrorMargin);
2640
2641 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002642 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002643 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002644 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002645 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002646 video_source_.IncomingCapturedFrame(
2647 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002648 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002649 ++num_frames_dropped;
2650 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002651 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002652 }
2653 }
2654 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2655
mflodmancc3d4422017-08-03 08:27:51 -07002656 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002657}
2658
mflodmancc3d4422017-08-03 08:27:51 -07002659TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002660 const int kFramerateFps = 5;
2661 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002662 const int kFrameWidth = 1280;
2663 const int kFrameHeight = 720;
2664
sprang4847ae62017-06-27 07:06:52 -07002665 // Reconfigure encoder with two temporal layers and screensharing, which will
2666 // disable frame dropping and make testing easier.
Niels Möllerf1338562018-04-26 09:51:47 +02002667 ResetEncoder("VP8", 1, 2, 1, true);
sprang4847ae62017-06-27 07:06:52 -07002668
mflodmancc3d4422017-08-03 08:27:51 -07002669 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2670 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002671 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002672 video_source_.set_adaptation_enabled(true);
2673
sprang4847ae62017-06-27 07:06:52 -07002674 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002675
2676 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08002677 rtc::VideoSinkWants last_wants;
2678 do {
2679 last_wants = video_source_.sink_wants();
2680
sprangc5d62e22017-04-02 23:53:04 -07002681 // Insert frames to get a new fps estimate...
2682 for (int j = 0; j < kFramerateFps; ++j) {
2683 video_source_.IncomingCapturedFrame(
2684 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08002685 if (video_source_.last_sent_width()) {
2686 sink_.WaitForEncodedFrame(timestamp_ms);
2687 }
sprangc5d62e22017-04-02 23:53:04 -07002688 timestamp_ms += kFrameIntervalMs;
Yves Gerey665174f2018-06-19 15:03:05 +02002689 fake_clock_.AdvanceTimeMicros(kFrameIntervalMs *
2690 rtc::kNumMicrosecsPerMillisec);
sprangc5d62e22017-04-02 23:53:04 -07002691 }
2692 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002693 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08002694 } while (video_source_.sink_wants().max_framerate_fps <
2695 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07002696
Jonathan Yubc771b72017-12-08 17:04:29 -08002697 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07002698
mflodmancc3d4422017-08-03 08:27:51 -07002699 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002700}
asaperssonf7e294d2017-06-13 23:25:22 -07002701
mflodmancc3d4422017-08-03 08:27:51 -07002702TEST_F(VideoStreamEncoderTest,
2703 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002704 const int kWidth = 1280;
2705 const int kHeight = 720;
2706 const int64_t kFrameIntervalMs = 150;
2707 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002708 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002709
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002710 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002711 AdaptingFrameForwarder source;
2712 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002713 video_stream_encoder_->SetSource(&source,
2714 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002715 timestamp_ms += kFrameIntervalMs;
2716 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002717 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002718 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002719 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2720 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2721 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2722
2723 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002724 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002725 timestamp_ms += kFrameIntervalMs;
2726 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002727 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002728 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2729 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2730 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2731 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2732
2733 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002734 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002735 timestamp_ms += kFrameIntervalMs;
2736 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002737 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002738 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2739 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2740 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2741 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2742
2743 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002744 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002745 timestamp_ms += kFrameIntervalMs;
2746 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002747 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002748 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2749 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2750 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2751 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2752
2753 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002754 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002755 timestamp_ms += kFrameIntervalMs;
2756 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002757 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002758 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2759 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2760 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2761 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2762
2763 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002764 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002765 timestamp_ms += kFrameIntervalMs;
2766 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002767 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002768 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2769 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2770 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2771 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2772
2773 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002774 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002775 timestamp_ms += kFrameIntervalMs;
2776 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002777 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002778 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2779 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2780 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2781 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2782
2783 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002784 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002785 timestamp_ms += kFrameIntervalMs;
2786 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002787 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002788 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2789 rtc::VideoSinkWants last_wants = source.sink_wants();
2790 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2791 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2792 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2793
2794 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002795 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002796 timestamp_ms += kFrameIntervalMs;
2797 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002798 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002799 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2800 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2801 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2802 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2803
2804 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002805 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002806 timestamp_ms += kFrameIntervalMs;
2807 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002808 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002809 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2810 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2811 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2812 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2813
2814 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002815 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002816 timestamp_ms += kFrameIntervalMs;
2817 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002818 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002819 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2820 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2821 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2822 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2823
2824 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002825 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002826 timestamp_ms += kFrameIntervalMs;
2827 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002828 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002829 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2830 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2831 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2832 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2833
2834 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002835 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002836 timestamp_ms += kFrameIntervalMs;
2837 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002838 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002839 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2840 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2841 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2842 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2843
2844 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002845 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002846 timestamp_ms += kFrameIntervalMs;
2847 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002848 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002849 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2850 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2851 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2852 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2853
2854 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002855 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002856 timestamp_ms += kFrameIntervalMs;
2857 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002858 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002859 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2860 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2861 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2862 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2863
2864 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002865 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002866 timestamp_ms += kFrameIntervalMs;
2867 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002868 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002869 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002870 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002871 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2872 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2873 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2874
2875 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002876 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002877 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002878 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2879
mflodmancc3d4422017-08-03 08:27:51 -07002880 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002881}
2882
mflodmancc3d4422017-08-03 08:27:51 -07002883TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07002884 const int kWidth = 1280;
2885 const int kHeight = 720;
2886 const int64_t kFrameIntervalMs = 150;
2887 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002888 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002889
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002890 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002891 AdaptingFrameForwarder source;
2892 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002893 video_stream_encoder_->SetSource(&source,
2894 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002895 timestamp_ms += kFrameIntervalMs;
2896 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002897 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002898 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002899 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2900 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2901 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2902 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2903 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2904 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2905
2906 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002907 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002908 timestamp_ms += kFrameIntervalMs;
2909 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002910 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002911 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2912 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2913 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2914 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2915 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2916 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2917 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2918
2919 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002920 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002921 timestamp_ms += kFrameIntervalMs;
2922 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002923 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002924 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2925 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2926 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2927 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2928 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2929 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2930 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2931
2932 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002933 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002934 timestamp_ms += kFrameIntervalMs;
2935 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002936 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002937 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2938 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2939 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2940 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2941 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2942 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2943 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2944
2945 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002946 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002947 timestamp_ms += kFrameIntervalMs;
2948 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002949 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002950 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2951 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2952 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2953 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2954 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2955 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2956 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2957
2958 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002959 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002960 timestamp_ms += kFrameIntervalMs;
2961 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002962 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002963 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2964 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2965 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2966 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2967 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2968 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2969 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2970
2971 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002972 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002973 timestamp_ms += kFrameIntervalMs;
2974 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002975 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002976 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002977 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002978 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2979 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2980 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2981 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2982 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2983 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2984
2985 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002986 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002987 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002988 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2989 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2990
mflodmancc3d4422017-08-03 08:27:51 -07002991 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002992}
2993
mflodmancc3d4422017-08-03 08:27:51 -07002994TEST_F(VideoStreamEncoderTest,
2995 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07002996 const int kWidth = 640;
2997 const int kHeight = 360;
2998 const int kFpsLimit = 15;
2999 const int64_t kFrameIntervalMs = 150;
3000 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07003001 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07003002
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003003 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07003004 AdaptingFrameForwarder source;
3005 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003006 video_stream_encoder_->SetSource(&source,
3007 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07003008 timestamp_ms += kFrameIntervalMs;
3009 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003010 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003011 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003012 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3013 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3014 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3015 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3016 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3017 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3018
3019 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003020 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003021 timestamp_ms += kFrameIntervalMs;
3022 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003023 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003024 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
3025 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3026 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3027 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3028 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3029 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3030 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3031
3032 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003033 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003034 timestamp_ms += kFrameIntervalMs;
3035 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003036 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003037 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
3038 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3039 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3040 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3041 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3042 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3043 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3044
3045 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003046 video_stream_encoder_->TriggerCpuNormalUsage();
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 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3051 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3052 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3053 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3054 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3055 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3056 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3057
3058 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003059 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003060 timestamp_ms += kFrameIntervalMs;
3061 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003062 WaitForEncodedFrame(timestamp_ms);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003063 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003064 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3065 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3066 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3067 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3068 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3069 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3070
3071 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003072 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003073 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003074 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3075 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3076
mflodmancc3d4422017-08-03 08:27:51 -07003077 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003078}
3079
mflodmancc3d4422017-08-03 08:27:51 -07003080TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003081 // Simulates simulcast behavior and makes highest stream resolutions divisible
3082 // by 4.
3083 class CroppingVideoStreamFactory
3084 : public VideoEncoderConfig::VideoStreamFactoryInterface {
3085 public:
3086 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
3087 int framerate)
3088 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
3089 EXPECT_GT(num_temporal_layers, 0u);
3090 EXPECT_GT(framerate, 0);
3091 }
3092
3093 private:
3094 std::vector<VideoStream> CreateEncoderStreams(
3095 int width,
3096 int height,
3097 const VideoEncoderConfig& encoder_config) override {
Yves Gerey665174f2018-06-19 15:03:05 +02003098 std::vector<VideoStream> streams = test::CreateVideoStreams(
3099 width - width % 4, height - height % 4, encoder_config);
ilnik6b826ef2017-06-16 06:53:48 -07003100 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +01003101 stream.num_temporal_layers = num_temporal_layers_;
ilnik6b826ef2017-06-16 06:53:48 -07003102 stream.max_framerate = framerate_;
3103 }
3104 return streams;
3105 }
3106
3107 const size_t num_temporal_layers_;
3108 const int framerate_;
3109 };
3110
3111 const int kFrameWidth = 1920;
3112 const int kFrameHeight = 1080;
3113 // 3/4 of 1920.
3114 const int kAdaptedFrameWidth = 1440;
3115 // 3/4 of 1080 rounded down to multiple of 4.
3116 const int kAdaptedFrameHeight = 808;
3117 const int kFramerate = 24;
3118
mflodmancc3d4422017-08-03 08:27:51 -07003119 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003120 // Trigger reconfigure encoder (without resetting the entire instance).
3121 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02003122 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07003123 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3124 video_encoder_config.number_of_streams = 1;
3125 video_encoder_config.video_stream_factory =
3126 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003127 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02003128 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07003129 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003130
3131 video_source_.set_adaptation_enabled(true);
3132
3133 video_source_.IncomingCapturedFrame(
3134 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003135 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003136
3137 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003138 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003139 video_source_.IncomingCapturedFrame(
3140 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003141 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003142
mflodmancc3d4422017-08-03 08:27:51 -07003143 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003144}
3145
mflodmancc3d4422017-08-03 08:27:51 -07003146TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003147 const int kFrameWidth = 1280;
3148 const int kFrameHeight = 720;
3149 const int kLowFps = 2;
3150 const int kHighFps = 30;
3151
mflodmancc3d4422017-08-03 08:27:51 -07003152 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003153
3154 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3155 max_framerate_ = kLowFps;
3156
3157 // Insert 2 seconds of 2fps video.
3158 for (int i = 0; i < kLowFps * 2; ++i) {
3159 video_source_.IncomingCapturedFrame(
3160 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3161 WaitForEncodedFrame(timestamp_ms);
3162 timestamp_ms += 1000 / kLowFps;
3163 }
3164
3165 // Make sure encoder is updated with new target.
mflodmancc3d4422017-08-03 08:27:51 -07003166 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003167 video_source_.IncomingCapturedFrame(
3168 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3169 WaitForEncodedFrame(timestamp_ms);
3170 timestamp_ms += 1000 / kLowFps;
3171
3172 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3173
3174 // Insert 30fps frames for just a little more than the forced update period.
3175 const int kVcmTimerIntervalFrames =
3176 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3177 const int kFrameIntervalMs = 1000 / kHighFps;
3178 max_framerate_ = kHighFps;
3179 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3180 video_source_.IncomingCapturedFrame(
3181 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3182 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3183 // be dropped if the encoder hans't been updated with the new higher target
3184 // framerate yet, causing it to overshoot the target bitrate and then
3185 // suffering the wrath of the media optimizer.
3186 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3187 timestamp_ms += kFrameIntervalMs;
3188 }
3189
3190 // Don expect correct measurement just yet, but it should be higher than
3191 // before.
3192 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3193
mflodmancc3d4422017-08-03 08:27:51 -07003194 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003195}
3196
mflodmancc3d4422017-08-03 08:27:51 -07003197TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003198 const int kFrameWidth = 1280;
3199 const int kFrameHeight = 720;
3200 const int kTargetBitrateBps = 1000000;
3201
3202 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02003203 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
mflodmancc3d4422017-08-03 08:27:51 -07003204 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3205 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003206
3207 // Insert a first video frame, causes another bitrate update.
3208 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3209 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3210 video_source_.IncomingCapturedFrame(
3211 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3212 WaitForEncodedFrame(timestamp_ms);
3213
3214 // Next, simulate video suspension due to pacer queue overrun.
mflodmancc3d4422017-08-03 08:27:51 -07003215 video_stream_encoder_->OnBitrateUpdated(0, 0, 1);
sprang4847ae62017-06-27 07:06:52 -07003216
3217 // Skip ahead until a new periodic parameter update should have occured.
3218 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3219 fake_clock_.AdvanceTimeMicros(
3220 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3221 rtc::kNumMicrosecsPerMillisec);
3222
3223 // Bitrate observer should not be called.
3224 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3225 video_source_.IncomingCapturedFrame(
3226 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3227 ExpectDroppedFrame();
3228
mflodmancc3d4422017-08-03 08:27:51 -07003229 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003230}
ilnik6b826ef2017-06-16 06:53:48 -07003231
Niels Möller4db138e2018-04-19 09:04:13 +02003232TEST_F(VideoStreamEncoderTest,
3233 DefaultCpuAdaptationThresholdsForSoftwareEncoder) {
3234 const int kFrameWidth = 1280;
3235 const int kFrameHeight = 720;
3236 const CpuOveruseOptions default_options;
3237 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3238 video_source_.IncomingCapturedFrame(
3239 CreateFrame(1, kFrameWidth, kFrameHeight));
3240 WaitForEncodedFrame(1);
3241 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3242 .low_encode_usage_threshold_percent,
3243 default_options.low_encode_usage_threshold_percent);
3244 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3245 .high_encode_usage_threshold_percent,
3246 default_options.high_encode_usage_threshold_percent);
3247 video_stream_encoder_->Stop();
3248}
3249
3250TEST_F(VideoStreamEncoderTest,
3251 HigherCpuAdaptationThresholdsForHardwareEncoder) {
3252 const int kFrameWidth = 1280;
3253 const int kFrameHeight = 720;
3254 CpuOveruseOptions hardware_options;
3255 hardware_options.low_encode_usage_threshold_percent = 150;
3256 hardware_options.high_encode_usage_threshold_percent = 200;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +01003257 fake_encoder_.SetIsHardwareAccelerated(true);
Niels Möller4db138e2018-04-19 09:04:13 +02003258
3259 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3260 video_source_.IncomingCapturedFrame(
3261 CreateFrame(1, kFrameWidth, kFrameHeight));
3262 WaitForEncodedFrame(1);
3263 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3264 .low_encode_usage_threshold_percent,
3265 hardware_options.low_encode_usage_threshold_percent);
3266 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3267 .high_encode_usage_threshold_percent,
3268 hardware_options.high_encode_usage_threshold_percent);
3269 video_stream_encoder_->Stop();
3270}
3271
Niels Möller6bb5ab92019-01-11 11:11:10 +01003272TEST_F(VideoStreamEncoderTest, DropsFramesWhenEncoderOvershoots) {
3273 const int kFrameWidth = 320;
3274 const int kFrameHeight = 240;
3275 const int kFps = 30;
3276 const int kTargetBitrateBps = 120000;
3277 const int kNumFramesInRun = kFps * 5; // Runs of five seconds.
3278
3279 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3280
3281 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3282 max_framerate_ = kFps;
3283
3284 // Insert 3 seconds of video, verify number of drops with normal bitrate.
3285 fake_encoder_.SimulateOvershoot(1.0);
3286 int num_dropped = 0;
3287 for (int i = 0; i < kNumFramesInRun; ++i) {
3288 video_source_.IncomingCapturedFrame(
3289 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3290 // Wait up to two frame durations for a frame to arrive.
3291 if (!TimedWaitForEncodedFrame(timestamp_ms, 2 * 1000 / kFps)) {
3292 ++num_dropped;
3293 }
3294 timestamp_ms += 1000 / kFps;
3295 }
3296
3297 // Frame drops should be less than 5%
3298 EXPECT_LT(num_dropped, 5 * kNumFramesInRun / 100);
3299
3300 // Make encoder produce frames at double the expected bitrate during 3 seconds
3301 // of video, verify number of drops. Rate needs to be slightly changed in
3302 // order to force the rate to be reconfigured.
3303 fake_encoder_.SimulateOvershoot(2.0);
3304 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps + 1000, 0, 0);
3305 num_dropped = 0;
3306 for (int i = 0; i < kNumFramesInRun; ++i) {
3307 video_source_.IncomingCapturedFrame(
3308 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3309 // Wait up to two frame durations for a frame to arrive.
3310 if (!TimedWaitForEncodedFrame(timestamp_ms, 2 * 1000 / kFps)) {
3311 ++num_dropped;
3312 }
3313 timestamp_ms += 1000 / kFps;
3314 }
3315
3316 // Frame drops should be more than 40%.
3317 EXPECT_GT(num_dropped, 40 * kNumFramesInRun / 100);
3318
3319 video_stream_encoder_->Stop();
3320}
3321
3322TEST_F(VideoStreamEncoderTest, ConfiguresCorrectFrameRate) {
3323 const int kFrameWidth = 320;
3324 const int kFrameHeight = 240;
3325 const int kActualInputFps = 24;
3326 const int kTargetBitrateBps = 120000;
3327
3328 ASSERT_GT(max_framerate_, kActualInputFps);
3329
3330 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3331 max_framerate_ = kActualInputFps;
3332 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3333
3334 // Insert 3 seconds of video, with an input fps lower than configured max.
3335 for (int i = 0; i < kActualInputFps * 3; ++i) {
3336 video_source_.IncomingCapturedFrame(
3337 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3338 // Wait up to two frame durations for a frame to arrive.
3339 WaitForEncodedFrame(timestamp_ms);
3340 timestamp_ms += 1000 / kActualInputFps;
3341 }
3342
3343 EXPECT_NEAR(kActualInputFps, fake_encoder_.GetLastFramerate(), 1);
3344
3345 video_stream_encoder_->Stop();
3346}
3347
perkj26091b12016-09-01 01:17:40 -07003348} // namespace webrtc