blob: 28e06c79804ca825fbd5b86d361fa47bcd71bdfc [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ång4529fbc2018-10-12 10:30:31 +020019#include "api/video_codecs/create_vp8_temporal_layers.h"
20#include "api/video_codecs/vp8_temporal_layers.h"
Steve Anton10542f22019-01-11 09:11:00 -080021#include "media/base/video_adapter.h"
Sergey Silkin86684962018-03-28 19:32:37 +020022#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
Steve Anton10542f22019-01-11 09:11:00 -080024#include "rtc_base/fake_clock.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080026#include "rtc_base/ref_counted_object.h"
Mirko Bonadei17f48782018-09-28 08:51:10 +020027#include "system_wrappers/include/metrics.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020028#include "system_wrappers/include/sleep.h"
29#include "test/encoder_settings.h"
30#include "test/fake_encoder.h"
Kári Tristan Helgason639602a2018-08-02 10:51:40 +020031#include "test/field_trial.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020032#include "test/frame_generator.h"
33#include "test/gmock.h"
34#include "test/gtest.h"
Niels Möllercbcbc222018-09-28 09:07:24 +020035#include "test/video_encoder_proxy_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020036#include "video/send_statistics_proxy.h"
perkj26091b12016-09-01 01:17:40 -070037
38namespace webrtc {
39
sprangb1ca0732017-02-01 08:38:12 -080040using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080041using ::testing::_;
42using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080043
perkj803d97f2016-11-01 11:45:46 -070044namespace {
Åsa Persson8c1bf952018-09-13 10:42:19 +020045const int kMinPixelsPerFrame = 320 * 180;
46const int kMinFramerateFps = 2;
47const int kMinBalancedFramerateFps = 7;
48const int64_t kFrameTimeoutMs = 100;
asapersson5f7226f2016-11-25 04:37:00 -080049const size_t kMaxPayloadLength = 1440;
kthelgason2bc68642017-02-07 07:02:22 -080050const int kTargetBitrateBps = 1000000;
51const int kLowTargetBitrateBps = kTargetBitrateBps / 10;
52const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070053const int kDefaultFramerate = 30;
Åsa Persson8c1bf952018-09-13 10:42:19 +020054const int64_t kFrameIntervalMs = rtc::kNumMillisecsPerSec / kDefaultFramerate;
asapersson5f7226f2016-11-25 04:37:00 -080055
perkj803d97f2016-11-01 11:45:46 -070056class TestBuffer : public webrtc::I420Buffer {
57 public:
58 TestBuffer(rtc::Event* event, int width, int height)
59 : I420Buffer(width, height), event_(event) {}
60
61 private:
62 friend class rtc::RefCountedObject<TestBuffer>;
63 ~TestBuffer() override {
64 if (event_)
65 event_->Set();
66 }
67 rtc::Event* const event_;
68};
69
Niels Möller7dc26b72017-12-06 10:27:48 +010070class CpuOveruseDetectorProxy : public OveruseFrameDetector {
71 public:
Niels Möllerd1f7eb62018-03-28 16:40:58 +020072 explicit CpuOveruseDetectorProxy(CpuOveruseMetricsObserver* metrics_observer)
73 : OveruseFrameDetector(metrics_observer),
Niels Möller7dc26b72017-12-06 10:27:48 +010074 last_target_framerate_fps_(-1) {}
75 virtual ~CpuOveruseDetectorProxy() {}
76
77 void OnTargetFramerateUpdated(int framerate_fps) override {
78 rtc::CritScope cs(&lock_);
79 last_target_framerate_fps_ = framerate_fps;
80 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
81 }
82
83 int GetLastTargetFramerate() {
84 rtc::CritScope cs(&lock_);
85 return last_target_framerate_fps_;
86 }
87
Niels Möller4db138e2018-04-19 09:04:13 +020088 CpuOveruseOptions GetOptions() { return options_; }
89
Niels Möller7dc26b72017-12-06 10:27:48 +010090 private:
91 rtc::CriticalSection lock_;
92 int last_target_framerate_fps_ RTC_GUARDED_BY(lock_);
93};
94
mflodmancc3d4422017-08-03 08:27:51 -070095class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -070096 public:
Niels Möller213618e2018-07-24 09:29:58 +020097 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
98 const VideoStreamEncoderSettings& settings)
Yves Gerey665174f2018-06-19 15:03:05 +020099 : VideoStreamEncoder(1 /* number_of_cores */,
100 stats_proxy,
101 settings,
Yves Gerey665174f2018-06-19 15:03:05 +0200102 std::unique_ptr<OveruseFrameDetector>(
103 overuse_detector_proxy_ =
104 new CpuOveruseDetectorProxy(stats_proxy))) {}
perkj803d97f2016-11-01 11:45:46 -0700105
sprangb1ca0732017-02-01 08:38:12 -0800106 void PostTaskAndWait(bool down, AdaptReason reason) {
Niels Möllerc572ff32018-11-07 08:43:50 +0100107 rtc::Event event;
kthelgason876222f2016-11-29 01:44:11 -0800108 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800109 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700110 event.Set();
111 });
perkj070ba852017-02-16 15:46:27 -0800112 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700113 }
114
kthelgason2fc52542017-03-03 00:24:41 -0800115 // This is used as a synchronisation mechanism, to make sure that the
116 // encoder queue is not blocked before we start sending it frames.
117 void WaitUntilTaskQueueIsIdle() {
Niels Möllerc572ff32018-11-07 08:43:50 +0100118 rtc::Event event;
Yves Gerey665174f2018-06-19 15:03:05 +0200119 encoder_queue()->PostTask([&event] { event.Set(); });
kthelgason2fc52542017-03-03 00:24:41 -0800120 ASSERT_TRUE(event.Wait(5000));
121 }
122
sprangb1ca0732017-02-01 08:38:12 -0800123 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800124
sprangb1ca0732017-02-01 08:38:12 -0800125 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800126
sprangb1ca0732017-02-01 08:38:12 -0800127 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800128
sprangb1ca0732017-02-01 08:38:12 -0800129 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700130
Niels Möller7dc26b72017-12-06 10:27:48 +0100131 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700132};
133
asapersson5f7226f2016-11-25 04:37:00 -0800134class VideoStreamFactory
135 : public VideoEncoderConfig::VideoStreamFactoryInterface {
136 public:
sprangfda496a2017-06-15 04:21:07 -0700137 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
138 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800139 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700140 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800141 }
142
143 private:
144 std::vector<VideoStream> CreateEncoderStreams(
145 int width,
146 int height,
147 const VideoEncoderConfig& encoder_config) override {
148 std::vector<VideoStream> streams =
149 test::CreateVideoStreams(width, height, encoder_config);
150 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +0100151 stream.num_temporal_layers = num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700152 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800153 }
154 return streams;
155 }
sprangfda496a2017-06-15 04:21:07 -0700156
asapersson5f7226f2016-11-25 04:37:00 -0800157 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700158 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800159};
160
sprangb1ca0732017-02-01 08:38:12 -0800161class AdaptingFrameForwarder : public test::FrameForwarder {
162 public:
163 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700164 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800165
166 void set_adaptation_enabled(bool enabled) {
167 rtc::CritScope cs(&crit_);
168 adaptation_enabled_ = enabled;
169 }
170
asaperssonfab67072017-04-04 05:51:49 -0700171 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800172 rtc::CritScope cs(&crit_);
173 return adaptation_enabled_;
174 }
175
asapersson09f05612017-05-15 23:40:18 -0700176 rtc::VideoSinkWants last_wants() const {
177 rtc::CritScope cs(&crit_);
178 return last_wants_;
179 }
180
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200181 absl::optional<int> last_sent_width() const { return last_width_; }
182 absl::optional<int> last_sent_height() const { return last_height_; }
Jonathan Yubc771b72017-12-08 17:04:29 -0800183
sprangb1ca0732017-02-01 08:38:12 -0800184 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
185 int cropped_width = 0;
186 int cropped_height = 0;
187 int out_width = 0;
188 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700189 if (adaption_enabled()) {
190 if (adapter_.AdaptFrameResolution(
191 video_frame.width(), video_frame.height(),
192 video_frame.timestamp_us() * 1000, &cropped_width,
193 &cropped_height, &out_width, &out_height)) {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100194 VideoFrame adapted_frame =
195 VideoFrame::Builder()
196 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
197 nullptr, out_width, out_height))
198 .set_timestamp_rtp(99)
199 .set_timestamp_ms(99)
200 .set_rotation(kVideoRotation_0)
201 .build();
sprangc5d62e22017-04-02 23:53:04 -0700202 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
203 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800204 last_width_.emplace(adapted_frame.width());
205 last_height_.emplace(adapted_frame.height());
206 } else {
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200207 last_width_ = absl::nullopt;
208 last_height_ = absl::nullopt;
sprangc5d62e22017-04-02 23:53:04 -0700209 }
sprangb1ca0732017-02-01 08:38:12 -0800210 } else {
211 test::FrameForwarder::IncomingCapturedFrame(video_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800212 last_width_.emplace(video_frame.width());
213 last_height_.emplace(video_frame.height());
sprangb1ca0732017-02-01 08:38:12 -0800214 }
215 }
216
217 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
218 const rtc::VideoSinkWants& wants) override {
219 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700220 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700221 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
222 wants.max_pixel_count,
223 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800224 test::FrameForwarder::AddOrUpdateSink(sink, wants);
225 }
sprangb1ca0732017-02-01 08:38:12 -0800226 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700227 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
228 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200229 absl::optional<int> last_width_;
230 absl::optional<int> last_height_;
sprangb1ca0732017-02-01 08:38:12 -0800231};
sprangc5d62e22017-04-02 23:53:04 -0700232
Niels Möller213618e2018-07-24 09:29:58 +0200233// TODO(nisse): Mock only VideoStreamEncoderObserver.
sprangc5d62e22017-04-02 23:53:04 -0700234class MockableSendStatisticsProxy : public SendStatisticsProxy {
235 public:
236 MockableSendStatisticsProxy(Clock* clock,
237 const VideoSendStream::Config& config,
238 VideoEncoderConfig::ContentType content_type)
239 : SendStatisticsProxy(clock, config, content_type) {}
240
241 VideoSendStream::Stats GetStats() override {
242 rtc::CritScope cs(&lock_);
243 if (mock_stats_)
244 return *mock_stats_;
245 return SendStatisticsProxy::GetStats();
246 }
247
Niels Möller213618e2018-07-24 09:29:58 +0200248 int GetInputFrameRate() const override {
249 rtc::CritScope cs(&lock_);
250 if (mock_stats_)
251 return mock_stats_->input_frame_rate;
252 return SendStatisticsProxy::GetInputFrameRate();
253 }
sprangc5d62e22017-04-02 23:53:04 -0700254 void SetMockStats(const VideoSendStream::Stats& stats) {
255 rtc::CritScope cs(&lock_);
256 mock_stats_.emplace(stats);
257 }
258
259 void ResetMockStats() {
260 rtc::CritScope cs(&lock_);
261 mock_stats_.reset();
262 }
263
264 private:
265 rtc::CriticalSection lock_;
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200266 absl::optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700267};
268
sprang4847ae62017-06-27 07:06:52 -0700269class MockBitrateObserver : public VideoBitrateAllocationObserver {
270 public:
Erik Språng566124a2018-04-23 12:32:22 +0200271 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const VideoBitrateAllocation&));
sprang4847ae62017-06-27 07:06:52 -0700272};
273
perkj803d97f2016-11-01 11:45:46 -0700274} // namespace
275
mflodmancc3d4422017-08-03 08:27:51 -0700276class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700277 public:
278 static const int kDefaultTimeoutMs = 30 * 1000;
279
mflodmancc3d4422017-08-03 08:27:51 -0700280 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700281 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700282 codec_width_(320),
283 codec_height_(240),
Åsa Persson8c1bf952018-09-13 10:42:19 +0200284 max_framerate_(kDefaultFramerate),
perkj26091b12016-09-01 01:17:40 -0700285 fake_encoder_(),
Niels Möller4db138e2018-04-19 09:04:13 +0200286 encoder_factory_(&fake_encoder_),
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800287 bitrate_allocator_factory_(CreateBuiltinVideoBitrateAllocatorFactory()),
sprangc5d62e22017-04-02 23:53:04 -0700288 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700289 Clock::GetRealTimeClock(),
290 video_send_config_,
291 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700292 sink_(&fake_encoder_) {}
293
294 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700295 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700296 video_send_config_ = VideoSendStream::Config(nullptr);
Niels Möller4db138e2018-04-19 09:04:13 +0200297 video_send_config_.encoder_settings.encoder_factory = &encoder_factory_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800298 video_send_config_.encoder_settings.bitrate_allocator_factory =
299 bitrate_allocator_factory_.get();
Niels Möller259a4972018-04-05 15:36:51 +0200300 video_send_config_.rtp.payload_name = "FAKE";
301 video_send_config_.rtp.payload_type = 125;
perkj26091b12016-09-01 01:17:40 -0700302
Per512ecb32016-09-23 15:52:06 +0200303 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200304 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700305 video_encoder_config.video_stream_factory =
306 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100307 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700308
309 // Framerate limit is specified by the VideoStreamFactory.
310 std::vector<VideoStream> streams =
311 video_encoder_config.video_stream_factory->CreateEncoderStreams(
312 codec_width_, codec_height_, video_encoder_config);
313 max_framerate_ = streams[0].max_framerate;
314 fake_clock_.SetTimeMicros(1234);
315
Niels Möllerf1338562018-04-26 09:51:47 +0200316 ConfigureEncoder(std::move(video_encoder_config));
asapersson5f7226f2016-11-25 04:37:00 -0800317 }
318
Niels Möllerf1338562018-04-26 09:51:47 +0200319 void ConfigureEncoder(VideoEncoderConfig video_encoder_config) {
mflodmancc3d4422017-08-03 08:27:51 -0700320 if (video_stream_encoder_)
321 video_stream_encoder_->Stop();
322 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700323 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700324 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
325 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700326 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -0700327 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
328 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200329 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -0700330 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800331 }
332
333 void ResetEncoder(const std::string& payload_name,
334 size_t num_streams,
335 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700336 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700337 bool screenshare) {
Niels Möller259a4972018-04-05 15:36:51 +0200338 video_send_config_.rtp.payload_name = payload_name;
asapersson5f7226f2016-11-25 04:37:00 -0800339
340 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200341 video_encoder_config.codec_type = PayloadStringToCodecType(payload_name);
asapersson5f7226f2016-11-25 04:37:00 -0800342 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800343 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800344 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700345 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
346 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700347 video_encoder_config.content_type =
348 screenshare ? VideoEncoderConfig::ContentType::kScreen
349 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700350 if (payload_name == "VP9") {
351 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
352 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
353 video_encoder_config.encoder_specific_settings =
354 new rtc::RefCountedObject<
355 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
356 }
Niels Möllerf1338562018-04-26 09:51:47 +0200357 ConfigureEncoder(std::move(video_encoder_config));
perkj26091b12016-09-01 01:17:40 -0700358 }
359
sprang57c2fff2017-01-16 06:24:02 -0800360 VideoFrame CreateFrame(int64_t ntp_time_ms,
361 rtc::Event* destruction_event) const {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100362 VideoFrame frame =
363 VideoFrame::Builder()
364 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
365 destruction_event, codec_width_, codec_height_))
366 .set_timestamp_rtp(99)
367 .set_timestamp_ms(99)
368 .set_rotation(kVideoRotation_0)
369 .build();
sprang57c2fff2017-01-16 06:24:02 -0800370 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700371 return frame;
372 }
373
sprang57c2fff2017-01-16 06:24:02 -0800374 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100375 VideoFrame frame =
376 VideoFrame::Builder()
377 .set_video_frame_buffer(
378 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height))
379 .set_timestamp_rtp(99)
380 .set_timestamp_ms(99)
381 .set_rotation(kVideoRotation_0)
382 .build();
sprang57c2fff2017-01-16 06:24:02 -0800383 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700384 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700385 return frame;
386 }
387
asapersson02465b82017-04-10 01:12:52 -0700388 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700389 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700390 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
391 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700392 }
393
asapersson09f05612017-05-15 23:40:18 -0700394 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
395 const rtc::VideoSinkWants& wants2) {
396 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
397 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
398 }
399
Åsa Persson8c1bf952018-09-13 10:42:19 +0200400 void VerifyFpsMaxResolutionMax(const rtc::VideoSinkWants& wants) {
401 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
402 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
403 EXPECT_FALSE(wants.target_pixel_count);
404 }
405
asapersson09f05612017-05-15 23:40:18 -0700406 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
407 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200408 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700409 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
410 EXPECT_GT(wants1.max_pixel_count, 0);
411 }
412
413 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
414 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200415 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700416 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
417 }
418
asaperssonf7e294d2017-06-13 23:25:22 -0700419 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
420 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200421 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700422 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
423 }
424
425 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
426 const rtc::VideoSinkWants& wants2) {
427 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
428 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
429 }
430
431 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
432 const rtc::VideoSinkWants& wants2) {
433 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
434 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
435 }
436
437 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
438 const rtc::VideoSinkWants& wants2) {
439 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
440 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
441 EXPECT_GT(wants1.max_pixel_count, 0);
442 }
443
444 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
445 const rtc::VideoSinkWants& wants2) {
446 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
447 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
448 }
449
asapersson09f05612017-05-15 23:40:18 -0700450 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
451 int pixel_count) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200452 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700453 EXPECT_LT(wants.max_pixel_count, pixel_count);
454 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700455 }
456
457 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
458 EXPECT_LT(wants.max_framerate_fps, fps);
459 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
460 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700461 }
462
asaperssonf7e294d2017-06-13 23:25:22 -0700463 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
464 int expected_fps) {
465 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
466 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
467 EXPECT_FALSE(wants.target_pixel_count);
468 }
469
Jonathan Yubc771b72017-12-08 17:04:29 -0800470 void VerifyBalancedModeFpsRange(const rtc::VideoSinkWants& wants,
471 int last_frame_pixels) {
472 // Balanced mode should always scale FPS to the desired range before
473 // attempting to scale resolution.
474 int fps_limit = wants.max_framerate_fps;
475 if (last_frame_pixels <= 320 * 240) {
476 EXPECT_TRUE(7 <= fps_limit && fps_limit <= 10);
477 } else if (last_frame_pixels <= 480 * 270) {
478 EXPECT_TRUE(10 <= fps_limit && fps_limit <= 15);
479 } else if (last_frame_pixels <= 640 * 480) {
480 EXPECT_LE(15, fps_limit);
481 } else {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200482 EXPECT_EQ(kDefaultFramerate, fps_limit);
Jonathan Yubc771b72017-12-08 17:04:29 -0800483 }
484 }
485
sprang4847ae62017-06-27 07:06:52 -0700486 void WaitForEncodedFrame(int64_t expected_ntp_time) {
487 sink_.WaitForEncodedFrame(expected_ntp_time);
488 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
489 }
490
491 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
492 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
493 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
494 return ok;
495 }
496
497 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
498 sink_.WaitForEncodedFrame(expected_width, expected_height);
499 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
500 }
501
502 void ExpectDroppedFrame() {
503 sink_.ExpectDroppedFrame();
504 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
505 }
506
507 bool WaitForFrame(int64_t timeout_ms) {
508 bool ok = sink_.WaitForFrame(timeout_ms);
509 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
510 return ok;
511 }
512
perkj26091b12016-09-01 01:17:40 -0700513 class TestEncoder : public test::FakeEncoder {
514 public:
Niels Möllerc572ff32018-11-07 08:43:50 +0100515 TestEncoder() : FakeEncoder(Clock::GetRealTimeClock()) {}
perkj26091b12016-09-01 01:17:40 -0700516
asaperssonfab67072017-04-04 05:51:49 -0700517 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800518 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700519 return config_;
520 }
521
522 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800523 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700524 block_next_encode_ = true;
525 }
526
Erik Språngaed30702018-11-05 12:57:17 +0100527 VideoEncoder::EncoderInfo GetEncoderInfo() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800528 rtc::CritScope lock(&local_crit_sect_);
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100529 EncoderInfo info;
530 if (initialized_) {
531 if (quality_scaling_) {
532 info.scaling_settings =
533 VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
534 }
535 info.is_hardware_accelerated = is_hardware_accelerated_;
Erik Språngaed30702018-11-05 12:57:17 +0100536 }
537 return info;
kthelgason876222f2016-11-29 01:44:11 -0800538 }
539
perkjfa10b552016-10-02 23:45:26 -0700540 void ContinueEncode() { continue_encode_event_.Set(); }
541
542 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
543 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800544 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700545 EXPECT_EQ(timestamp_, timestamp);
546 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
547 }
548
kthelgason2fc52542017-03-03 00:24:41 -0800549 void SetQualityScaling(bool b) {
550 rtc::CritScope lock(&local_crit_sect_);
551 quality_scaling_ = b;
552 }
kthelgasonad9010c2017-02-14 00:46:51 -0800553
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100554 void SetIsHardwareAccelerated(bool is_hardware_accelerated) {
555 rtc::CritScope lock(&local_crit_sect_);
556 is_hardware_accelerated_ = is_hardware_accelerated;
557 }
558
sprangfe627f32017-03-29 08:24:59 -0700559 void ForceInitEncodeFailure(bool force_failure) {
560 rtc::CritScope lock(&local_crit_sect_);
561 force_init_encode_failed_ = force_failure;
562 }
563
Niels Möller6bb5ab92019-01-11 11:11:10 +0100564 void SimulateOvershoot(double rate_factor) {
565 rtc::CritScope lock(&local_crit_sect_);
566 rate_factor_ = rate_factor;
567 }
568
569 uint32_t GetLastFramerate() {
570 rtc::CritScope lock(&local_crit_sect_);
571 return last_framerate_;
572 }
573
perkjfa10b552016-10-02 23:45:26 -0700574 private:
perkj26091b12016-09-01 01:17:40 -0700575 int32_t Encode(const VideoFrame& input_image,
576 const CodecSpecificInfo* codec_specific_info,
577 const std::vector<FrameType>* frame_types) override {
578 bool block_encode;
579 {
brandtre78d2662017-01-16 05:57:16 -0800580 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700581 EXPECT_GT(input_image.timestamp(), timestamp_);
582 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
583 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
584
585 timestamp_ = input_image.timestamp();
586 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700587 last_input_width_ = input_image.width();
588 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700589 block_encode = block_next_encode_;
590 block_next_encode_ = false;
591 }
592 int32_t result =
593 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
594 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700595 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700596 return result;
597 }
598
sprangfe627f32017-03-29 08:24:59 -0700599 int32_t InitEncode(const VideoCodec* config,
600 int32_t number_of_cores,
601 size_t max_payload_size) override {
602 int res =
603 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
604 rtc::CritScope lock(&local_crit_sect_);
Erik Språng82fad3d2018-03-21 09:57:23 +0100605 if (config->codecType == kVideoCodecVP8) {
sprangfe627f32017-03-29 08:24:59 -0700606 // Simulate setting up temporal layers, in order to validate the life
607 // cycle of these objects.
608 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
sprangfe627f32017-03-29 08:24:59 -0700609 for (int i = 0; i < num_streams; ++i) {
610 allocated_temporal_layers_.emplace_back(
Erik Språng4529fbc2018-10-12 10:30:31 +0200611 CreateVp8TemporalLayers(Vp8TemporalLayersType::kFixedPattern,
612 config->VP8().numberOfTemporalLayers));
sprangfe627f32017-03-29 08:24:59 -0700613 }
614 }
615 if (force_init_encode_failed_)
616 return -1;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100617
618 initialized_ = true;
sprangfe627f32017-03-29 08:24:59 -0700619 return res;
620 }
621
Niels Möller6bb5ab92019-01-11 11:11:10 +0100622 int32_t SetRateAllocation(const VideoBitrateAllocation& rate_allocation,
623 uint32_t framerate) {
624 rtc::CritScope lock(&local_crit_sect_);
625 VideoBitrateAllocation adjusted_rate_allocation;
626 for (size_t si = 0; si < kMaxSpatialLayers; ++si) {
627 for (size_t ti = 0; ti < kMaxTemporalStreams; ++ti) {
628 if (rate_allocation.HasBitrate(si, ti)) {
629 adjusted_rate_allocation.SetBitrate(
630 si, ti,
631 static_cast<uint32_t>(rate_allocation.GetBitrate(si, ti) *
632 rate_factor_));
633 }
634 }
635 }
636 last_framerate_ = framerate;
637 return FakeEncoder::SetRateAllocation(adjusted_rate_allocation,
638 framerate);
639 }
640
brandtre78d2662017-01-16 05:57:16 -0800641 rtc::CriticalSection local_crit_sect_;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100642 bool initialized_ RTC_GUARDED_BY(local_crit_sect_) = false;
danilchapa37de392017-09-09 04:17:22 -0700643 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700644 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700645 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
646 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
647 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
648 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
649 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100650 bool is_hardware_accelerated_ RTC_GUARDED_BY(local_crit_sect_) = false;
Erik Språng4529fbc2018-10-12 10:30:31 +0200651 std::vector<std::unique_ptr<Vp8TemporalLayers>> allocated_temporal_layers_
danilchapa37de392017-09-09 04:17:22 -0700652 RTC_GUARDED_BY(local_crit_sect_);
653 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
Niels Möller6bb5ab92019-01-11 11:11:10 +0100654 double rate_factor_ RTC_GUARDED_BY(local_crit_sect_) = 1.0;
655 uint32_t last_framerate_ RTC_GUARDED_BY(local_crit_sect_) = 0;
perkj26091b12016-09-01 01:17:40 -0700656 };
657
mflodmancc3d4422017-08-03 08:27:51 -0700658 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700659 public:
660 explicit TestSink(TestEncoder* test_encoder)
Niels Möllerc572ff32018-11-07 08:43:50 +0100661 : test_encoder_(test_encoder) {}
perkj26091b12016-09-01 01:17:40 -0700662
perkj26091b12016-09-01 01:17:40 -0700663 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700664 EXPECT_TRUE(
665 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
666 }
667
668 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
669 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700670 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700671 if (!encoded_frame_event_.Wait(timeout_ms))
672 return false;
perkj26091b12016-09-01 01:17:40 -0700673 {
674 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800675 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700676 }
677 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700678 return true;
perkj26091b12016-09-01 01:17:40 -0700679 }
680
sprangb1ca0732017-02-01 08:38:12 -0800681 void WaitForEncodedFrame(uint32_t expected_width,
682 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700683 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100684 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700685 }
686
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100687 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700688 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800689 uint32_t width = 0;
690 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800691 {
692 rtc::CritScope lock(&crit_);
693 width = last_width_;
694 height = last_height_;
695 }
696 EXPECT_EQ(expected_height, height);
697 EXPECT_EQ(expected_width, width);
698 }
699
kthelgason2fc52542017-03-03 00:24:41 -0800700 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800701
sprangc5d62e22017-04-02 23:53:04 -0700702 bool WaitForFrame(int64_t timeout_ms) {
703 return encoded_frame_event_.Wait(timeout_ms);
704 }
705
perkj26091b12016-09-01 01:17:40 -0700706 void SetExpectNoFrames() {
707 rtc::CritScope lock(&crit_);
708 expect_frames_ = false;
709 }
710
asaperssonfab67072017-04-04 05:51:49 -0700711 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200712 rtc::CritScope lock(&crit_);
713 return number_of_reconfigurations_;
714 }
715
asaperssonfab67072017-04-04 05:51:49 -0700716 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200717 rtc::CritScope lock(&crit_);
718 return min_transmit_bitrate_bps_;
719 }
720
perkj26091b12016-09-01 01:17:40 -0700721 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700722 Result OnEncodedImage(
723 const EncodedImage& encoded_image,
724 const CodecSpecificInfo* codec_specific_info,
725 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200726 rtc::CritScope lock(&crit_);
727 EXPECT_TRUE(expect_frames_);
Niels Möller23775882018-08-16 10:24:12 +0200728 last_timestamp_ = encoded_image.Timestamp();
sprangb1ca0732017-02-01 08:38:12 -0800729 last_width_ = encoded_image._encodedWidth;
730 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200731 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800732 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200733 }
734
735 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
736 int min_transmit_bitrate_bps) override {
737 rtc::CriticalSection crit_;
738 ++number_of_reconfigurations_;
739 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
740 }
741
perkj26091b12016-09-01 01:17:40 -0700742 rtc::CriticalSection crit_;
743 TestEncoder* test_encoder_;
744 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800745 uint32_t last_timestamp_ = 0;
746 uint32_t last_height_ = 0;
747 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700748 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200749 int number_of_reconfigurations_ = 0;
750 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700751 };
752
753 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100754 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200755 int codec_width_;
756 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700757 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700758 TestEncoder fake_encoder_;
Niels Möllercbcbc222018-09-28 09:07:24 +0200759 test::VideoEncoderProxyFactory encoder_factory_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800760 std::unique_ptr<VideoBitrateAllocatorFactory> bitrate_allocator_factory_;
sprangc5d62e22017-04-02 23:53:04 -0700761 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700762 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800763 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700764 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700765 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700766};
767
mflodmancc3d4422017-08-03 08:27:51 -0700768TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
769 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Niels Möllerc572ff32018-11-07 08:43:50 +0100770 rtc::Event frame_destroyed_event;
perkja49cbd32016-09-16 07:53:41 -0700771 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700772 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700773 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700774 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700775}
776
mflodmancc3d4422017-08-03 08:27:51 -0700777TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700778 // Dropped since no target bitrate has been set.
Niels Möllerc572ff32018-11-07 08:43:50 +0100779 rtc::Event frame_destroyed_event;
Sebastian Janssona3177052018-04-10 13:05:49 +0200780 // The encoder will cache up to one frame for a short duration. Adding two
781 // frames means that the first frame will be dropped and the second frame will
782 // be sent when the encoder is enabled.
perkja49cbd32016-09-16 07:53:41 -0700783 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
Sebastian Janssona3177052018-04-10 13:05:49 +0200784 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkja49cbd32016-09-16 07:53:41 -0700785 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700786
mflodmancc3d4422017-08-03 08:27:51 -0700787 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700788
Sebastian Janssona3177052018-04-10 13:05:49 +0200789 // The pending frame should be received.
sprang4847ae62017-06-27 07:06:52 -0700790 WaitForEncodedFrame(2);
Sebastian Janssona3177052018-04-10 13:05:49 +0200791 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
792
793 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700794 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700795}
796
mflodmancc3d4422017-08-03 08:27:51 -0700797TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
798 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700799 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700800 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700801
mflodmancc3d4422017-08-03 08:27:51 -0700802 video_stream_encoder_->OnBitrateUpdated(0, 0, 0);
Sebastian Janssona3177052018-04-10 13:05:49 +0200803 // The encoder will cache up to one frame for a short duration. Adding two
804 // frames means that the first frame will be dropped and the second frame will
805 // be sent when the encoder is resumed.
perkja49cbd32016-09-16 07:53:41 -0700806 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Sebastian Janssona3177052018-04-10 13:05:49 +0200807 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700808
mflodmancc3d4422017-08-03 08:27:51 -0700809 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -0700810 WaitForEncodedFrame(3);
Sebastian Janssona3177052018-04-10 13:05:49 +0200811 video_source_.IncomingCapturedFrame(CreateFrame(4, nullptr));
812 WaitForEncodedFrame(4);
mflodmancc3d4422017-08-03 08:27:51 -0700813 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700814}
815
mflodmancc3d4422017-08-03 08:27:51 -0700816TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
817 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700818 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700819 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700820
821 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700822 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700823
perkja49cbd32016-09-16 07:53:41 -0700824 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700825 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700826 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700827}
828
mflodmancc3d4422017-08-03 08:27:51 -0700829TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
830 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700831
perkja49cbd32016-09-16 07:53:41 -0700832 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700833 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700834
mflodmancc3d4422017-08-03 08:27:51 -0700835 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700836 sink_.SetExpectNoFrames();
Niels Möllerc572ff32018-11-07 08:43:50 +0100837 rtc::Event frame_destroyed_event;
perkja49cbd32016-09-16 07:53:41 -0700838 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
839 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700840}
841
mflodmancc3d4422017-08-03 08:27:51 -0700842TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
843 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700844
845 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700846 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700847 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700848 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
849 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700850 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
851 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700852 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700853 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700854
mflodmancc3d4422017-08-03 08:27:51 -0700855 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700856}
857
mflodmancc3d4422017-08-03 08:27:51 -0700858TEST_F(VideoStreamEncoderTest,
859 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
860 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100861 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200862
863 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200864 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700865 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100866 // The encoder will have been configured once when the first frame is
867 // received.
868 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200869
870 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200871 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200872 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -0700873 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200874 kMaxPayloadLength);
Per512ecb32016-09-23 15:52:06 +0200875
876 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200877 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700878 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100879 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700880 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700881
mflodmancc3d4422017-08-03 08:27:51 -0700882 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -0700883}
884
mflodmancc3d4422017-08-03 08:27:51 -0700885TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
886 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkjfa10b552016-10-02 23:45:26 -0700887
888 // Capture a frame and wait for it to synchronize with the encoder thread.
889 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700890 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100891 // The encoder will have been configured once.
892 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700893 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
894 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
895
896 codec_width_ *= 2;
897 codec_height_ *= 2;
898 // Capture a frame with a higher resolution and wait for it to synchronize
899 // with the encoder thread.
900 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700901 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700902 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
903 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100904 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700905
mflodmancc3d4422017-08-03 08:27:51 -0700906 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -0700907}
908
mflodmancc3d4422017-08-03 08:27:51 -0700909TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -0700910 EXPECT_TRUE(video_source_.has_sinks());
911 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700912 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700913 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -0700914 EXPECT_FALSE(video_source_.has_sinks());
915 EXPECT_TRUE(new_video_source.has_sinks());
916
mflodmancc3d4422017-08-03 08:27:51 -0700917 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700918}
919
mflodmancc3d4422017-08-03 08:27:51 -0700920TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -0700921 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700922 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -0700923 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700924 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700925}
926
Jonathan Yubc771b72017-12-08 17:04:29 -0800927TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
928 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -0700929 const int kWidth = 1280;
930 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -0800931
932 // We rely on the automatic resolution adaptation, but we handle framerate
933 // adaptation manually by mocking the stats proxy.
934 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -0700935
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700936 // Enable BALANCED preference, no initial limitation.
Jonathan Yubc771b72017-12-08 17:04:29 -0800937 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700938 video_stream_encoder_->SetSource(&video_source_,
939 webrtc::DegradationPreference::BALANCED);
Jonathan Yubc771b72017-12-08 17:04:29 -0800940 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -0700941 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800942 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -0700943 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
944
Jonathan Yubc771b72017-12-08 17:04:29 -0800945 // Adapt down as far as possible.
946 rtc::VideoSinkWants last_wants;
947 int64_t t = 1;
948 int loop_count = 0;
949 do {
950 ++loop_count;
951 last_wants = video_source_.sink_wants();
952
953 // Simulate the framerate we've been asked to adapt to.
954 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
955 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
956 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
957 mock_stats.input_frame_rate = fps;
958 stats_proxy_->SetMockStats(mock_stats);
959
960 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
961 sink_.WaitForEncodedFrame(t);
962 t += frame_interval_ms;
963
mflodmancc3d4422017-08-03 08:27:51 -0700964 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -0800965 VerifyBalancedModeFpsRange(
966 video_source_.sink_wants(),
967 *video_source_.last_sent_width() * *video_source_.last_sent_height());
968 } while (video_source_.sink_wants().max_pixel_count <
969 last_wants.max_pixel_count ||
970 video_source_.sink_wants().max_framerate_fps <
971 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700972
Jonathan Yubc771b72017-12-08 17:04:29 -0800973 // Verify that we've adapted all the way down.
974 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700975 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800976 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
977 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -0700978 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -0800979 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
980 *video_source_.last_sent_height());
981 EXPECT_EQ(kMinBalancedFramerateFps,
982 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700983
Jonathan Yubc771b72017-12-08 17:04:29 -0800984 // Adapt back up the same number of times we adapted down.
985 for (int i = 0; i < loop_count - 1; ++i) {
986 last_wants = video_source_.sink_wants();
987
988 // Simulate the framerate we've been asked to adapt to.
989 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
990 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
991 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
992 mock_stats.input_frame_rate = fps;
993 stats_proxy_->SetMockStats(mock_stats);
994
995 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
996 sink_.WaitForEncodedFrame(t);
997 t += frame_interval_ms;
998
mflodmancc3d4422017-08-03 08:27:51 -0700999 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -08001000 VerifyBalancedModeFpsRange(
1001 video_source_.sink_wants(),
1002 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1003 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
1004 last_wants.max_pixel_count ||
1005 video_source_.sink_wants().max_framerate_fps >
1006 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001007 }
1008
Åsa Persson8c1bf952018-09-13 10:42:19 +02001009 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001010 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001011 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001012 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1013 EXPECT_EQ((loop_count - 1) * 2,
1014 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -07001015
mflodmancc3d4422017-08-03 08:27:51 -07001016 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001017}
mflodmancc3d4422017-08-03 08:27:51 -07001018TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
1019 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001020 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001021
sprangc5d62e22017-04-02 23:53:04 -07001022 const int kFrameWidth = 1280;
1023 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07001024
Åsa Persson8c1bf952018-09-13 10:42:19 +02001025 int64_t frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -07001026
kthelgason5e13d412016-12-01 03:59:51 -08001027 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001028 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001029 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001030 frame_timestamp += kFrameIntervalMs;
1031
perkj803d97f2016-11-01 11:45:46 -07001032 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001033 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001034 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001035 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001036 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001037 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -07001038
asapersson0944a802017-04-07 00:57:58 -07001039 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -07001040 // wanted resolution.
1041 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
1042 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
1043 kFrameWidth * kFrameHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001044 EXPECT_EQ(kDefaultFramerate, video_source_.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001045
1046 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -07001047 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001048 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001049 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001050
sprangc5d62e22017-04-02 23:53:04 -07001051 // Initially no degradation registered.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001052 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001053
sprangc5d62e22017-04-02 23:53:04 -07001054 // Force an input frame rate to be available, or the adaptation call won't
1055 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -07001056 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -07001057 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -07001058 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -07001059 stats_proxy_->SetMockStats(stats);
1060
mflodmancc3d4422017-08-03 08:27:51 -07001061 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001062 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001063 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001064 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001065 frame_timestamp += kFrameIntervalMs;
1066
1067 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001068 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001069 EXPECT_EQ(std::numeric_limits<int>::max(),
1070 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001071 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001072
asapersson02465b82017-04-10 01:12:52 -07001073 // Turn off degradation completely.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001074 video_stream_encoder_->SetSource(&new_video_source,
1075 webrtc::DegradationPreference::DISABLED);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001076 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001077
mflodmancc3d4422017-08-03 08:27:51 -07001078 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001079 new_video_source.IncomingCapturedFrame(
1080 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001081 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001082 frame_timestamp += kFrameIntervalMs;
1083
1084 // Still no degradation.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001085 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001086
1087 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001088 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001089 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
sprangc5d62e22017-04-02 23:53:04 -07001090 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1091 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001092 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001093 EXPECT_EQ(kDefaultFramerate, new_video_source.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001094
1095 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001096 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001097 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001098 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1099 EXPECT_EQ(std::numeric_limits<int>::max(),
1100 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001101 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001102
mflodmancc3d4422017-08-03 08:27:51 -07001103 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001104}
1105
mflodmancc3d4422017-08-03 08:27:51 -07001106TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
1107 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001108
asaperssonfab67072017-04-04 05:51:49 -07001109 const int kWidth = 1280;
1110 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001111 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001112 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001113 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1114 EXPECT_FALSE(stats.bw_limited_resolution);
1115 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1116
1117 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001118 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001119 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001120 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001121
1122 stats = stats_proxy_->GetStats();
1123 EXPECT_TRUE(stats.bw_limited_resolution);
1124 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1125
1126 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001127 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001128 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001129 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001130
1131 stats = stats_proxy_->GetStats();
1132 EXPECT_FALSE(stats.bw_limited_resolution);
1133 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1134 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1135
mflodmancc3d4422017-08-03 08:27:51 -07001136 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001137}
1138
mflodmancc3d4422017-08-03 08:27:51 -07001139TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
1140 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001141
1142 const int kWidth = 1280;
1143 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001144 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001145 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001146 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1147 EXPECT_FALSE(stats.cpu_limited_resolution);
1148 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1149
1150 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001151 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001152 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001153 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001154
1155 stats = stats_proxy_->GetStats();
1156 EXPECT_TRUE(stats.cpu_limited_resolution);
1157 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1158
1159 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001160 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001161 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001162 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001163
1164 stats = stats_proxy_->GetStats();
1165 EXPECT_FALSE(stats.cpu_limited_resolution);
1166 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001167 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001168
mflodmancc3d4422017-08-03 08:27:51 -07001169 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001170}
1171
mflodmancc3d4422017-08-03 08:27:51 -07001172TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
1173 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001174
asaperssonfab67072017-04-04 05:51:49 -07001175 const int kWidth = 1280;
1176 const int kHeight = 720;
1177 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001178 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001179 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001180 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001181 EXPECT_FALSE(stats.cpu_limited_resolution);
1182 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1183
asaperssonfab67072017-04-04 05:51:49 -07001184 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001185 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001186 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001187 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001188 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001189 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001190 EXPECT_TRUE(stats.cpu_limited_resolution);
1191 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1192
1193 // Set new source with adaptation still enabled.
1194 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001195 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001196 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001197
asaperssonfab67072017-04-04 05:51:49 -07001198 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001199 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001200 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001201 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001202 EXPECT_TRUE(stats.cpu_limited_resolution);
1203 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1204
1205 // Set adaptation disabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001206 video_stream_encoder_->SetSource(&new_video_source,
1207 webrtc::DegradationPreference::DISABLED);
kthelgason876222f2016-11-29 01:44:11 -08001208
asaperssonfab67072017-04-04 05:51:49 -07001209 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001210 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001211 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001212 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001213 EXPECT_FALSE(stats.cpu_limited_resolution);
1214 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1215
1216 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001217 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001218 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001219
asaperssonfab67072017-04-04 05:51:49 -07001220 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001221 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001222 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001223 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001224 EXPECT_TRUE(stats.cpu_limited_resolution);
1225 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1226
asaperssonfab67072017-04-04 05:51:49 -07001227 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001228 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001229 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001230 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001231 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001232 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001233 EXPECT_FALSE(stats.cpu_limited_resolution);
1234 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001235 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001236
mflodmancc3d4422017-08-03 08:27:51 -07001237 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001238}
1239
mflodmancc3d4422017-08-03 08:27:51 -07001240TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
1241 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001242
asaperssonfab67072017-04-04 05:51:49 -07001243 const int kWidth = 1280;
1244 const int kHeight = 720;
1245 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001246 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001247 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001248 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001249 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001250 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001251
1252 // Set new source with adaptation still enabled.
1253 test::FrameForwarder new_video_source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001254 video_stream_encoder_->SetSource(&new_video_source,
1255 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001256
asaperssonfab67072017-04-04 05:51:49 -07001257 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001258 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001259 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001260 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001261 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001262 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001263
asaperssonfab67072017-04-04 05:51:49 -07001264 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001265 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001266 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001267 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001268 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001269 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001270 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001271 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001272
asaperssonfab67072017-04-04 05:51:49 -07001273 // Set new source with adaptation still enabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001274 video_stream_encoder_->SetSource(&new_video_source,
1275 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001276
asaperssonfab67072017-04-04 05:51:49 -07001277 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001278 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001279 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001280 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001281 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001282 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001283
asapersson02465b82017-04-10 01:12:52 -07001284 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001285 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001286 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001287
asaperssonfab67072017-04-04 05:51:49 -07001288 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001289 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001290 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001291 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001292 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001293 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1294 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001295
mflodmancc3d4422017-08-03 08:27:51 -07001296 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001297}
1298
mflodmancc3d4422017-08-03 08:27:51 -07001299TEST_F(VideoStreamEncoderTest,
1300 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1301 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001302
1303 const int kWidth = 1280;
1304 const int kHeight = 720;
Åsa Persson8c1bf952018-09-13 10:42:19 +02001305 int64_t timestamp_ms = kFrameIntervalMs;
asapersson36e9eb42017-03-31 05:29:12 -07001306 video_source_.set_adaptation_enabled(true);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001307 video_source_.IncomingCapturedFrame(
1308 CreateFrame(timestamp_ms, kWidth, kHeight));
1309 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001310 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1311 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1312 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1313
1314 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001315 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001316 timestamp_ms += kFrameIntervalMs;
1317 video_source_.IncomingCapturedFrame(
1318 CreateFrame(timestamp_ms, kWidth, kHeight));
1319 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001320 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1321 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1322 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1323
1324 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001325 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001326 timestamp_ms += kFrameIntervalMs;
1327 video_source_.IncomingCapturedFrame(
1328 CreateFrame(timestamp_ms, kWidth, kHeight));
1329 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001330 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1331 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1332 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1333
Niels Möller4db138e2018-04-19 09:04:13 +02001334 // Leave source unchanged, but disable quality scaler.
asapersson36e9eb42017-03-31 05:29:12 -07001335 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02001336
1337 VideoEncoderConfig video_encoder_config;
1338 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
1339 // Make format different, to force recreation of encoder.
1340 video_encoder_config.video_format.parameters["foo"] = "foo";
1341 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001342 kMaxPayloadLength);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001343 timestamp_ms += kFrameIntervalMs;
1344 video_source_.IncomingCapturedFrame(
1345 CreateFrame(timestamp_ms, kWidth, kHeight));
1346 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001347 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1348 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1349 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1350
mflodmancc3d4422017-08-03 08:27:51 -07001351 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001352}
1353
mflodmancc3d4422017-08-03 08:27:51 -07001354TEST_F(VideoStreamEncoderTest,
1355 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
1356 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001357
asapersson0944a802017-04-07 00:57:58 -07001358 const int kWidth = 1280;
1359 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001360 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001361
asaperssonfab67072017-04-04 05:51:49 -07001362 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001363 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001364 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001365 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001366 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001367 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1368
asapersson02465b82017-04-10 01:12:52 -07001369 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001370 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001371 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001372 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001373 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001374 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001375 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001376 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1377
1378 // Set new source with adaptation still enabled.
1379 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001380 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001381 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001382
1383 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001384 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001385 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001386 stats = stats_proxy_->GetStats();
1387 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001388 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001389 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1390
sprangc5d62e22017-04-02 23:53:04 -07001391 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001392 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001393 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001394 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001395 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001396 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001397 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001398 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001399 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001400 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001401 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1402
sprangc5d62e22017-04-02 23:53:04 -07001403 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001404 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001405 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1406 mock_stats.input_frame_rate = 30;
1407 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001408 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001409 stats_proxy_->ResetMockStats();
1410
1411 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001412 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001413 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001414
1415 // Framerate now adapted.
1416 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001417 EXPECT_FALSE(stats.cpu_limited_resolution);
1418 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001419 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1420
1421 // Disable CPU adaptation.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001422 video_stream_encoder_->SetSource(&new_video_source,
1423 webrtc::DegradationPreference::DISABLED);
sprangc5d62e22017-04-02 23:53:04 -07001424 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001425 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001426 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001427
1428 stats = stats_proxy_->GetStats();
1429 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001430 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001431 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1432
1433 // Try to trigger overuse. Should not succeed.
1434 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001435 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001436 stats_proxy_->ResetMockStats();
1437
1438 stats = stats_proxy_->GetStats();
1439 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001440 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001441 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1442
1443 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001444 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001445 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssonfab67072017-04-04 05:51:49 -07001446 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001447 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001448 stats = stats_proxy_->GetStats();
1449 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001450 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001451 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001452
1453 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001454 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001455 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001456 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001457 stats = stats_proxy_->GetStats();
1458 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001459 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001460 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1461
1462 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001463 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001464 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001465 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001466 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001467 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001468 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001469 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001470 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001471 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001472 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1473
1474 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001475 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001476 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001477 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001478 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001479 stats = stats_proxy_->GetStats();
1480 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001481 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001482 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001483 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001484
mflodmancc3d4422017-08-03 08:27:51 -07001485 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001486}
1487
mflodmancc3d4422017-08-03 08:27:51 -07001488TEST_F(VideoStreamEncoderTest,
1489 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001490 const int kWidth = 1280;
1491 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001492 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001493
asaperssonfab67072017-04-04 05:51:49 -07001494 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001495 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001496
asaperssonfab67072017-04-04 05:51:49 -07001497 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001498 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001499
asaperssonfab67072017-04-04 05:51:49 -07001500 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001501 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001502
asaperssonfab67072017-04-04 05:51:49 -07001503 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001504 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001505
kthelgason876222f2016-11-29 01:44:11 -08001506 // Expect a scale down.
1507 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001508 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001509
asapersson02465b82017-04-10 01:12:52 -07001510 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001511 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001512 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001513 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001514
asaperssonfab67072017-04-04 05:51:49 -07001515 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001516 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001517 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001518 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001519
asaperssonfab67072017-04-04 05:51:49 -07001520 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001521 EXPECT_EQ(std::numeric_limits<int>::max(),
1522 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001523
asaperssonfab67072017-04-04 05:51:49 -07001524 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001525 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001526 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001527 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001528
asapersson02465b82017-04-10 01:12:52 -07001529 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001530 EXPECT_EQ(std::numeric_limits<int>::max(),
1531 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001532
mflodmancc3d4422017-08-03 08:27:51 -07001533 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001534}
1535
mflodmancc3d4422017-08-03 08:27:51 -07001536TEST_F(VideoStreamEncoderTest,
1537 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001538 const int kWidth = 1280;
1539 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001540 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001541
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001542 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001543 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001544 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001545 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001546
1547 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001548 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001549 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001550 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1551 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1552
1553 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001554 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001555 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001556 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1557 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1558 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1559
1560 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001561 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001562 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1563 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1564 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1565
mflodmancc3d4422017-08-03 08:27:51 -07001566 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001567}
1568
mflodmancc3d4422017-08-03 08:27:51 -07001569TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001570 const int kWidth = 1280;
1571 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001572 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001573
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001574 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001575 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001576 video_stream_encoder_->SetSource(&source,
1577 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001578 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1579 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001580 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001581
1582 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001583 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001584 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1585 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1586 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1587 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1588
1589 // Trigger adapt down for same input resolution, expect no change.
1590 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1591 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001592 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001593 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1594 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1595 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1596
1597 // Trigger adapt down for larger input resolution, expect no change.
1598 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1599 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001600 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001601 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1602 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1603 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1604
mflodmancc3d4422017-08-03 08:27:51 -07001605 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001606}
1607
mflodmancc3d4422017-08-03 08:27:51 -07001608TEST_F(VideoStreamEncoderTest,
1609 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001610 const int kWidth = 1280;
1611 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001612 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001613
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001614 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001615 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001616 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001617 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001618
1619 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001620 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001621 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001622 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1623 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1624
1625 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001626 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001627 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001628 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1629 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1630
mflodmancc3d4422017-08-03 08:27:51 -07001631 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001632}
1633
mflodmancc3d4422017-08-03 08:27:51 -07001634TEST_F(VideoStreamEncoderTest,
1635 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001636 const int kWidth = 1280;
1637 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001638 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001639
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001640 // Enable MAINTAIN_RESOLUTION preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001641 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001642 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001643 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
asapersson02465b82017-04-10 01:12:52 -07001644
1645 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001646 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001647 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001648 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001649 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1650
1651 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001652 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001653 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001654 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001655 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1656
mflodmancc3d4422017-08-03 08:27:51 -07001657 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001658}
1659
mflodmancc3d4422017-08-03 08:27:51 -07001660TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001661 const int kWidth = 1280;
1662 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001663 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001664
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001665 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001666 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001667 video_stream_encoder_->SetSource(&source,
1668 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001669
1670 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1671 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001672 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001673 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1674 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1675 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1676
1677 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001678 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001679 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001680 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1681 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1682 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1683
mflodmancc3d4422017-08-03 08:27:51 -07001684 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001685}
1686
mflodmancc3d4422017-08-03 08:27:51 -07001687TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001688 const int kWidth = 1280;
1689 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001690 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001691
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001692 // Enable DISABLED preference, no initial limitation.
asapersson09f05612017-05-15 23:40:18 -07001693 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001694 video_stream_encoder_->SetSource(&source,
1695 webrtc::DegradationPreference::DISABLED);
asapersson09f05612017-05-15 23:40:18 -07001696
1697 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1698 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001699 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001700 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1701 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1702 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1703
1704 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001705 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001706 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001707 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1708 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1709 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1710
mflodmancc3d4422017-08-03 08:27:51 -07001711 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001712}
1713
mflodmancc3d4422017-08-03 08:27:51 -07001714TEST_F(VideoStreamEncoderTest,
1715 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001716 const int kWidth = 1280;
1717 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001718 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001719
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001720 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001721 AdaptingFrameForwarder source;
1722 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001723 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001724 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001725
1726 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001727 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001728 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001729 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1730 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1731
1732 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001733 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001734 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001735 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001736 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001737 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1738 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1739
1740 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001741 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001742 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001743 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1744 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1745 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1746
mflodmancc3d4422017-08-03 08:27:51 -07001747 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001748}
1749
mflodmancc3d4422017-08-03 08:27:51 -07001750TEST_F(VideoStreamEncoderTest,
1751 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001752 const int kWidth = 1280;
1753 const int kHeight = 720;
1754 const int kInputFps = 30;
mflodmancc3d4422017-08-03 08:27:51 -07001755 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001756
1757 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1758 stats.input_frame_rate = kInputFps;
1759 stats_proxy_->SetMockStats(stats);
1760
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001761 // Expect no scaling to begin with (preference: MAINTAIN_FRAMERATE).
asapersson09f05612017-05-15 23:40:18 -07001762 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1763 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001764 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001765
1766 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001767 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001768 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1769 sink_.WaitForEncodedFrame(2);
1770 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1771
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001772 // Enable MAINTAIN_RESOLUTION preference.
asapersson09f05612017-05-15 23:40:18 -07001773 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001774 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001775 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001776 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001777
1778 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001779 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001780 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1781 sink_.WaitForEncodedFrame(3);
1782 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1783
1784 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001785 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001786 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001787
mflodmancc3d4422017-08-03 08:27:51 -07001788 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001789}
1790
mflodmancc3d4422017-08-03 08:27:51 -07001791TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001792 const int kWidth = 1280;
1793 const int kHeight = 720;
1794 const size_t kNumFrames = 10;
1795
mflodmancc3d4422017-08-03 08:27:51 -07001796 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001797
asaperssond0de2952017-04-21 01:47:31 -07001798 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001799 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001800 video_source_.set_adaptation_enabled(true);
1801
1802 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1803 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1804
1805 int downscales = 0;
1806 for (size_t i = 1; i <= kNumFrames; i++) {
Åsa Persson8c1bf952018-09-13 10:42:19 +02001807 video_source_.IncomingCapturedFrame(
1808 CreateFrame(i * kFrameIntervalMs, kWidth, kHeight));
1809 WaitForEncodedFrame(i * kFrameIntervalMs);
asaperssond0de2952017-04-21 01:47:31 -07001810
asaperssonfab67072017-04-04 05:51:49 -07001811 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001812 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001813 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001814 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001815
1816 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1817 ++downscales;
1818
1819 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1820 EXPECT_EQ(downscales,
1821 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1822 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001823 }
mflodmancc3d4422017-08-03 08:27:51 -07001824 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001825}
1826
mflodmancc3d4422017-08-03 08:27:51 -07001827TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001828 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1829 const int kWidth = 1280;
1830 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001831 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001832
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001833 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001834 AdaptingFrameForwarder source;
1835 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001836 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001837 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001838
Åsa Persson8c1bf952018-09-13 10:42:19 +02001839 int64_t timestamp_ms = kFrameIntervalMs;
1840 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001841 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001842 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001843 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1844 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1845
1846 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001847 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001848 timestamp_ms += kFrameIntervalMs;
1849 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1850 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001851 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001852 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1853 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1854
1855 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001856 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001857 timestamp_ms += kFrameIntervalMs;
1858 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001859 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001860 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001861 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1862 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1863
1864 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001865 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001866 timestamp_ms += kFrameIntervalMs;
1867 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1868 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001869 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001870 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1871 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1872
1873 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001874 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001875 timestamp_ms += kFrameIntervalMs;
1876 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asapersson09f05612017-05-15 23:40:18 -07001877 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001878 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001879 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1880 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1881
mflodmancc3d4422017-08-03 08:27:51 -07001882 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001883}
1884
mflodmancc3d4422017-08-03 08:27:51 -07001885TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07001886 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
1887 const int kWidth = 1280;
1888 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001889 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001890
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001891 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001892 AdaptingFrameForwarder source;
1893 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001894 video_stream_encoder_->SetSource(&source,
1895 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001896
Åsa Persson8c1bf952018-09-13 10:42:19 +02001897 int64_t timestamp_ms = kFrameIntervalMs;
1898 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001899 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001900 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001901 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1902 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1903
1904 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001905 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001906 timestamp_ms += kFrameIntervalMs;
1907 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1908 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07001909 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1910 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1911 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1912
1913 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001914 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001915 timestamp_ms += kFrameIntervalMs;
1916 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001917 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001918 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001919 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1920 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1921
1922 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001923 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001924 timestamp_ms += kFrameIntervalMs;
1925 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1926 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07001927 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1928 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1929 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1930
1931 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001932 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001933 timestamp_ms += kFrameIntervalMs;
1934 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001935 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001936 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001937 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1938 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1939
mflodmancc3d4422017-08-03 08:27:51 -07001940 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001941}
1942
mflodmancc3d4422017-08-03 08:27:51 -07001943TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001944 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
1945 const int kWidth = 1280;
1946 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001947 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001948
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001949 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001950 AdaptingFrameForwarder source;
1951 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001952 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001953 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001954
Åsa Persson8c1bf952018-09-13 10:42:19 +02001955 int64_t timestamp_ms = kFrameIntervalMs;
1956 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001957 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001958 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001959 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1960 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1961 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1962 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1963
1964 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001965 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001966 timestamp_ms += kFrameIntervalMs;
1967 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1968 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001969 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001970 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1971 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1972 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1973 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1974
1975 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07001976 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001977 timestamp_ms += kFrameIntervalMs;
1978 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1979 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001980 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001981 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1982 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1983 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1984 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1985
Jonathan Yubc771b72017-12-08 17:04:29 -08001986 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001987 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001988 timestamp_ms += kFrameIntervalMs;
1989 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1990 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001991 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001992 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1993 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001994 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001995 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1996
Jonathan Yubc771b72017-12-08 17:04:29 -08001997 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07001998 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001999 timestamp_ms += kFrameIntervalMs;
2000 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2001 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002002 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002003 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07002004 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2005 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2006 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2007 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2008
Jonathan Yubc771b72017-12-08 17:04:29 -08002009 // Trigger quality adapt down, expect no change (min resolution reached).
2010 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002011 timestamp_ms += kFrameIntervalMs;
2012 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2013 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002014 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
2015 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2016 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2017 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2018 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2019
2020 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002021 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002022 timestamp_ms += kFrameIntervalMs;
2023 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2024 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002025 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002026 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2027 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2028 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2029 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2030
2031 // Trigger cpu adapt up, expect upscaled resolution (640x360).
2032 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002033 timestamp_ms += kFrameIntervalMs;
2034 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2035 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002036 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2037 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2038 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2039 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2040 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2041
2042 // Trigger cpu adapt up, expect upscaled resolution (960x540).
2043 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002044 timestamp_ms += kFrameIntervalMs;
2045 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2046 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002047 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002048 last_wants = source.sink_wants();
2049 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2050 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002051 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002052 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2053
2054 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002055 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002056 timestamp_ms += kFrameIntervalMs;
2057 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2058 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002059 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002060 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2061 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002062 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002063 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2064
2065 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002066 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002067 timestamp_ms += kFrameIntervalMs;
2068 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002069 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002070 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002071 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002072 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2073 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002074 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002075 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002076
mflodmancc3d4422017-08-03 08:27:51 -07002077 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002078}
2079
mflodmancc3d4422017-08-03 08:27:51 -07002080TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002081 const int kWidth = 640;
2082 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002083
mflodmancc3d4422017-08-03 08:27:51 -07002084 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002085
perkj803d97f2016-11-01 11:45:46 -07002086 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002087 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002088 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002089 }
2090
mflodmancc3d4422017-08-03 08:27:51 -07002091 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002092 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002093 video_source_.IncomingCapturedFrame(CreateFrame(
2094 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002095 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002096 }
2097
mflodmancc3d4422017-08-03 08:27:51 -07002098 video_stream_encoder_->Stop();
2099 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002100 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002101
perkj803d97f2016-11-01 11:45:46 -07002102 EXPECT_EQ(1,
2103 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2104 EXPECT_EQ(
2105 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2106}
2107
mflodmancc3d4422017-08-03 08:27:51 -07002108TEST_F(VideoStreamEncoderTest,
2109 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2110 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002111 const int kWidth = 640;
2112 const int kHeight = 360;
2113
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002114 video_stream_encoder_->SetSource(&video_source_,
2115 webrtc::DegradationPreference::DISABLED);
asaperssonf4e44af2017-04-19 02:01:06 -07002116
2117 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2118 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002119 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002120 }
2121
mflodmancc3d4422017-08-03 08:27:51 -07002122 video_stream_encoder_->Stop();
2123 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002124 stats_proxy_.reset();
2125
2126 EXPECT_EQ(0,
2127 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2128}
2129
mflodmancc3d4422017-08-03 08:27:51 -07002130TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002131 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02002132 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002133
2134 const int kDefaultFps = 30;
Erik Språng566124a2018-04-23 12:32:22 +02002135 const VideoBitrateAllocation expected_bitrate =
sprang57c2fff2017-01-16 06:24:02 -08002136 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002137 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002138
sprang57c2fff2017-01-16 06:24:02 -08002139 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
Niels Möller6bb5ab92019-01-11 11:11:10 +01002140 .Times(1);
mflodmancc3d4422017-08-03 08:27:51 -07002141 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002142
2143 const int64_t kStartTimeMs = 1;
2144 video_source_.IncomingCapturedFrame(
2145 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002146 WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002147
2148 // Not called on second frame.
2149 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2150 .Times(0);
2151 video_source_.IncomingCapturedFrame(
2152 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002153 WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002154
2155 // Called after a process interval.
2156 const int64_t kProcessIntervalMs =
2157 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang4847ae62017-06-27 07:06:52 -07002158 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec *
2159 (kProcessIntervalMs + (1000 / kDefaultFps)));
sprang57c2fff2017-01-16 06:24:02 -08002160 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2161 .Times(1);
2162 video_source_.IncomingCapturedFrame(CreateFrame(
2163 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002164 WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002165
mflodmancc3d4422017-08-03 08:27:51 -07002166 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002167}
2168
Niels Möller7dc26b72017-12-06 10:27:48 +01002169TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2170 const int kFrameWidth = 1280;
2171 const int kFrameHeight = 720;
2172 const int kFramerate = 24;
2173
2174 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2175 test::FrameForwarder source;
2176 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002177 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002178
2179 // Insert a single frame, triggering initial configuration.
2180 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2181 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2182
2183 EXPECT_EQ(
2184 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2185 kDefaultFramerate);
2186
2187 // Trigger reconfigure encoder (without resetting the entire instance).
2188 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002189 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002190 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2191 video_encoder_config.number_of_streams = 1;
2192 video_encoder_config.video_stream_factory =
2193 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2194 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002195 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002196 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2197
2198 // Detector should be updated with fps limit from codec config.
2199 EXPECT_EQ(
2200 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2201 kFramerate);
2202
2203 // Trigger overuse, max framerate should be reduced.
2204 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2205 stats.input_frame_rate = kFramerate;
2206 stats_proxy_->SetMockStats(stats);
2207 video_stream_encoder_->TriggerCpuOveruse();
2208 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2209 int adapted_framerate =
2210 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2211 EXPECT_LT(adapted_framerate, kFramerate);
2212
2213 // Trigger underuse, max framerate should go back to codec configured fps.
2214 // Set extra low fps, to make sure it's actually reset, not just incremented.
2215 stats = stats_proxy_->GetStats();
2216 stats.input_frame_rate = adapted_framerate / 2;
2217 stats_proxy_->SetMockStats(stats);
2218 video_stream_encoder_->TriggerCpuNormalUsage();
2219 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2220 EXPECT_EQ(
2221 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2222 kFramerate);
2223
2224 video_stream_encoder_->Stop();
2225}
2226
2227TEST_F(VideoStreamEncoderTest,
2228 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2229 const int kFrameWidth = 1280;
2230 const int kFrameHeight = 720;
2231 const int kLowFramerate = 15;
2232 const int kHighFramerate = 25;
2233
2234 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2235 test::FrameForwarder source;
2236 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002237 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002238
2239 // Trigger initial configuration.
2240 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002241 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002242 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2243 video_encoder_config.number_of_streams = 1;
2244 video_encoder_config.video_stream_factory =
2245 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2246 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2247 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002248 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002249 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2250
2251 EXPECT_EQ(
2252 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2253 kLowFramerate);
2254
2255 // Trigger overuse, max framerate should be reduced.
2256 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2257 stats.input_frame_rate = kLowFramerate;
2258 stats_proxy_->SetMockStats(stats);
2259 video_stream_encoder_->TriggerCpuOveruse();
2260 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2261 int adapted_framerate =
2262 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2263 EXPECT_LT(adapted_framerate, kLowFramerate);
2264
2265 // Reconfigure the encoder with a new (higher max framerate), max fps should
2266 // still respect the adaptation.
2267 video_encoder_config.video_stream_factory =
2268 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2269 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2270 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002271 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002272 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2273
2274 EXPECT_EQ(
2275 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2276 adapted_framerate);
2277
2278 // Trigger underuse, max framerate should go back to codec configured fps.
2279 stats = stats_proxy_->GetStats();
2280 stats.input_frame_rate = adapted_framerate;
2281 stats_proxy_->SetMockStats(stats);
2282 video_stream_encoder_->TriggerCpuNormalUsage();
2283 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2284 EXPECT_EQ(
2285 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2286 kHighFramerate);
2287
2288 video_stream_encoder_->Stop();
2289}
2290
mflodmancc3d4422017-08-03 08:27:51 -07002291TEST_F(VideoStreamEncoderTest,
2292 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002293 const int kFrameWidth = 1280;
2294 const int kFrameHeight = 720;
2295 const int kFramerate = 24;
2296
mflodmancc3d4422017-08-03 08:27:51 -07002297 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002298 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002299 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002300 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangfda496a2017-06-15 04:21:07 -07002301
2302 // Trigger initial configuration.
2303 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002304 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002305 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2306 video_encoder_config.number_of_streams = 1;
2307 video_encoder_config.video_stream_factory =
2308 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2309 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002310 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002311 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002312 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002313
Niels Möller7dc26b72017-12-06 10:27:48 +01002314 EXPECT_EQ(
2315 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2316 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002317
2318 // Trigger overuse, max framerate should be reduced.
2319 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2320 stats.input_frame_rate = kFramerate;
2321 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002322 video_stream_encoder_->TriggerCpuOveruse();
2323 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002324 int adapted_framerate =
2325 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002326 EXPECT_LT(adapted_framerate, kFramerate);
2327
2328 // Change degradation preference to not enable framerate scaling. Target
2329 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002330 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002331 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -07002332 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002333 EXPECT_EQ(
2334 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2335 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002336
mflodmancc3d4422017-08-03 08:27:51 -07002337 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002338}
2339
mflodmancc3d4422017-08-03 08:27:51 -07002340TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002341 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002342 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002343 const int kWidth = 640;
2344 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002345
asaperssonfab67072017-04-04 05:51:49 -07002346 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002347
2348 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002349 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002350
2351 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002352 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002353
sprangc5d62e22017-04-02 23:53:04 -07002354 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002355
asaperssonfab67072017-04-04 05:51:49 -07002356 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002357 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002358 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002359
2360 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002361 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002362
sprangc5d62e22017-04-02 23:53:04 -07002363 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002364
mflodmancc3d4422017-08-03 08:27:51 -07002365 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002366}
2367
mflodmancc3d4422017-08-03 08:27:51 -07002368TEST_F(VideoStreamEncoderTest,
2369 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002370 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002371 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002372 const int kWidth = 640;
2373 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002374
2375 // We expect the n initial frames to get dropped.
2376 int i;
2377 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002378 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002379 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002380 }
2381 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002382 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002383 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002384
2385 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002386 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002387
mflodmancc3d4422017-08-03 08:27:51 -07002388 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002389}
2390
mflodmancc3d4422017-08-03 08:27:51 -07002391TEST_F(VideoStreamEncoderTest,
2392 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002393 const int kWidth = 640;
2394 const int kHeight = 360;
mflodmancc3d4422017-08-03 08:27:51 -07002395 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002396
2397 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002398 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002399 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason2bc68642017-02-07 07:02:22 -08002400
asaperssonfab67072017-04-04 05:51:49 -07002401 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002402 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002403 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002404
mflodmancc3d4422017-08-03 08:27:51 -07002405 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002406}
2407
mflodmancc3d4422017-08-03 08:27:51 -07002408TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002409 const int kWidth = 640;
2410 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002411 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02002412
2413 VideoEncoderConfig video_encoder_config;
2414 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
2415 // Make format different, to force recreation of encoder.
2416 video_encoder_config.video_format.parameters["foo"] = "foo";
2417 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002418 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002419 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002420
kthelgasonb83797b2017-02-14 11:57:25 -08002421 // Force quality scaler reconfiguration by resetting the source.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002422 video_stream_encoder_->SetSource(&video_source_,
2423 webrtc::DegradationPreference::BALANCED);
kthelgasonad9010c2017-02-14 00:46:51 -08002424
asaperssonfab67072017-04-04 05:51:49 -07002425 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002426 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002427 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002428
mflodmancc3d4422017-08-03 08:27:51 -07002429 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002430 fake_encoder_.SetQualityScaling(true);
2431}
2432
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002433TEST_F(VideoStreamEncoderTest, InitialFrameDropActivatesWhenBWEstimateReady) {
2434 webrtc::test::ScopedFieldTrials field_trials(
2435 "WebRTC-InitialFramedrop/Enabled/");
2436 // Reset encoder for field trials to take effect.
2437 ConfigureEncoder(video_encoder_config_.Copy());
2438 const int kTooLowBitrateForFrameSizeBps = 10000;
2439 const int kWidth = 640;
2440 const int kHeight = 360;
2441
2442 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2443 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2444 // Frame should not be dropped.
2445 WaitForEncodedFrame(1);
2446
2447 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
2448 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
2449 // Expect to drop this frame, the wait should time out.
2450 ExpectDroppedFrame();
2451
2452 // Expect the sink_wants to specify a scaled frame.
2453 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
2454 video_stream_encoder_->Stop();
2455}
2456
mflodmancc3d4422017-08-03 08:27:51 -07002457TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002458 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2459 const int kTooSmallWidth = 10;
2460 const int kTooSmallHeight = 10;
mflodmancc3d4422017-08-03 08:27:51 -07002461 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002462
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002463 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002464 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002465 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002466 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002467 VerifyNoLimitation(source.sink_wants());
2468 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2469
2470 // Trigger adapt down, too small frame, expect no change.
2471 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002472 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002473 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002474 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002475 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2476 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2477
mflodmancc3d4422017-08-03 08:27:51 -07002478 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002479}
2480
mflodmancc3d4422017-08-03 08:27:51 -07002481TEST_F(VideoStreamEncoderTest,
2482 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002483 const int kTooSmallWidth = 10;
2484 const int kTooSmallHeight = 10;
2485 const int kFpsLimit = 7;
mflodmancc3d4422017-08-03 08:27:51 -07002486 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002487
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002488 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002489 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002490 video_stream_encoder_->SetSource(&source,
2491 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002492 VerifyNoLimitation(source.sink_wants());
2493 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2494 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2495
2496 // Trigger adapt down, expect limited framerate.
2497 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002498 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002499 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002500 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2501 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2502 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2503 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2504
2505 // Trigger adapt down, too small frame, expect no change.
2506 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002507 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002508 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002509 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2510 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2511 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2512 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2513
mflodmancc3d4422017-08-03 08:27:51 -07002514 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002515}
2516
mflodmancc3d4422017-08-03 08:27:51 -07002517TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002518 fake_encoder_.ForceInitEncodeFailure(true);
mflodmancc3d4422017-08-03 08:27:51 -07002519 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Niels Möllerf1338562018-04-26 09:51:47 +02002520 ResetEncoder("VP8", 2, 1, 1, false);
asapersson02465b82017-04-10 01:12:52 -07002521 const int kFrameWidth = 1280;
2522 const int kFrameHeight = 720;
2523 video_source_.IncomingCapturedFrame(
2524 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002525 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002526 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002527}
2528
sprangb1ca0732017-02-01 08:38:12 -08002529// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002530TEST_F(VideoStreamEncoderTest,
2531 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
2532 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002533
2534 const int kFrameWidth = 1280;
2535 const int kFrameHeight = 720;
2536 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002537 // requested by
2538 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002539 video_source_.set_adaptation_enabled(true);
2540
2541 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002542 CreateFrame(1 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002543 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002544
2545 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002546 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002547 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002548 CreateFrame(2 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002549 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002550
asaperssonfab67072017-04-04 05:51:49 -07002551 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002552 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002553 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002554 CreateFrame(3 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002555 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002556
mflodmancc3d4422017-08-03 08:27:51 -07002557 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002558}
sprangfe627f32017-03-29 08:24:59 -07002559
mflodmancc3d4422017-08-03 08:27:51 -07002560TEST_F(VideoStreamEncoderTest,
2561 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002562 const int kFrameWidth = 1280;
2563 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07002564
mflodmancc3d4422017-08-03 08:27:51 -07002565 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2566 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002567 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002568 video_source_.set_adaptation_enabled(true);
2569
sprang4847ae62017-06-27 07:06:52 -07002570 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002571
2572 video_source_.IncomingCapturedFrame(
2573 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002574 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002575
2576 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002577 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002578
2579 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002580 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002581 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002582 video_source_.IncomingCapturedFrame(
2583 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002584 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002585 }
2586
2587 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002588 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002589 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002590 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002591 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002592 video_source_.IncomingCapturedFrame(
2593 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002594 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002595 ++num_frames_dropped;
2596 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002597 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002598 }
2599 }
2600
sprang4847ae62017-06-27 07:06:52 -07002601 // Add some slack to account for frames dropped by the frame dropper.
2602 const int kErrorMargin = 1;
2603 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002604 kErrorMargin);
2605
2606 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002607 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002608 num_frames_dropped = 0;
Åsa Persson8c1bf952018-09-13 10:42:19 +02002609 for (int i = 0; i <= max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002610 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002611 video_source_.IncomingCapturedFrame(
2612 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002613 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002614 ++num_frames_dropped;
2615 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002616 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002617 }
2618 }
sprang4847ae62017-06-27 07:06:52 -07002619 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002620 kErrorMargin);
2621
2622 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002623 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002624 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002625 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002626 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002627 video_source_.IncomingCapturedFrame(
2628 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002629 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002630 ++num_frames_dropped;
2631 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002632 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002633 }
2634 }
sprang4847ae62017-06-27 07:06:52 -07002635 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002636 kErrorMargin);
2637
2638 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002639 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002640 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002641 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002642 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002643 video_source_.IncomingCapturedFrame(
2644 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002645 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002646 ++num_frames_dropped;
2647 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002648 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002649 }
2650 }
2651 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2652
mflodmancc3d4422017-08-03 08:27:51 -07002653 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002654}
2655
mflodmancc3d4422017-08-03 08:27:51 -07002656TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002657 const int kFramerateFps = 5;
2658 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002659 const int kFrameWidth = 1280;
2660 const int kFrameHeight = 720;
2661
sprang4847ae62017-06-27 07:06:52 -07002662 // Reconfigure encoder with two temporal layers and screensharing, which will
2663 // disable frame dropping and make testing easier.
Niels Möllerf1338562018-04-26 09:51:47 +02002664 ResetEncoder("VP8", 1, 2, 1, true);
sprang4847ae62017-06-27 07:06:52 -07002665
mflodmancc3d4422017-08-03 08:27:51 -07002666 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2667 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002668 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002669 video_source_.set_adaptation_enabled(true);
2670
sprang4847ae62017-06-27 07:06:52 -07002671 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002672
2673 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08002674 rtc::VideoSinkWants last_wants;
2675 do {
2676 last_wants = video_source_.sink_wants();
2677
sprangc5d62e22017-04-02 23:53:04 -07002678 // Insert frames to get a new fps estimate...
2679 for (int j = 0; j < kFramerateFps; ++j) {
2680 video_source_.IncomingCapturedFrame(
2681 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08002682 if (video_source_.last_sent_width()) {
2683 sink_.WaitForEncodedFrame(timestamp_ms);
2684 }
sprangc5d62e22017-04-02 23:53:04 -07002685 timestamp_ms += kFrameIntervalMs;
Yves Gerey665174f2018-06-19 15:03:05 +02002686 fake_clock_.AdvanceTimeMicros(kFrameIntervalMs *
2687 rtc::kNumMicrosecsPerMillisec);
sprangc5d62e22017-04-02 23:53:04 -07002688 }
2689 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002690 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08002691 } while (video_source_.sink_wants().max_framerate_fps <
2692 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07002693
Jonathan Yubc771b72017-12-08 17:04:29 -08002694 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07002695
mflodmancc3d4422017-08-03 08:27:51 -07002696 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002697}
asaperssonf7e294d2017-06-13 23:25:22 -07002698
mflodmancc3d4422017-08-03 08:27:51 -07002699TEST_F(VideoStreamEncoderTest,
2700 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002701 const int kWidth = 1280;
2702 const int kHeight = 720;
2703 const int64_t kFrameIntervalMs = 150;
2704 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002705 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002706
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002707 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002708 AdaptingFrameForwarder source;
2709 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002710 video_stream_encoder_->SetSource(&source,
2711 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002712 timestamp_ms += kFrameIntervalMs;
2713 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002714 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002715 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002716 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2717 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2718 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2719
2720 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002721 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002722 timestamp_ms += kFrameIntervalMs;
2723 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002724 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002725 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2726 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2727 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2728 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2729
2730 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002731 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002732 timestamp_ms += kFrameIntervalMs;
2733 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002734 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002735 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2736 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2737 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2738 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2739
2740 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002741 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002742 timestamp_ms += kFrameIntervalMs;
2743 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002744 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002745 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2746 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2747 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2748 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2749
2750 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002751 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002752 timestamp_ms += kFrameIntervalMs;
2753 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002754 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002755 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2756 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2757 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2758 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2759
2760 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002761 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002762 timestamp_ms += kFrameIntervalMs;
2763 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002764 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002765 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2766 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2767 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2768 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2769
2770 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002771 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002772 timestamp_ms += kFrameIntervalMs;
2773 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002774 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002775 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2776 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2777 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2778 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2779
2780 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002781 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002782 timestamp_ms += kFrameIntervalMs;
2783 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002784 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002785 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2786 rtc::VideoSinkWants last_wants = source.sink_wants();
2787 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2788 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2789 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2790
2791 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002792 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002793 timestamp_ms += kFrameIntervalMs;
2794 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002795 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002796 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2797 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2798 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2799 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2800
2801 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002802 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002803 timestamp_ms += kFrameIntervalMs;
2804 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002805 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002806 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2807 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2808 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2809 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2810
2811 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002812 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002813 timestamp_ms += kFrameIntervalMs;
2814 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002815 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002816 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2817 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2818 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2819 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2820
2821 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002822 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002823 timestamp_ms += kFrameIntervalMs;
2824 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002825 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002826 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2827 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2828 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2829 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2830
2831 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002832 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002833 timestamp_ms += kFrameIntervalMs;
2834 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002835 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002836 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2837 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2838 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2839 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2840
2841 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002842 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002843 timestamp_ms += kFrameIntervalMs;
2844 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002845 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002846 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2847 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2848 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2849 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2850
2851 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002852 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002853 timestamp_ms += kFrameIntervalMs;
2854 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002855 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002856 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2857 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2858 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2859 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2860
2861 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002862 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002863 timestamp_ms += kFrameIntervalMs;
2864 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002865 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002866 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002867 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002868 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2869 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2870 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2871
2872 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002873 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002874 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002875 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2876
mflodmancc3d4422017-08-03 08:27:51 -07002877 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002878}
2879
mflodmancc3d4422017-08-03 08:27:51 -07002880TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07002881 const int kWidth = 1280;
2882 const int kHeight = 720;
2883 const int64_t kFrameIntervalMs = 150;
2884 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002885 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002886
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002887 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002888 AdaptingFrameForwarder source;
2889 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002890 video_stream_encoder_->SetSource(&source,
2891 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002892 timestamp_ms += kFrameIntervalMs;
2893 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002894 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002895 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002896 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2897 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2898 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2899 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2900 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2901 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2902
2903 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002904 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002905 timestamp_ms += kFrameIntervalMs;
2906 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002907 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002908 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2909 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2910 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2911 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2912 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2913 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2914 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2915
2916 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002917 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002918 timestamp_ms += kFrameIntervalMs;
2919 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002920 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002921 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2922 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2923 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2924 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2925 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2926 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2927 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2928
2929 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002930 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002931 timestamp_ms += kFrameIntervalMs;
2932 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002933 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002934 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2935 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2936 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2937 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2938 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2939 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2940 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2941
2942 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002943 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002944 timestamp_ms += kFrameIntervalMs;
2945 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002946 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002947 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2948 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2949 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2950 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2951 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2952 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2953 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2954
2955 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002956 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002957 timestamp_ms += kFrameIntervalMs;
2958 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002959 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002960 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2961 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2962 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2963 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2964 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2965 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2966 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2967
2968 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002969 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002970 timestamp_ms += kFrameIntervalMs;
2971 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002972 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002973 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002974 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002975 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2976 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2977 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2978 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2979 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2980 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2981
2982 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002983 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002984 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002985 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2986 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2987
mflodmancc3d4422017-08-03 08:27:51 -07002988 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002989}
2990
mflodmancc3d4422017-08-03 08:27:51 -07002991TEST_F(VideoStreamEncoderTest,
2992 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07002993 const int kWidth = 640;
2994 const int kHeight = 360;
2995 const int kFpsLimit = 15;
2996 const int64_t kFrameIntervalMs = 150;
2997 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002998 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002999
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003000 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07003001 AdaptingFrameForwarder source;
3002 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003003 video_stream_encoder_->SetSource(&source,
3004 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07003005 timestamp_ms += kFrameIntervalMs;
3006 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003007 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003008 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003009 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3010 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3011 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3012 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3013 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3014 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3015
3016 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003017 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003018 timestamp_ms += kFrameIntervalMs;
3019 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003020 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003021 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
3022 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3023 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3024 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3025 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3026 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3027 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3028
3029 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003030 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003031 timestamp_ms += kFrameIntervalMs;
3032 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003033 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003034 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
3035 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3036 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3037 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3038 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3039 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3040 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3041
3042 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003043 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003044 timestamp_ms += kFrameIntervalMs;
3045 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003046 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003047 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3048 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3049 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3050 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3051 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3052 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3053 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3054
3055 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003056 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003057 timestamp_ms += kFrameIntervalMs;
3058 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003059 WaitForEncodedFrame(timestamp_ms);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003060 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003061 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3062 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3063 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3064 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3065 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3066 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3067
3068 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003069 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003070 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003071 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3072 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3073
mflodmancc3d4422017-08-03 08:27:51 -07003074 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003075}
3076
mflodmancc3d4422017-08-03 08:27:51 -07003077TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003078 // Simulates simulcast behavior and makes highest stream resolutions divisible
3079 // by 4.
3080 class CroppingVideoStreamFactory
3081 : public VideoEncoderConfig::VideoStreamFactoryInterface {
3082 public:
3083 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
3084 int framerate)
3085 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
3086 EXPECT_GT(num_temporal_layers, 0u);
3087 EXPECT_GT(framerate, 0);
3088 }
3089
3090 private:
3091 std::vector<VideoStream> CreateEncoderStreams(
3092 int width,
3093 int height,
3094 const VideoEncoderConfig& encoder_config) override {
Yves Gerey665174f2018-06-19 15:03:05 +02003095 std::vector<VideoStream> streams = test::CreateVideoStreams(
3096 width - width % 4, height - height % 4, encoder_config);
ilnik6b826ef2017-06-16 06:53:48 -07003097 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +01003098 stream.num_temporal_layers = num_temporal_layers_;
ilnik6b826ef2017-06-16 06:53:48 -07003099 stream.max_framerate = framerate_;
3100 }
3101 return streams;
3102 }
3103
3104 const size_t num_temporal_layers_;
3105 const int framerate_;
3106 };
3107
3108 const int kFrameWidth = 1920;
3109 const int kFrameHeight = 1080;
3110 // 3/4 of 1920.
3111 const int kAdaptedFrameWidth = 1440;
3112 // 3/4 of 1080 rounded down to multiple of 4.
3113 const int kAdaptedFrameHeight = 808;
3114 const int kFramerate = 24;
3115
mflodmancc3d4422017-08-03 08:27:51 -07003116 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003117 // Trigger reconfigure encoder (without resetting the entire instance).
3118 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02003119 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07003120 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3121 video_encoder_config.number_of_streams = 1;
3122 video_encoder_config.video_stream_factory =
3123 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003124 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02003125 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07003126 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003127
3128 video_source_.set_adaptation_enabled(true);
3129
3130 video_source_.IncomingCapturedFrame(
3131 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003132 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003133
3134 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003135 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003136 video_source_.IncomingCapturedFrame(
3137 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003138 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003139
mflodmancc3d4422017-08-03 08:27:51 -07003140 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003141}
3142
mflodmancc3d4422017-08-03 08:27:51 -07003143TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003144 const int kFrameWidth = 1280;
3145 const int kFrameHeight = 720;
3146 const int kLowFps = 2;
3147 const int kHighFps = 30;
3148
mflodmancc3d4422017-08-03 08:27:51 -07003149 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003150
3151 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3152 max_framerate_ = kLowFps;
3153
3154 // Insert 2 seconds of 2fps video.
3155 for (int i = 0; i < kLowFps * 2; ++i) {
3156 video_source_.IncomingCapturedFrame(
3157 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3158 WaitForEncodedFrame(timestamp_ms);
3159 timestamp_ms += 1000 / kLowFps;
3160 }
3161
3162 // Make sure encoder is updated with new target.
mflodmancc3d4422017-08-03 08:27:51 -07003163 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003164 video_source_.IncomingCapturedFrame(
3165 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3166 WaitForEncodedFrame(timestamp_ms);
3167 timestamp_ms += 1000 / kLowFps;
3168
3169 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3170
3171 // Insert 30fps frames for just a little more than the forced update period.
3172 const int kVcmTimerIntervalFrames =
3173 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3174 const int kFrameIntervalMs = 1000 / kHighFps;
3175 max_framerate_ = kHighFps;
3176 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3177 video_source_.IncomingCapturedFrame(
3178 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3179 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3180 // be dropped if the encoder hans't been updated with the new higher target
3181 // framerate yet, causing it to overshoot the target bitrate and then
3182 // suffering the wrath of the media optimizer.
3183 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3184 timestamp_ms += kFrameIntervalMs;
3185 }
3186
3187 // Don expect correct measurement just yet, but it should be higher than
3188 // before.
3189 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3190
mflodmancc3d4422017-08-03 08:27:51 -07003191 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003192}
3193
mflodmancc3d4422017-08-03 08:27:51 -07003194TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003195 const int kFrameWidth = 1280;
3196 const int kFrameHeight = 720;
3197 const int kTargetBitrateBps = 1000000;
3198
3199 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02003200 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
mflodmancc3d4422017-08-03 08:27:51 -07003201 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3202 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003203
3204 // Insert a first video frame, causes another bitrate update.
3205 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3206 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3207 video_source_.IncomingCapturedFrame(
3208 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3209 WaitForEncodedFrame(timestamp_ms);
3210
3211 // Next, simulate video suspension due to pacer queue overrun.
mflodmancc3d4422017-08-03 08:27:51 -07003212 video_stream_encoder_->OnBitrateUpdated(0, 0, 1);
sprang4847ae62017-06-27 07:06:52 -07003213
3214 // Skip ahead until a new periodic parameter update should have occured.
3215 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3216 fake_clock_.AdvanceTimeMicros(
3217 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3218 rtc::kNumMicrosecsPerMillisec);
3219
3220 // Bitrate observer should not be called.
3221 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3222 video_source_.IncomingCapturedFrame(
3223 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3224 ExpectDroppedFrame();
3225
mflodmancc3d4422017-08-03 08:27:51 -07003226 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003227}
ilnik6b826ef2017-06-16 06:53:48 -07003228
Niels Möller4db138e2018-04-19 09:04:13 +02003229TEST_F(VideoStreamEncoderTest,
3230 DefaultCpuAdaptationThresholdsForSoftwareEncoder) {
3231 const int kFrameWidth = 1280;
3232 const int kFrameHeight = 720;
3233 const CpuOveruseOptions default_options;
3234 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3235 video_source_.IncomingCapturedFrame(
3236 CreateFrame(1, kFrameWidth, kFrameHeight));
3237 WaitForEncodedFrame(1);
3238 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3239 .low_encode_usage_threshold_percent,
3240 default_options.low_encode_usage_threshold_percent);
3241 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3242 .high_encode_usage_threshold_percent,
3243 default_options.high_encode_usage_threshold_percent);
3244 video_stream_encoder_->Stop();
3245}
3246
3247TEST_F(VideoStreamEncoderTest,
3248 HigherCpuAdaptationThresholdsForHardwareEncoder) {
3249 const int kFrameWidth = 1280;
3250 const int kFrameHeight = 720;
3251 CpuOveruseOptions hardware_options;
3252 hardware_options.low_encode_usage_threshold_percent = 150;
3253 hardware_options.high_encode_usage_threshold_percent = 200;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +01003254 fake_encoder_.SetIsHardwareAccelerated(true);
Niels Möller4db138e2018-04-19 09:04:13 +02003255
3256 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3257 video_source_.IncomingCapturedFrame(
3258 CreateFrame(1, kFrameWidth, kFrameHeight));
3259 WaitForEncodedFrame(1);
3260 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3261 .low_encode_usage_threshold_percent,
3262 hardware_options.low_encode_usage_threshold_percent);
3263 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3264 .high_encode_usage_threshold_percent,
3265 hardware_options.high_encode_usage_threshold_percent);
3266 video_stream_encoder_->Stop();
3267}
3268
Niels Möller6bb5ab92019-01-11 11:11:10 +01003269TEST_F(VideoStreamEncoderTest, DropsFramesWhenEncoderOvershoots) {
3270 const int kFrameWidth = 320;
3271 const int kFrameHeight = 240;
3272 const int kFps = 30;
3273 const int kTargetBitrateBps = 120000;
3274 const int kNumFramesInRun = kFps * 5; // Runs of five seconds.
3275
3276 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3277
3278 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3279 max_framerate_ = kFps;
3280
3281 // Insert 3 seconds of video, verify number of drops with normal bitrate.
3282 fake_encoder_.SimulateOvershoot(1.0);
3283 int num_dropped = 0;
3284 for (int i = 0; i < kNumFramesInRun; ++i) {
3285 video_source_.IncomingCapturedFrame(
3286 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3287 // Wait up to two frame durations for a frame to arrive.
3288 if (!TimedWaitForEncodedFrame(timestamp_ms, 2 * 1000 / kFps)) {
3289 ++num_dropped;
3290 }
3291 timestamp_ms += 1000 / kFps;
3292 }
3293
3294 // Frame drops should be less than 5%
3295 EXPECT_LT(num_dropped, 5 * kNumFramesInRun / 100);
3296
3297 // Make encoder produce frames at double the expected bitrate during 3 seconds
3298 // of video, verify number of drops. Rate needs to be slightly changed in
3299 // order to force the rate to be reconfigured.
3300 fake_encoder_.SimulateOvershoot(2.0);
3301 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps + 1000, 0, 0);
3302 num_dropped = 0;
3303 for (int i = 0; i < kNumFramesInRun; ++i) {
3304 video_source_.IncomingCapturedFrame(
3305 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3306 // Wait up to two frame durations for a frame to arrive.
3307 if (!TimedWaitForEncodedFrame(timestamp_ms, 2 * 1000 / kFps)) {
3308 ++num_dropped;
3309 }
3310 timestamp_ms += 1000 / kFps;
3311 }
3312
3313 // Frame drops should be more than 40%.
3314 EXPECT_GT(num_dropped, 40 * kNumFramesInRun / 100);
3315
3316 video_stream_encoder_->Stop();
3317}
3318
3319TEST_F(VideoStreamEncoderTest, ConfiguresCorrectFrameRate) {
3320 const int kFrameWidth = 320;
3321 const int kFrameHeight = 240;
3322 const int kActualInputFps = 24;
3323 const int kTargetBitrateBps = 120000;
3324
3325 ASSERT_GT(max_framerate_, kActualInputFps);
3326
3327 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3328 max_framerate_ = kActualInputFps;
3329 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3330
3331 // Insert 3 seconds of video, with an input fps lower than configured max.
3332 for (int i = 0; i < kActualInputFps * 3; ++i) {
3333 video_source_.IncomingCapturedFrame(
3334 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3335 // Wait up to two frame durations for a frame to arrive.
3336 WaitForEncodedFrame(timestamp_ms);
3337 timestamp_ms += 1000 / kActualInputFps;
3338 }
3339
3340 EXPECT_NEAR(kActualInputFps, fake_encoder_.GetLastFramerate(), 1);
3341
3342 video_stream_encoder_->Stop();
3343}
3344
perkj26091b12016-09-01 01:17:40 -07003345} // namespace webrtc