blob: 9d275adae5db78cbb228dc72e37a746274c3b278 [file] [log] [blame]
perkj26091b12016-09-01 01:17:40 -07001/*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Erik Språng4529fbc2018-10-12 10:30:31 +020011#include "video/video_stream_encoder.h"
12
sprangfe627f32017-03-29 08:24:59 -070013#include <algorithm>
perkj803d97f2016-11-01 11:45:46 -070014#include <limits>
Per512ecb32016-09-23 15:52:06 +020015#include <utility>
16
Jiawei Ouc2ebe212018-11-08 10:02:56 -080017#include "api/video/builtin_video_bitrate_allocator_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "api/video/i420_buffer.h"
Erik Språngf93eda12019-01-16 17:10:57 +010019#include "api/video/video_bitrate_allocation.h"
Erik Språng4529fbc2018-10-12 10:30:31 +020020#include "api/video_codecs/create_vp8_temporal_layers.h"
21#include "api/video_codecs/vp8_temporal_layers.h"
Steve Anton10542f22019-01-11 09:11:00 -080022#include "media/base/video_adapter.h"
Sergey Silkin86684962018-03-28 19:32:37 +020023#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
Steve Anton10542f22019-01-11 09:11:00 -080025#include "rtc_base/fake_clock.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020026#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080027#include "rtc_base/ref_counted_object.h"
Mirko Bonadei17f48782018-09-28 08:51:10 +020028#include "system_wrappers/include/metrics.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020029#include "system_wrappers/include/sleep.h"
30#include "test/encoder_settings.h"
31#include "test/fake_encoder.h"
Kári Tristan Helgason639602a2018-08-02 10:51:40 +020032#include "test/field_trial.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020033#include "test/frame_generator.h"
34#include "test/gmock.h"
35#include "test/gtest.h"
Niels Möllercbcbc222018-09-28 09:07:24 +020036#include "test/video_encoder_proxy_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020037#include "video/send_statistics_proxy.h"
perkj26091b12016-09-01 01:17:40 -070038
39namespace webrtc {
40
sprangb1ca0732017-02-01 08:38:12 -080041using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080042using ::testing::_;
43using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080044
perkj803d97f2016-11-01 11:45:46 -070045namespace {
Åsa Persson8c1bf952018-09-13 10:42:19 +020046const int kMinPixelsPerFrame = 320 * 180;
47const int kMinFramerateFps = 2;
48const int kMinBalancedFramerateFps = 7;
49const int64_t kFrameTimeoutMs = 100;
asapersson5f7226f2016-11-25 04:37:00 -080050const size_t kMaxPayloadLength = 1440;
kthelgason2bc68642017-02-07 07:02:22 -080051const int kTargetBitrateBps = 1000000;
52const int kLowTargetBitrateBps = kTargetBitrateBps / 10;
53const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070054const int kDefaultFramerate = 30;
Åsa Persson8c1bf952018-09-13 10:42:19 +020055const int64_t kFrameIntervalMs = rtc::kNumMillisecsPerSec / kDefaultFramerate;
asapersson5f7226f2016-11-25 04:37:00 -080056
perkj803d97f2016-11-01 11:45:46 -070057class TestBuffer : public webrtc::I420Buffer {
58 public:
59 TestBuffer(rtc::Event* event, int width, int height)
60 : I420Buffer(width, height), event_(event) {}
61
62 private:
63 friend class rtc::RefCountedObject<TestBuffer>;
64 ~TestBuffer() override {
65 if (event_)
66 event_->Set();
67 }
68 rtc::Event* const event_;
69};
70
Niels Möller7dc26b72017-12-06 10:27:48 +010071class CpuOveruseDetectorProxy : public OveruseFrameDetector {
72 public:
Niels Möllerd1f7eb62018-03-28 16:40:58 +020073 explicit CpuOveruseDetectorProxy(CpuOveruseMetricsObserver* metrics_observer)
74 : OveruseFrameDetector(metrics_observer),
Niels Möller7dc26b72017-12-06 10:27:48 +010075 last_target_framerate_fps_(-1) {}
76 virtual ~CpuOveruseDetectorProxy() {}
77
78 void OnTargetFramerateUpdated(int framerate_fps) override {
79 rtc::CritScope cs(&lock_);
80 last_target_framerate_fps_ = framerate_fps;
81 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
82 }
83
84 int GetLastTargetFramerate() {
85 rtc::CritScope cs(&lock_);
86 return last_target_framerate_fps_;
87 }
88
Niels Möller4db138e2018-04-19 09:04:13 +020089 CpuOveruseOptions GetOptions() { return options_; }
90
Niels Möller7dc26b72017-12-06 10:27:48 +010091 private:
92 rtc::CriticalSection lock_;
93 int last_target_framerate_fps_ RTC_GUARDED_BY(lock_);
94};
95
mflodmancc3d4422017-08-03 08:27:51 -070096class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -070097 public:
Niels Möller213618e2018-07-24 09:29:58 +020098 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
99 const VideoStreamEncoderSettings& settings)
Yves Gerey665174f2018-06-19 15:03:05 +0200100 : VideoStreamEncoder(1 /* number_of_cores */,
101 stats_proxy,
102 settings,
Yves Gerey665174f2018-06-19 15:03:05 +0200103 std::unique_ptr<OveruseFrameDetector>(
104 overuse_detector_proxy_ =
105 new CpuOveruseDetectorProxy(stats_proxy))) {}
perkj803d97f2016-11-01 11:45:46 -0700106
sprangb1ca0732017-02-01 08:38:12 -0800107 void PostTaskAndWait(bool down, AdaptReason reason) {
Niels Möllerc572ff32018-11-07 08:43:50 +0100108 rtc::Event event;
kthelgason876222f2016-11-29 01:44:11 -0800109 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800110 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700111 event.Set();
112 });
perkj070ba852017-02-16 15:46:27 -0800113 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700114 }
115
kthelgason2fc52542017-03-03 00:24:41 -0800116 // This is used as a synchronisation mechanism, to make sure that the
117 // encoder queue is not blocked before we start sending it frames.
118 void WaitUntilTaskQueueIsIdle() {
Niels Möllerc572ff32018-11-07 08:43:50 +0100119 rtc::Event event;
Yves Gerey665174f2018-06-19 15:03:05 +0200120 encoder_queue()->PostTask([&event] { event.Set(); });
kthelgason2fc52542017-03-03 00:24:41 -0800121 ASSERT_TRUE(event.Wait(5000));
122 }
123
sprangb1ca0732017-02-01 08:38:12 -0800124 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800125
sprangb1ca0732017-02-01 08:38:12 -0800126 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800127
sprangb1ca0732017-02-01 08:38:12 -0800128 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800129
sprangb1ca0732017-02-01 08:38:12 -0800130 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700131
Niels Möller7dc26b72017-12-06 10:27:48 +0100132 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700133};
134
asapersson5f7226f2016-11-25 04:37:00 -0800135class VideoStreamFactory
136 : public VideoEncoderConfig::VideoStreamFactoryInterface {
137 public:
sprangfda496a2017-06-15 04:21:07 -0700138 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
139 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800140 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700141 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800142 }
143
144 private:
145 std::vector<VideoStream> CreateEncoderStreams(
146 int width,
147 int height,
148 const VideoEncoderConfig& encoder_config) override {
149 std::vector<VideoStream> streams =
150 test::CreateVideoStreams(width, height, encoder_config);
151 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +0100152 stream.num_temporal_layers = num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700153 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800154 }
155 return streams;
156 }
sprangfda496a2017-06-15 04:21:07 -0700157
asapersson5f7226f2016-11-25 04:37:00 -0800158 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700159 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800160};
161
sprangb1ca0732017-02-01 08:38:12 -0800162class AdaptingFrameForwarder : public test::FrameForwarder {
163 public:
164 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700165 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800166
167 void set_adaptation_enabled(bool enabled) {
168 rtc::CritScope cs(&crit_);
169 adaptation_enabled_ = enabled;
170 }
171
asaperssonfab67072017-04-04 05:51:49 -0700172 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800173 rtc::CritScope cs(&crit_);
174 return adaptation_enabled_;
175 }
176
asapersson09f05612017-05-15 23:40:18 -0700177 rtc::VideoSinkWants last_wants() const {
178 rtc::CritScope cs(&crit_);
179 return last_wants_;
180 }
181
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200182 absl::optional<int> last_sent_width() const { return last_width_; }
183 absl::optional<int> last_sent_height() const { return last_height_; }
Jonathan Yubc771b72017-12-08 17:04:29 -0800184
sprangb1ca0732017-02-01 08:38:12 -0800185 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
186 int cropped_width = 0;
187 int cropped_height = 0;
188 int out_width = 0;
189 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700190 if (adaption_enabled()) {
191 if (adapter_.AdaptFrameResolution(
192 video_frame.width(), video_frame.height(),
193 video_frame.timestamp_us() * 1000, &cropped_width,
194 &cropped_height, &out_width, &out_height)) {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100195 VideoFrame adapted_frame =
196 VideoFrame::Builder()
197 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
198 nullptr, out_width, out_height))
199 .set_timestamp_rtp(99)
200 .set_timestamp_ms(99)
201 .set_rotation(kVideoRotation_0)
202 .build();
sprangc5d62e22017-04-02 23:53:04 -0700203 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
204 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800205 last_width_.emplace(adapted_frame.width());
206 last_height_.emplace(adapted_frame.height());
207 } else {
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200208 last_width_ = absl::nullopt;
209 last_height_ = absl::nullopt;
sprangc5d62e22017-04-02 23:53:04 -0700210 }
sprangb1ca0732017-02-01 08:38:12 -0800211 } else {
212 test::FrameForwarder::IncomingCapturedFrame(video_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800213 last_width_.emplace(video_frame.width());
214 last_height_.emplace(video_frame.height());
sprangb1ca0732017-02-01 08:38:12 -0800215 }
216 }
217
218 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
219 const rtc::VideoSinkWants& wants) override {
220 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700221 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700222 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
223 wants.max_pixel_count,
224 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800225 test::FrameForwarder::AddOrUpdateSink(sink, wants);
226 }
sprangb1ca0732017-02-01 08:38:12 -0800227 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700228 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
229 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200230 absl::optional<int> last_width_;
231 absl::optional<int> last_height_;
sprangb1ca0732017-02-01 08:38:12 -0800232};
sprangc5d62e22017-04-02 23:53:04 -0700233
Niels Möller213618e2018-07-24 09:29:58 +0200234// TODO(nisse): Mock only VideoStreamEncoderObserver.
sprangc5d62e22017-04-02 23:53:04 -0700235class MockableSendStatisticsProxy : public SendStatisticsProxy {
236 public:
237 MockableSendStatisticsProxy(Clock* clock,
238 const VideoSendStream::Config& config,
239 VideoEncoderConfig::ContentType content_type)
240 : SendStatisticsProxy(clock, config, content_type) {}
241
242 VideoSendStream::Stats GetStats() override {
243 rtc::CritScope cs(&lock_);
244 if (mock_stats_)
245 return *mock_stats_;
246 return SendStatisticsProxy::GetStats();
247 }
248
Niels Möller213618e2018-07-24 09:29:58 +0200249 int GetInputFrameRate() const override {
250 rtc::CritScope cs(&lock_);
251 if (mock_stats_)
252 return mock_stats_->input_frame_rate;
253 return SendStatisticsProxy::GetInputFrameRate();
254 }
sprangc5d62e22017-04-02 23:53:04 -0700255 void SetMockStats(const VideoSendStream::Stats& stats) {
256 rtc::CritScope cs(&lock_);
257 mock_stats_.emplace(stats);
258 }
259
260 void ResetMockStats() {
261 rtc::CritScope cs(&lock_);
262 mock_stats_.reset();
263 }
264
265 private:
266 rtc::CriticalSection lock_;
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200267 absl::optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700268};
269
sprang4847ae62017-06-27 07:06:52 -0700270class MockBitrateObserver : public VideoBitrateAllocationObserver {
271 public:
Erik Språng566124a2018-04-23 12:32:22 +0200272 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const VideoBitrateAllocation&));
sprang4847ae62017-06-27 07:06:52 -0700273};
274
perkj803d97f2016-11-01 11:45:46 -0700275} // namespace
276
mflodmancc3d4422017-08-03 08:27:51 -0700277class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700278 public:
279 static const int kDefaultTimeoutMs = 30 * 1000;
280
mflodmancc3d4422017-08-03 08:27:51 -0700281 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700282 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700283 codec_width_(320),
284 codec_height_(240),
Åsa Persson8c1bf952018-09-13 10:42:19 +0200285 max_framerate_(kDefaultFramerate),
perkj26091b12016-09-01 01:17:40 -0700286 fake_encoder_(),
Niels Möller4db138e2018-04-19 09:04:13 +0200287 encoder_factory_(&fake_encoder_),
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800288 bitrate_allocator_factory_(CreateBuiltinVideoBitrateAllocatorFactory()),
sprangc5d62e22017-04-02 23:53:04 -0700289 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700290 Clock::GetRealTimeClock(),
291 video_send_config_,
292 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700293 sink_(&fake_encoder_) {}
294
295 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700296 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700297 video_send_config_ = VideoSendStream::Config(nullptr);
Niels Möller4db138e2018-04-19 09:04:13 +0200298 video_send_config_.encoder_settings.encoder_factory = &encoder_factory_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800299 video_send_config_.encoder_settings.bitrate_allocator_factory =
300 bitrate_allocator_factory_.get();
Niels Möller259a4972018-04-05 15:36:51 +0200301 video_send_config_.rtp.payload_name = "FAKE";
302 video_send_config_.rtp.payload_type = 125;
perkj26091b12016-09-01 01:17:40 -0700303
Per512ecb32016-09-23 15:52:06 +0200304 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200305 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700306 video_encoder_config.video_stream_factory =
307 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100308 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700309
310 // Framerate limit is specified by the VideoStreamFactory.
311 std::vector<VideoStream> streams =
312 video_encoder_config.video_stream_factory->CreateEncoderStreams(
313 codec_width_, codec_height_, video_encoder_config);
314 max_framerate_ = streams[0].max_framerate;
315 fake_clock_.SetTimeMicros(1234);
316
Niels Möllerf1338562018-04-26 09:51:47 +0200317 ConfigureEncoder(std::move(video_encoder_config));
asapersson5f7226f2016-11-25 04:37:00 -0800318 }
319
Niels Möllerf1338562018-04-26 09:51:47 +0200320 void ConfigureEncoder(VideoEncoderConfig video_encoder_config) {
mflodmancc3d4422017-08-03 08:27:51 -0700321 if (video_stream_encoder_)
322 video_stream_encoder_->Stop();
323 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700324 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700325 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
326 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700327 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -0700328 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
329 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200330 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -0700331 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800332 }
333
334 void ResetEncoder(const std::string& payload_name,
335 size_t num_streams,
336 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700337 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700338 bool screenshare) {
Niels Möller259a4972018-04-05 15:36:51 +0200339 video_send_config_.rtp.payload_name = payload_name;
asapersson5f7226f2016-11-25 04:37:00 -0800340
341 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200342 video_encoder_config.codec_type = PayloadStringToCodecType(payload_name);
asapersson5f7226f2016-11-25 04:37:00 -0800343 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800344 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800345 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700346 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
347 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700348 video_encoder_config.content_type =
349 screenshare ? VideoEncoderConfig::ContentType::kScreen
350 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700351 if (payload_name == "VP9") {
352 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
353 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
354 video_encoder_config.encoder_specific_settings =
355 new rtc::RefCountedObject<
356 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
357 }
Niels Möllerf1338562018-04-26 09:51:47 +0200358 ConfigureEncoder(std::move(video_encoder_config));
perkj26091b12016-09-01 01:17:40 -0700359 }
360
sprang57c2fff2017-01-16 06:24:02 -0800361 VideoFrame CreateFrame(int64_t ntp_time_ms,
362 rtc::Event* destruction_event) const {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100363 VideoFrame frame =
364 VideoFrame::Builder()
365 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
366 destruction_event, codec_width_, codec_height_))
367 .set_timestamp_rtp(99)
368 .set_timestamp_ms(99)
369 .set_rotation(kVideoRotation_0)
370 .build();
sprang57c2fff2017-01-16 06:24:02 -0800371 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700372 return frame;
373 }
374
sprang57c2fff2017-01-16 06:24:02 -0800375 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100376 VideoFrame frame =
377 VideoFrame::Builder()
378 .set_video_frame_buffer(
379 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height))
380 .set_timestamp_rtp(99)
381 .set_timestamp_ms(99)
382 .set_rotation(kVideoRotation_0)
383 .build();
sprang57c2fff2017-01-16 06:24:02 -0800384 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700385 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700386 return frame;
387 }
388
asapersson02465b82017-04-10 01:12:52 -0700389 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700390 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700391 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
392 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700393 }
394
asapersson09f05612017-05-15 23:40:18 -0700395 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
396 const rtc::VideoSinkWants& wants2) {
397 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
398 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
399 }
400
Åsa Persson8c1bf952018-09-13 10:42:19 +0200401 void VerifyFpsMaxResolutionMax(const rtc::VideoSinkWants& wants) {
402 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
403 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
404 EXPECT_FALSE(wants.target_pixel_count);
405 }
406
asapersson09f05612017-05-15 23:40:18 -0700407 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
408 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200409 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700410 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
411 EXPECT_GT(wants1.max_pixel_count, 0);
412 }
413
414 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
415 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200416 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700417 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
418 }
419
asaperssonf7e294d2017-06-13 23:25:22 -0700420 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
421 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200422 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700423 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
424 }
425
426 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
427 const rtc::VideoSinkWants& wants2) {
428 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
429 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
430 }
431
432 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
433 const rtc::VideoSinkWants& wants2) {
434 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
435 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
436 }
437
438 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
439 const rtc::VideoSinkWants& wants2) {
440 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
441 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
442 EXPECT_GT(wants1.max_pixel_count, 0);
443 }
444
445 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
446 const rtc::VideoSinkWants& wants2) {
447 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
448 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
449 }
450
asapersson09f05612017-05-15 23:40:18 -0700451 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
452 int pixel_count) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200453 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700454 EXPECT_LT(wants.max_pixel_count, pixel_count);
455 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700456 }
457
458 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
459 EXPECT_LT(wants.max_framerate_fps, fps);
460 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
461 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700462 }
463
asaperssonf7e294d2017-06-13 23:25:22 -0700464 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
465 int expected_fps) {
466 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
467 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
468 EXPECT_FALSE(wants.target_pixel_count);
469 }
470
Jonathan Yubc771b72017-12-08 17:04:29 -0800471 void VerifyBalancedModeFpsRange(const rtc::VideoSinkWants& wants,
472 int last_frame_pixels) {
473 // Balanced mode should always scale FPS to the desired range before
474 // attempting to scale resolution.
475 int fps_limit = wants.max_framerate_fps;
476 if (last_frame_pixels <= 320 * 240) {
477 EXPECT_TRUE(7 <= fps_limit && fps_limit <= 10);
478 } else if (last_frame_pixels <= 480 * 270) {
479 EXPECT_TRUE(10 <= fps_limit && fps_limit <= 15);
480 } else if (last_frame_pixels <= 640 * 480) {
481 EXPECT_LE(15, fps_limit);
482 } else {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200483 EXPECT_EQ(kDefaultFramerate, fps_limit);
Jonathan Yubc771b72017-12-08 17:04:29 -0800484 }
485 }
486
sprang4847ae62017-06-27 07:06:52 -0700487 void WaitForEncodedFrame(int64_t expected_ntp_time) {
488 sink_.WaitForEncodedFrame(expected_ntp_time);
489 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
490 }
491
492 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
493 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
494 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
495 return ok;
496 }
497
498 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
499 sink_.WaitForEncodedFrame(expected_width, expected_height);
500 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
501 }
502
503 void ExpectDroppedFrame() {
504 sink_.ExpectDroppedFrame();
505 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
506 }
507
508 bool WaitForFrame(int64_t timeout_ms) {
509 bool ok = sink_.WaitForFrame(timeout_ms);
510 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
511 return ok;
512 }
513
perkj26091b12016-09-01 01:17:40 -0700514 class TestEncoder : public test::FakeEncoder {
515 public:
Niels Möllerc572ff32018-11-07 08:43:50 +0100516 TestEncoder() : FakeEncoder(Clock::GetRealTimeClock()) {}
perkj26091b12016-09-01 01:17:40 -0700517
asaperssonfab67072017-04-04 05:51:49 -0700518 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800519 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700520 return config_;
521 }
522
523 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800524 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700525 block_next_encode_ = true;
526 }
527
Erik Språngaed30702018-11-05 12:57:17 +0100528 VideoEncoder::EncoderInfo GetEncoderInfo() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800529 rtc::CritScope lock(&local_crit_sect_);
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100530 EncoderInfo info;
531 if (initialized_) {
532 if (quality_scaling_) {
533 info.scaling_settings =
534 VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
535 }
536 info.is_hardware_accelerated = is_hardware_accelerated_;
Erik Språngaed30702018-11-05 12:57:17 +0100537 }
538 return info;
kthelgason876222f2016-11-29 01:44:11 -0800539 }
540
perkjfa10b552016-10-02 23:45:26 -0700541 void ContinueEncode() { continue_encode_event_.Set(); }
542
543 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
544 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800545 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700546 EXPECT_EQ(timestamp_, timestamp);
547 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
548 }
549
kthelgason2fc52542017-03-03 00:24:41 -0800550 void SetQualityScaling(bool b) {
551 rtc::CritScope lock(&local_crit_sect_);
552 quality_scaling_ = b;
553 }
kthelgasonad9010c2017-02-14 00:46:51 -0800554
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100555 void SetIsHardwareAccelerated(bool is_hardware_accelerated) {
556 rtc::CritScope lock(&local_crit_sect_);
557 is_hardware_accelerated_ = is_hardware_accelerated;
558 }
559
sprangfe627f32017-03-29 08:24:59 -0700560 void ForceInitEncodeFailure(bool force_failure) {
561 rtc::CritScope lock(&local_crit_sect_);
562 force_init_encode_failed_ = force_failure;
563 }
564
Niels Möller6bb5ab92019-01-11 11:11:10 +0100565 void SimulateOvershoot(double rate_factor) {
566 rtc::CritScope lock(&local_crit_sect_);
567 rate_factor_ = rate_factor;
568 }
569
570 uint32_t GetLastFramerate() {
571 rtc::CritScope lock(&local_crit_sect_);
572 return last_framerate_;
573 }
574
perkjfa10b552016-10-02 23:45:26 -0700575 private:
perkj26091b12016-09-01 01:17:40 -0700576 int32_t Encode(const VideoFrame& input_image,
577 const CodecSpecificInfo* codec_specific_info,
578 const std::vector<FrameType>* frame_types) override {
579 bool block_encode;
580 {
brandtre78d2662017-01-16 05:57:16 -0800581 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700582 EXPECT_GT(input_image.timestamp(), timestamp_);
583 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
584 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
585
586 timestamp_ = input_image.timestamp();
587 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700588 last_input_width_ = input_image.width();
589 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700590 block_encode = block_next_encode_;
591 block_next_encode_ = false;
592 }
593 int32_t result =
594 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
595 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700596 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700597 return result;
598 }
599
sprangfe627f32017-03-29 08:24:59 -0700600 int32_t InitEncode(const VideoCodec* config,
601 int32_t number_of_cores,
602 size_t max_payload_size) override {
603 int res =
604 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
605 rtc::CritScope lock(&local_crit_sect_);
Erik Språng82fad3d2018-03-21 09:57:23 +0100606 if (config->codecType == kVideoCodecVP8) {
sprangfe627f32017-03-29 08:24:59 -0700607 // Simulate setting up temporal layers, in order to validate the life
608 // cycle of these objects.
609 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
sprangfe627f32017-03-29 08:24:59 -0700610 for (int i = 0; i < num_streams; ++i) {
611 allocated_temporal_layers_.emplace_back(
Erik Språng4529fbc2018-10-12 10:30:31 +0200612 CreateVp8TemporalLayers(Vp8TemporalLayersType::kFixedPattern,
613 config->VP8().numberOfTemporalLayers));
sprangfe627f32017-03-29 08:24:59 -0700614 }
615 }
616 if (force_init_encode_failed_)
617 return -1;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100618
619 initialized_ = true;
sprangfe627f32017-03-29 08:24:59 -0700620 return res;
621 }
622
Niels Möller6bb5ab92019-01-11 11:11:10 +0100623 int32_t SetRateAllocation(const VideoBitrateAllocation& rate_allocation,
624 uint32_t framerate) {
625 rtc::CritScope lock(&local_crit_sect_);
626 VideoBitrateAllocation adjusted_rate_allocation;
627 for (size_t si = 0; si < kMaxSpatialLayers; ++si) {
628 for (size_t ti = 0; ti < kMaxTemporalStreams; ++ti) {
629 if (rate_allocation.HasBitrate(si, ti)) {
630 adjusted_rate_allocation.SetBitrate(
631 si, ti,
632 static_cast<uint32_t>(rate_allocation.GetBitrate(si, ti) *
633 rate_factor_));
634 }
635 }
636 }
637 last_framerate_ = framerate;
638 return FakeEncoder::SetRateAllocation(adjusted_rate_allocation,
639 framerate);
640 }
641
brandtre78d2662017-01-16 05:57:16 -0800642 rtc::CriticalSection local_crit_sect_;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100643 bool initialized_ RTC_GUARDED_BY(local_crit_sect_) = false;
danilchapa37de392017-09-09 04:17:22 -0700644 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700645 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700646 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
647 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
648 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
649 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
650 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100651 bool is_hardware_accelerated_ RTC_GUARDED_BY(local_crit_sect_) = false;
Erik Språng4529fbc2018-10-12 10:30:31 +0200652 std::vector<std::unique_ptr<Vp8TemporalLayers>> allocated_temporal_layers_
danilchapa37de392017-09-09 04:17:22 -0700653 RTC_GUARDED_BY(local_crit_sect_);
654 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
Niels Möller6bb5ab92019-01-11 11:11:10 +0100655 double rate_factor_ RTC_GUARDED_BY(local_crit_sect_) = 1.0;
656 uint32_t last_framerate_ RTC_GUARDED_BY(local_crit_sect_) = 0;
perkj26091b12016-09-01 01:17:40 -0700657 };
658
mflodmancc3d4422017-08-03 08:27:51 -0700659 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700660 public:
661 explicit TestSink(TestEncoder* test_encoder)
Niels Möllerc572ff32018-11-07 08:43:50 +0100662 : test_encoder_(test_encoder) {}
perkj26091b12016-09-01 01:17:40 -0700663
perkj26091b12016-09-01 01:17:40 -0700664 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700665 EXPECT_TRUE(
666 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
667 }
668
669 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
670 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700671 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700672 if (!encoded_frame_event_.Wait(timeout_ms))
673 return false;
perkj26091b12016-09-01 01:17:40 -0700674 {
675 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800676 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700677 }
678 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700679 return true;
perkj26091b12016-09-01 01:17:40 -0700680 }
681
sprangb1ca0732017-02-01 08:38:12 -0800682 void WaitForEncodedFrame(uint32_t expected_width,
683 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700684 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100685 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700686 }
687
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100688 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700689 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800690 uint32_t width = 0;
691 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800692 {
693 rtc::CritScope lock(&crit_);
694 width = last_width_;
695 height = last_height_;
696 }
697 EXPECT_EQ(expected_height, height);
698 EXPECT_EQ(expected_width, width);
699 }
700
kthelgason2fc52542017-03-03 00:24:41 -0800701 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800702
sprangc5d62e22017-04-02 23:53:04 -0700703 bool WaitForFrame(int64_t timeout_ms) {
704 return encoded_frame_event_.Wait(timeout_ms);
705 }
706
perkj26091b12016-09-01 01:17:40 -0700707 void SetExpectNoFrames() {
708 rtc::CritScope lock(&crit_);
709 expect_frames_ = false;
710 }
711
asaperssonfab67072017-04-04 05:51:49 -0700712 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200713 rtc::CritScope lock(&crit_);
714 return number_of_reconfigurations_;
715 }
716
asaperssonfab67072017-04-04 05:51:49 -0700717 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200718 rtc::CritScope lock(&crit_);
719 return min_transmit_bitrate_bps_;
720 }
721
perkj26091b12016-09-01 01:17:40 -0700722 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700723 Result OnEncodedImage(
724 const EncodedImage& encoded_image,
725 const CodecSpecificInfo* codec_specific_info,
726 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200727 rtc::CritScope lock(&crit_);
728 EXPECT_TRUE(expect_frames_);
Niels Möller23775882018-08-16 10:24:12 +0200729 last_timestamp_ = encoded_image.Timestamp();
sprangb1ca0732017-02-01 08:38:12 -0800730 last_width_ = encoded_image._encodedWidth;
731 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200732 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800733 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200734 }
735
736 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
737 int min_transmit_bitrate_bps) override {
738 rtc::CriticalSection crit_;
739 ++number_of_reconfigurations_;
740 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
741 }
742
perkj26091b12016-09-01 01:17:40 -0700743 rtc::CriticalSection crit_;
744 TestEncoder* test_encoder_;
745 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800746 uint32_t last_timestamp_ = 0;
747 uint32_t last_height_ = 0;
748 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700749 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200750 int number_of_reconfigurations_ = 0;
751 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700752 };
753
754 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100755 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200756 int codec_width_;
757 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700758 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700759 TestEncoder fake_encoder_;
Niels Möllercbcbc222018-09-28 09:07:24 +0200760 test::VideoEncoderProxyFactory encoder_factory_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800761 std::unique_ptr<VideoBitrateAllocatorFactory> bitrate_allocator_factory_;
sprangc5d62e22017-04-02 23:53:04 -0700762 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700763 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800764 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700765 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700766 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700767};
768
mflodmancc3d4422017-08-03 08:27:51 -0700769TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
770 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Niels Möllerc572ff32018-11-07 08:43:50 +0100771 rtc::Event frame_destroyed_event;
perkja49cbd32016-09-16 07:53:41 -0700772 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700773 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700774 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700775 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700776}
777
mflodmancc3d4422017-08-03 08:27:51 -0700778TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700779 // Dropped since no target bitrate has been set.
Niels Möllerc572ff32018-11-07 08:43:50 +0100780 rtc::Event frame_destroyed_event;
Sebastian Janssona3177052018-04-10 13:05:49 +0200781 // The encoder will cache up to one frame for a short duration. Adding two
782 // frames means that the first frame will be dropped and the second frame will
783 // be sent when the encoder is enabled.
perkja49cbd32016-09-16 07:53:41 -0700784 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
Sebastian Janssona3177052018-04-10 13:05:49 +0200785 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkja49cbd32016-09-16 07:53:41 -0700786 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700787
mflodmancc3d4422017-08-03 08:27:51 -0700788 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700789
Sebastian Janssona3177052018-04-10 13:05:49 +0200790 // The pending frame should be received.
sprang4847ae62017-06-27 07:06:52 -0700791 WaitForEncodedFrame(2);
Sebastian Janssona3177052018-04-10 13:05:49 +0200792 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
793
794 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700795 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700796}
797
mflodmancc3d4422017-08-03 08:27:51 -0700798TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
799 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700800 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700801 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700802
mflodmancc3d4422017-08-03 08:27:51 -0700803 video_stream_encoder_->OnBitrateUpdated(0, 0, 0);
Sebastian Janssona3177052018-04-10 13:05:49 +0200804 // The encoder will cache up to one frame for a short duration. Adding two
805 // frames means that the first frame will be dropped and the second frame will
806 // be sent when the encoder is resumed.
perkja49cbd32016-09-16 07:53:41 -0700807 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Sebastian Janssona3177052018-04-10 13:05:49 +0200808 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700809
mflodmancc3d4422017-08-03 08:27:51 -0700810 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -0700811 WaitForEncodedFrame(3);
Sebastian Janssona3177052018-04-10 13:05:49 +0200812 video_source_.IncomingCapturedFrame(CreateFrame(4, nullptr));
813 WaitForEncodedFrame(4);
mflodmancc3d4422017-08-03 08:27:51 -0700814 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700815}
816
mflodmancc3d4422017-08-03 08:27:51 -0700817TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
818 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700819 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700820 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700821
822 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700823 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700824
perkja49cbd32016-09-16 07:53:41 -0700825 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700826 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700827 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700828}
829
mflodmancc3d4422017-08-03 08:27:51 -0700830TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
831 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700832
perkja49cbd32016-09-16 07:53:41 -0700833 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700834 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700835
mflodmancc3d4422017-08-03 08:27:51 -0700836 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700837 sink_.SetExpectNoFrames();
Niels Möllerc572ff32018-11-07 08:43:50 +0100838 rtc::Event frame_destroyed_event;
perkja49cbd32016-09-16 07:53:41 -0700839 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
840 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700841}
842
mflodmancc3d4422017-08-03 08:27:51 -0700843TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
844 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700845
846 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700847 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700848 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700849 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
850 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700851 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
852 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700853 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700854 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700855
mflodmancc3d4422017-08-03 08:27:51 -0700856 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700857}
858
mflodmancc3d4422017-08-03 08:27:51 -0700859TEST_F(VideoStreamEncoderTest,
860 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
861 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100862 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200863
864 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200865 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700866 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100867 // The encoder will have been configured once when the first frame is
868 // received.
869 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200870
871 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200872 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200873 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -0700874 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200875 kMaxPayloadLength);
Per512ecb32016-09-23 15:52:06 +0200876
877 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200878 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700879 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100880 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700881 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700882
mflodmancc3d4422017-08-03 08:27:51 -0700883 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -0700884}
885
mflodmancc3d4422017-08-03 08:27:51 -0700886TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
887 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkjfa10b552016-10-02 23:45:26 -0700888
889 // Capture a frame and wait for it to synchronize with the encoder thread.
890 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700891 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100892 // The encoder will have been configured once.
893 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700894 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
895 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
896
897 codec_width_ *= 2;
898 codec_height_ *= 2;
899 // Capture a frame with a higher resolution and wait for it to synchronize
900 // with the encoder thread.
901 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700902 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700903 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
904 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100905 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700906
mflodmancc3d4422017-08-03 08:27:51 -0700907 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -0700908}
909
mflodmancc3d4422017-08-03 08:27:51 -0700910TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -0700911 EXPECT_TRUE(video_source_.has_sinks());
912 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700913 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700914 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -0700915 EXPECT_FALSE(video_source_.has_sinks());
916 EXPECT_TRUE(new_video_source.has_sinks());
917
mflodmancc3d4422017-08-03 08:27:51 -0700918 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700919}
920
mflodmancc3d4422017-08-03 08:27:51 -0700921TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -0700922 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700923 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -0700924 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700925 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700926}
927
Jonathan Yubc771b72017-12-08 17:04:29 -0800928TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
929 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -0700930 const int kWidth = 1280;
931 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -0800932
933 // We rely on the automatic resolution adaptation, but we handle framerate
934 // adaptation manually by mocking the stats proxy.
935 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -0700936
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700937 // Enable BALANCED preference, no initial limitation.
Jonathan Yubc771b72017-12-08 17:04:29 -0800938 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700939 video_stream_encoder_->SetSource(&video_source_,
940 webrtc::DegradationPreference::BALANCED);
Jonathan Yubc771b72017-12-08 17:04:29 -0800941 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -0700942 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800943 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -0700944 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
945
Jonathan Yubc771b72017-12-08 17:04:29 -0800946 // Adapt down as far as possible.
947 rtc::VideoSinkWants last_wants;
948 int64_t t = 1;
949 int loop_count = 0;
950 do {
951 ++loop_count;
952 last_wants = video_source_.sink_wants();
953
954 // Simulate the framerate we've been asked to adapt to.
955 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
956 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
957 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
958 mock_stats.input_frame_rate = fps;
959 stats_proxy_->SetMockStats(mock_stats);
960
961 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
962 sink_.WaitForEncodedFrame(t);
963 t += frame_interval_ms;
964
mflodmancc3d4422017-08-03 08:27:51 -0700965 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -0800966 VerifyBalancedModeFpsRange(
967 video_source_.sink_wants(),
968 *video_source_.last_sent_width() * *video_source_.last_sent_height());
969 } while (video_source_.sink_wants().max_pixel_count <
970 last_wants.max_pixel_count ||
971 video_source_.sink_wants().max_framerate_fps <
972 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700973
Jonathan Yubc771b72017-12-08 17:04:29 -0800974 // Verify that we've adapted all the way down.
975 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -0700976 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -0800977 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
978 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -0700979 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -0800980 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
981 *video_source_.last_sent_height());
982 EXPECT_EQ(kMinBalancedFramerateFps,
983 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700984
Jonathan Yubc771b72017-12-08 17:04:29 -0800985 // Adapt back up the same number of times we adapted down.
986 for (int i = 0; i < loop_count - 1; ++i) {
987 last_wants = video_source_.sink_wants();
988
989 // Simulate the framerate we've been asked to adapt to.
990 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
991 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
992 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
993 mock_stats.input_frame_rate = fps;
994 stats_proxy_->SetMockStats(mock_stats);
995
996 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
997 sink_.WaitForEncodedFrame(t);
998 t += frame_interval_ms;
999
mflodmancc3d4422017-08-03 08:27:51 -07001000 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -08001001 VerifyBalancedModeFpsRange(
1002 video_source_.sink_wants(),
1003 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1004 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
1005 last_wants.max_pixel_count ||
1006 video_source_.sink_wants().max_framerate_fps >
1007 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001008 }
1009
Åsa Persson8c1bf952018-09-13 10:42:19 +02001010 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001011 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001012 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001013 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1014 EXPECT_EQ((loop_count - 1) * 2,
1015 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -07001016
mflodmancc3d4422017-08-03 08:27:51 -07001017 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001018}
mflodmancc3d4422017-08-03 08:27:51 -07001019TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
1020 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001021 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001022
sprangc5d62e22017-04-02 23:53:04 -07001023 const int kFrameWidth = 1280;
1024 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07001025
Åsa Persson8c1bf952018-09-13 10:42:19 +02001026 int64_t frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -07001027
kthelgason5e13d412016-12-01 03:59:51 -08001028 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001029 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001030 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001031 frame_timestamp += kFrameIntervalMs;
1032
perkj803d97f2016-11-01 11:45:46 -07001033 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001034 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001035 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001036 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001037 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001038 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -07001039
asapersson0944a802017-04-07 00:57:58 -07001040 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -07001041 // wanted resolution.
1042 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
1043 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
1044 kFrameWidth * kFrameHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001045 EXPECT_EQ(kDefaultFramerate, video_source_.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001046
1047 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -07001048 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001049 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001050 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001051
sprangc5d62e22017-04-02 23:53:04 -07001052 // Initially no degradation registered.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001053 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001054
sprangc5d62e22017-04-02 23:53:04 -07001055 // Force an input frame rate to be available, or the adaptation call won't
1056 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -07001057 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -07001058 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -07001059 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -07001060 stats_proxy_->SetMockStats(stats);
1061
mflodmancc3d4422017-08-03 08:27:51 -07001062 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001063 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001064 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001065 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001066 frame_timestamp += kFrameIntervalMs;
1067
1068 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001069 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001070 EXPECT_EQ(std::numeric_limits<int>::max(),
1071 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001072 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001073
asapersson02465b82017-04-10 01:12:52 -07001074 // Turn off degradation completely.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001075 video_stream_encoder_->SetSource(&new_video_source,
1076 webrtc::DegradationPreference::DISABLED);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001077 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001078
mflodmancc3d4422017-08-03 08:27:51 -07001079 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001080 new_video_source.IncomingCapturedFrame(
1081 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001082 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001083 frame_timestamp += kFrameIntervalMs;
1084
1085 // Still no degradation.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001086 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001087
1088 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001089 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001090 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
sprangc5d62e22017-04-02 23:53:04 -07001091 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1092 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001093 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001094 EXPECT_EQ(kDefaultFramerate, new_video_source.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001095
1096 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001097 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001098 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001099 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1100 EXPECT_EQ(std::numeric_limits<int>::max(),
1101 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001102 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001103
mflodmancc3d4422017-08-03 08:27:51 -07001104 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001105}
1106
mflodmancc3d4422017-08-03 08:27:51 -07001107TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
1108 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001109
asaperssonfab67072017-04-04 05:51:49 -07001110 const int kWidth = 1280;
1111 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001112 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001113 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001114 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1115 EXPECT_FALSE(stats.bw_limited_resolution);
1116 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1117
1118 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001119 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001120 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001121 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001122
1123 stats = stats_proxy_->GetStats();
1124 EXPECT_TRUE(stats.bw_limited_resolution);
1125 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1126
1127 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001128 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001129 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001130 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001131
1132 stats = stats_proxy_->GetStats();
1133 EXPECT_FALSE(stats.bw_limited_resolution);
1134 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1135 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1136
mflodmancc3d4422017-08-03 08:27:51 -07001137 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001138}
1139
mflodmancc3d4422017-08-03 08:27:51 -07001140TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
1141 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001142
1143 const int kWidth = 1280;
1144 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001145 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001146 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001147 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1148 EXPECT_FALSE(stats.cpu_limited_resolution);
1149 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1150
1151 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001152 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001153 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001154 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001155
1156 stats = stats_proxy_->GetStats();
1157 EXPECT_TRUE(stats.cpu_limited_resolution);
1158 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1159
1160 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001161 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001162 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001163 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001164
1165 stats = stats_proxy_->GetStats();
1166 EXPECT_FALSE(stats.cpu_limited_resolution);
1167 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001168 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001169
mflodmancc3d4422017-08-03 08:27:51 -07001170 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001171}
1172
mflodmancc3d4422017-08-03 08:27:51 -07001173TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
1174 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001175
asaperssonfab67072017-04-04 05:51:49 -07001176 const int kWidth = 1280;
1177 const int kHeight = 720;
1178 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001179 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001180 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001181 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001182 EXPECT_FALSE(stats.cpu_limited_resolution);
1183 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1184
asaperssonfab67072017-04-04 05:51:49 -07001185 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001186 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001187 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001188 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001189 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001190 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001191 EXPECT_TRUE(stats.cpu_limited_resolution);
1192 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1193
1194 // Set new source with adaptation still enabled.
1195 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001196 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001197 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001198
asaperssonfab67072017-04-04 05:51:49 -07001199 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001200 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001201 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001202 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001203 EXPECT_TRUE(stats.cpu_limited_resolution);
1204 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1205
1206 // Set adaptation disabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001207 video_stream_encoder_->SetSource(&new_video_source,
1208 webrtc::DegradationPreference::DISABLED);
kthelgason876222f2016-11-29 01:44:11 -08001209
asaperssonfab67072017-04-04 05:51:49 -07001210 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001211 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001212 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001213 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001214 EXPECT_FALSE(stats.cpu_limited_resolution);
1215 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1216
1217 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001218 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001219 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001220
asaperssonfab67072017-04-04 05:51:49 -07001221 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001222 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001223 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001224 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001225 EXPECT_TRUE(stats.cpu_limited_resolution);
1226 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1227
asaperssonfab67072017-04-04 05:51:49 -07001228 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001229 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001230 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001231 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001232 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001233 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001234 EXPECT_FALSE(stats.cpu_limited_resolution);
1235 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001236 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001237
mflodmancc3d4422017-08-03 08:27:51 -07001238 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001239}
1240
mflodmancc3d4422017-08-03 08:27:51 -07001241TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
1242 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001243
asaperssonfab67072017-04-04 05:51:49 -07001244 const int kWidth = 1280;
1245 const int kHeight = 720;
1246 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001247 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001248 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001249 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001250 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001251 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001252
1253 // Set new source with adaptation still enabled.
1254 test::FrameForwarder new_video_source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001255 video_stream_encoder_->SetSource(&new_video_source,
1256 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001257
asaperssonfab67072017-04-04 05:51:49 -07001258 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001259 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001260 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001261 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001262 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001263 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001264
asaperssonfab67072017-04-04 05:51:49 -07001265 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001266 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001267 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001268 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001269 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001270 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001271 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001272 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001273
asaperssonfab67072017-04-04 05:51:49 -07001274 // Set new source with adaptation still enabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001275 video_stream_encoder_->SetSource(&new_video_source,
1276 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001277
asaperssonfab67072017-04-04 05:51:49 -07001278 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001279 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001280 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001281 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001282 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001283 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001284
asapersson02465b82017-04-10 01:12:52 -07001285 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001286 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001287 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001288
asaperssonfab67072017-04-04 05:51:49 -07001289 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001290 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001291 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001292 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001293 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001294 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1295 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001296
mflodmancc3d4422017-08-03 08:27:51 -07001297 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001298}
1299
mflodmancc3d4422017-08-03 08:27:51 -07001300TEST_F(VideoStreamEncoderTest,
1301 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1302 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001303
1304 const int kWidth = 1280;
1305 const int kHeight = 720;
Åsa Persson8c1bf952018-09-13 10:42:19 +02001306 int64_t timestamp_ms = kFrameIntervalMs;
asapersson36e9eb42017-03-31 05:29:12 -07001307 video_source_.set_adaptation_enabled(true);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001308 video_source_.IncomingCapturedFrame(
1309 CreateFrame(timestamp_ms, kWidth, kHeight));
1310 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001311 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1312 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1313 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1314
1315 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001316 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001317 timestamp_ms += kFrameIntervalMs;
1318 video_source_.IncomingCapturedFrame(
1319 CreateFrame(timestamp_ms, kWidth, kHeight));
1320 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001321 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1322 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1323 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1324
1325 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001326 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001327 timestamp_ms += kFrameIntervalMs;
1328 video_source_.IncomingCapturedFrame(
1329 CreateFrame(timestamp_ms, kWidth, kHeight));
1330 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001331 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1332 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1333 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1334
Niels Möller4db138e2018-04-19 09:04:13 +02001335 // Leave source unchanged, but disable quality scaler.
asapersson36e9eb42017-03-31 05:29:12 -07001336 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02001337
1338 VideoEncoderConfig video_encoder_config;
1339 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
1340 // Make format different, to force recreation of encoder.
1341 video_encoder_config.video_format.parameters["foo"] = "foo";
1342 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001343 kMaxPayloadLength);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001344 timestamp_ms += kFrameIntervalMs;
1345 video_source_.IncomingCapturedFrame(
1346 CreateFrame(timestamp_ms, kWidth, kHeight));
1347 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001348 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1349 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1350 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1351
mflodmancc3d4422017-08-03 08:27:51 -07001352 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001353}
1354
mflodmancc3d4422017-08-03 08:27:51 -07001355TEST_F(VideoStreamEncoderTest,
1356 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
1357 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001358
asapersson0944a802017-04-07 00:57:58 -07001359 const int kWidth = 1280;
1360 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001361 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001362
asaperssonfab67072017-04-04 05:51:49 -07001363 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001364 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001365 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001366 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001367 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001368 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1369
asapersson02465b82017-04-10 01:12:52 -07001370 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001371 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001372 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001373 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001374 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001375 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001376 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001377 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1378
1379 // Set new source with adaptation still enabled.
1380 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001381 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001382 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001383
1384 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001385 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001386 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001387 stats = stats_proxy_->GetStats();
1388 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001389 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001390 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1391
sprangc5d62e22017-04-02 23:53:04 -07001392 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001393 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001394 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001395 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001396 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001397 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001398 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001399 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001400 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001401 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001402 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1403
sprangc5d62e22017-04-02 23:53:04 -07001404 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001405 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001406 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1407 mock_stats.input_frame_rate = 30;
1408 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001409 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001410 stats_proxy_->ResetMockStats();
1411
1412 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001413 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001414 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001415
1416 // Framerate now adapted.
1417 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001418 EXPECT_FALSE(stats.cpu_limited_resolution);
1419 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001420 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1421
1422 // Disable CPU adaptation.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001423 video_stream_encoder_->SetSource(&new_video_source,
1424 webrtc::DegradationPreference::DISABLED);
sprangc5d62e22017-04-02 23:53:04 -07001425 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001426 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001427 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001428
1429 stats = stats_proxy_->GetStats();
1430 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001431 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001432 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1433
1434 // Try to trigger overuse. Should not succeed.
1435 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001436 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001437 stats_proxy_->ResetMockStats();
1438
1439 stats = stats_proxy_->GetStats();
1440 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001441 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001442 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1443
1444 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001445 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001446 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssonfab67072017-04-04 05:51:49 -07001447 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001448 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001449 stats = stats_proxy_->GetStats();
1450 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001451 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001452 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001453
1454 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001455 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001456 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001457 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001458 stats = stats_proxy_->GetStats();
1459 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001460 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001461 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1462
1463 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001464 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001465 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001466 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001467 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001468 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001469 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001470 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001471 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001472 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001473 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1474
1475 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001476 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001477 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001478 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001479 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001480 stats = stats_proxy_->GetStats();
1481 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001482 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001483 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001484 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001485
mflodmancc3d4422017-08-03 08:27:51 -07001486 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001487}
1488
mflodmancc3d4422017-08-03 08:27:51 -07001489TEST_F(VideoStreamEncoderTest,
1490 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001491 const int kWidth = 1280;
1492 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001493 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001494
asaperssonfab67072017-04-04 05:51:49 -07001495 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001496 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001497
asaperssonfab67072017-04-04 05:51:49 -07001498 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001499 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001500
asaperssonfab67072017-04-04 05:51:49 -07001501 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001502 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001503
asaperssonfab67072017-04-04 05:51:49 -07001504 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001505 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001506
kthelgason876222f2016-11-29 01:44:11 -08001507 // Expect a scale down.
1508 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001509 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001510
asapersson02465b82017-04-10 01:12:52 -07001511 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001512 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001513 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001514 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001515
asaperssonfab67072017-04-04 05:51:49 -07001516 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001517 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001518 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001519 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001520
asaperssonfab67072017-04-04 05:51:49 -07001521 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001522 EXPECT_EQ(std::numeric_limits<int>::max(),
1523 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001524
asaperssonfab67072017-04-04 05:51:49 -07001525 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001526 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001527 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001528 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001529
asapersson02465b82017-04-10 01:12:52 -07001530 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001531 EXPECT_EQ(std::numeric_limits<int>::max(),
1532 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001533
mflodmancc3d4422017-08-03 08:27:51 -07001534 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001535}
1536
mflodmancc3d4422017-08-03 08:27:51 -07001537TEST_F(VideoStreamEncoderTest,
1538 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001539 const int kWidth = 1280;
1540 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001541 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001542
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001543 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001544 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001545 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001546 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001547
1548 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001549 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001550 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001551 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1552 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1553
1554 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001555 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001556 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001557 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1558 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1559 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1560
1561 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001562 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001563 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1564 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1565 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1566
mflodmancc3d4422017-08-03 08:27:51 -07001567 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001568}
1569
mflodmancc3d4422017-08-03 08:27:51 -07001570TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001571 const int kWidth = 1280;
1572 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001573 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001574
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001575 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001576 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001577 video_stream_encoder_->SetSource(&source,
1578 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001579 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1580 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001581 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001582
1583 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001584 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001585 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1586 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1587 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1588 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1589
1590 // Trigger adapt down for same input resolution, expect no change.
1591 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1592 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001593 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001594 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1595 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1596 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1597
1598 // Trigger adapt down for larger input resolution, expect no change.
1599 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1600 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001601 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001602 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1603 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1604 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1605
mflodmancc3d4422017-08-03 08:27:51 -07001606 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001607}
1608
mflodmancc3d4422017-08-03 08:27:51 -07001609TEST_F(VideoStreamEncoderTest,
1610 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001611 const int kWidth = 1280;
1612 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001613 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001614
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001615 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001616 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001617 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001618 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001619
1620 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001621 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001622 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001623 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1624 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1625
1626 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001627 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001628 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001629 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1630 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1631
mflodmancc3d4422017-08-03 08:27:51 -07001632 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001633}
1634
mflodmancc3d4422017-08-03 08:27:51 -07001635TEST_F(VideoStreamEncoderTest,
1636 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001637 const int kWidth = 1280;
1638 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001639 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001640
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001641 // Enable MAINTAIN_RESOLUTION preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001642 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001643 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001644 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
asapersson02465b82017-04-10 01:12:52 -07001645
1646 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001647 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001648 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001649 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001650 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1651
1652 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001653 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001654 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001655 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001656 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1657
mflodmancc3d4422017-08-03 08:27:51 -07001658 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001659}
1660
mflodmancc3d4422017-08-03 08:27:51 -07001661TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001662 const int kWidth = 1280;
1663 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001664 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001665
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001666 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001667 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001668 video_stream_encoder_->SetSource(&source,
1669 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001670
1671 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1672 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001673 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001674 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1675 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1676 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1677
1678 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001679 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001680 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001681 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1682 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1683 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1684
mflodmancc3d4422017-08-03 08:27:51 -07001685 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001686}
1687
mflodmancc3d4422017-08-03 08:27:51 -07001688TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001689 const int kWidth = 1280;
1690 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001691 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001692
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001693 // Enable DISABLED preference, no initial limitation.
asapersson09f05612017-05-15 23:40:18 -07001694 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001695 video_stream_encoder_->SetSource(&source,
1696 webrtc::DegradationPreference::DISABLED);
asapersson09f05612017-05-15 23:40:18 -07001697
1698 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1699 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001700 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001701 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1702 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1703 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1704
1705 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001706 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001707 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001708 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1709 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1710 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1711
mflodmancc3d4422017-08-03 08:27:51 -07001712 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001713}
1714
mflodmancc3d4422017-08-03 08:27:51 -07001715TEST_F(VideoStreamEncoderTest,
1716 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001717 const int kWidth = 1280;
1718 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001719 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001720
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001721 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001722 AdaptingFrameForwarder source;
1723 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001724 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001725 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001726
1727 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001728 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001729 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001730 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1731 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1732
1733 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001734 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001735 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001736 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001737 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001738 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1739 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1740
1741 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001742 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001743 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001744 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1745 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1746 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1747
mflodmancc3d4422017-08-03 08:27:51 -07001748 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001749}
1750
mflodmancc3d4422017-08-03 08:27:51 -07001751TEST_F(VideoStreamEncoderTest,
1752 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001753 const int kWidth = 1280;
1754 const int kHeight = 720;
1755 const int kInputFps = 30;
mflodmancc3d4422017-08-03 08:27:51 -07001756 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001757
1758 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1759 stats.input_frame_rate = kInputFps;
1760 stats_proxy_->SetMockStats(stats);
1761
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001762 // Expect no scaling to begin with (preference: MAINTAIN_FRAMERATE).
asapersson09f05612017-05-15 23:40:18 -07001763 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1764 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001765 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001766
1767 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001768 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001769 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1770 sink_.WaitForEncodedFrame(2);
1771 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1772
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001773 // Enable MAINTAIN_RESOLUTION preference.
asapersson09f05612017-05-15 23:40:18 -07001774 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001775 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001776 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001777 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001778
1779 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001780 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001781 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1782 sink_.WaitForEncodedFrame(3);
1783 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1784
1785 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001786 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001787 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001788
mflodmancc3d4422017-08-03 08:27:51 -07001789 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001790}
1791
mflodmancc3d4422017-08-03 08:27:51 -07001792TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001793 const int kWidth = 1280;
1794 const int kHeight = 720;
1795 const size_t kNumFrames = 10;
1796
mflodmancc3d4422017-08-03 08:27:51 -07001797 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001798
asaperssond0de2952017-04-21 01:47:31 -07001799 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001800 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001801 video_source_.set_adaptation_enabled(true);
1802
1803 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1804 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1805
1806 int downscales = 0;
1807 for (size_t i = 1; i <= kNumFrames; i++) {
Åsa Persson8c1bf952018-09-13 10:42:19 +02001808 video_source_.IncomingCapturedFrame(
1809 CreateFrame(i * kFrameIntervalMs, kWidth, kHeight));
1810 WaitForEncodedFrame(i * kFrameIntervalMs);
asaperssond0de2952017-04-21 01:47:31 -07001811
asaperssonfab67072017-04-04 05:51:49 -07001812 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001813 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001814 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001815 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001816
1817 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1818 ++downscales;
1819
1820 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1821 EXPECT_EQ(downscales,
1822 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1823 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001824 }
mflodmancc3d4422017-08-03 08:27:51 -07001825 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001826}
1827
mflodmancc3d4422017-08-03 08:27:51 -07001828TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001829 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1830 const int kWidth = 1280;
1831 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001832 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001833
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001834 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001835 AdaptingFrameForwarder source;
1836 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001837 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001838 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001839
Åsa Persson8c1bf952018-09-13 10:42:19 +02001840 int64_t timestamp_ms = kFrameIntervalMs;
1841 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001842 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001843 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001844 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1845 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1846
1847 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001848 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001849 timestamp_ms += kFrameIntervalMs;
1850 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1851 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001852 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001853 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1854 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1855
1856 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001857 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001858 timestamp_ms += kFrameIntervalMs;
1859 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001860 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001861 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001862 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1863 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1864
1865 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001866 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001867 timestamp_ms += kFrameIntervalMs;
1868 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1869 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001870 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001871 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1872 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1873
1874 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001875 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001876 timestamp_ms += kFrameIntervalMs;
1877 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asapersson09f05612017-05-15 23:40:18 -07001878 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001879 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001880 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1881 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1882
mflodmancc3d4422017-08-03 08:27:51 -07001883 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001884}
1885
mflodmancc3d4422017-08-03 08:27:51 -07001886TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07001887 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
1888 const int kWidth = 1280;
1889 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001890 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001891
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001892 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001893 AdaptingFrameForwarder source;
1894 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001895 video_stream_encoder_->SetSource(&source,
1896 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001897
Åsa Persson8c1bf952018-09-13 10:42:19 +02001898 int64_t timestamp_ms = kFrameIntervalMs;
1899 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001900 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001901 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001902 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1903 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1904
1905 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001906 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001907 timestamp_ms += kFrameIntervalMs;
1908 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1909 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07001910 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1911 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1912 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1913
1914 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001915 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001916 timestamp_ms += kFrameIntervalMs;
1917 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001918 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001919 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001920 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1921 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1922
1923 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001924 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001925 timestamp_ms += kFrameIntervalMs;
1926 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1927 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07001928 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1929 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1930 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1931
1932 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001933 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001934 timestamp_ms += kFrameIntervalMs;
1935 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07001936 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001937 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001938 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1939 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1940
mflodmancc3d4422017-08-03 08:27:51 -07001941 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001942}
1943
mflodmancc3d4422017-08-03 08:27:51 -07001944TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001945 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
1946 const int kWidth = 1280;
1947 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001948 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001949
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001950 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001951 AdaptingFrameForwarder source;
1952 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001953 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001954 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001955
Åsa Persson8c1bf952018-09-13 10:42:19 +02001956 int64_t timestamp_ms = kFrameIntervalMs;
1957 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001958 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001959 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001960 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1961 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1962 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1963 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1964
1965 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001966 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001967 timestamp_ms += kFrameIntervalMs;
1968 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1969 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001970 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001971 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1972 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1973 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1974 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1975
1976 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07001977 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001978 timestamp_ms += kFrameIntervalMs;
1979 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1980 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001981 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001982 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1983 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1984 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1985 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1986
Jonathan Yubc771b72017-12-08 17:04:29 -08001987 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001988 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001989 timestamp_ms += kFrameIntervalMs;
1990 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1991 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08001992 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07001993 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1994 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001995 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07001996 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1997
Jonathan Yubc771b72017-12-08 17:04:29 -08001998 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07001999 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002000 timestamp_ms += kFrameIntervalMs;
2001 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2002 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002003 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002004 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07002005 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2006 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2007 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2008 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2009
Jonathan Yubc771b72017-12-08 17:04:29 -08002010 // Trigger quality adapt down, expect no change (min resolution reached).
2011 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002012 timestamp_ms += kFrameIntervalMs;
2013 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2014 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002015 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
2016 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2017 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2018 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2019 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2020
2021 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002022 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002023 timestamp_ms += kFrameIntervalMs;
2024 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2025 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002026 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002027 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2028 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2029 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2030 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2031
2032 // Trigger cpu adapt up, expect upscaled resolution (640x360).
2033 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002034 timestamp_ms += kFrameIntervalMs;
2035 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2036 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002037 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2038 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2039 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2040 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2041 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2042
2043 // Trigger cpu adapt up, expect upscaled resolution (960x540).
2044 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002045 timestamp_ms += kFrameIntervalMs;
2046 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2047 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002048 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002049 last_wants = source.sink_wants();
2050 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2051 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002052 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002053 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2054
2055 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002056 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002057 timestamp_ms += kFrameIntervalMs;
2058 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2059 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002060 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002061 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2062 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002063 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002064 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2065
2066 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002067 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002068 timestamp_ms += kFrameIntervalMs;
2069 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002070 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002071 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002072 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002073 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2074 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002075 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002076 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002077
mflodmancc3d4422017-08-03 08:27:51 -07002078 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002079}
2080
mflodmancc3d4422017-08-03 08:27:51 -07002081TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002082 const int kWidth = 640;
2083 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002084
mflodmancc3d4422017-08-03 08:27:51 -07002085 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002086
perkj803d97f2016-11-01 11:45:46 -07002087 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002088 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002089 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002090 }
2091
mflodmancc3d4422017-08-03 08:27:51 -07002092 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002093 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002094 video_source_.IncomingCapturedFrame(CreateFrame(
2095 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002096 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002097 }
2098
mflodmancc3d4422017-08-03 08:27:51 -07002099 video_stream_encoder_->Stop();
2100 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002101 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002102
perkj803d97f2016-11-01 11:45:46 -07002103 EXPECT_EQ(1,
2104 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2105 EXPECT_EQ(
2106 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2107}
2108
mflodmancc3d4422017-08-03 08:27:51 -07002109TEST_F(VideoStreamEncoderTest,
2110 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2111 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002112 const int kWidth = 640;
2113 const int kHeight = 360;
2114
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002115 video_stream_encoder_->SetSource(&video_source_,
2116 webrtc::DegradationPreference::DISABLED);
asaperssonf4e44af2017-04-19 02:01:06 -07002117
2118 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2119 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002120 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002121 }
2122
mflodmancc3d4422017-08-03 08:27:51 -07002123 video_stream_encoder_->Stop();
2124 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002125 stats_proxy_.reset();
2126
2127 EXPECT_EQ(0,
2128 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2129}
2130
mflodmancc3d4422017-08-03 08:27:51 -07002131TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002132 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02002133 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002134
2135 const int kDefaultFps = 30;
Erik Språng566124a2018-04-23 12:32:22 +02002136 const VideoBitrateAllocation expected_bitrate =
sprang57c2fff2017-01-16 06:24:02 -08002137 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002138 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002139
sprang57c2fff2017-01-16 06:24:02 -08002140 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
Niels Möller6bb5ab92019-01-11 11:11:10 +01002141 .Times(1);
mflodmancc3d4422017-08-03 08:27:51 -07002142 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002143
2144 const int64_t kStartTimeMs = 1;
2145 video_source_.IncomingCapturedFrame(
2146 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002147 WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002148
2149 // Not called on second frame.
2150 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2151 .Times(0);
2152 video_source_.IncomingCapturedFrame(
2153 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002154 WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002155
2156 // Called after a process interval.
2157 const int64_t kProcessIntervalMs =
2158 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang4847ae62017-06-27 07:06:52 -07002159 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec *
2160 (kProcessIntervalMs + (1000 / kDefaultFps)));
sprang57c2fff2017-01-16 06:24:02 -08002161 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2162 .Times(1);
2163 video_source_.IncomingCapturedFrame(CreateFrame(
2164 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002165 WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002166
mflodmancc3d4422017-08-03 08:27:51 -07002167 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002168}
2169
Niels Möller7dc26b72017-12-06 10:27:48 +01002170TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2171 const int kFrameWidth = 1280;
2172 const int kFrameHeight = 720;
2173 const int kFramerate = 24;
2174
2175 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2176 test::FrameForwarder source;
2177 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002178 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002179
2180 // Insert a single frame, triggering initial configuration.
2181 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2182 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2183
2184 EXPECT_EQ(
2185 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2186 kDefaultFramerate);
2187
2188 // Trigger reconfigure encoder (without resetting the entire instance).
2189 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002190 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002191 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2192 video_encoder_config.number_of_streams = 1;
2193 video_encoder_config.video_stream_factory =
2194 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2195 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002196 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002197 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2198
2199 // Detector should be updated with fps limit from codec config.
2200 EXPECT_EQ(
2201 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2202 kFramerate);
2203
2204 // Trigger overuse, max framerate should be reduced.
2205 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2206 stats.input_frame_rate = kFramerate;
2207 stats_proxy_->SetMockStats(stats);
2208 video_stream_encoder_->TriggerCpuOveruse();
2209 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2210 int adapted_framerate =
2211 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2212 EXPECT_LT(adapted_framerate, kFramerate);
2213
2214 // Trigger underuse, max framerate should go back to codec configured fps.
2215 // Set extra low fps, to make sure it's actually reset, not just incremented.
2216 stats = stats_proxy_->GetStats();
2217 stats.input_frame_rate = adapted_framerate / 2;
2218 stats_proxy_->SetMockStats(stats);
2219 video_stream_encoder_->TriggerCpuNormalUsage();
2220 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2221 EXPECT_EQ(
2222 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2223 kFramerate);
2224
2225 video_stream_encoder_->Stop();
2226}
2227
2228TEST_F(VideoStreamEncoderTest,
2229 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2230 const int kFrameWidth = 1280;
2231 const int kFrameHeight = 720;
2232 const int kLowFramerate = 15;
2233 const int kHighFramerate = 25;
2234
2235 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2236 test::FrameForwarder source;
2237 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002238 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002239
2240 // Trigger initial configuration.
2241 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002242 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002243 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2244 video_encoder_config.number_of_streams = 1;
2245 video_encoder_config.video_stream_factory =
2246 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2247 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2248 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002249 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002250 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2251
2252 EXPECT_EQ(
2253 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2254 kLowFramerate);
2255
2256 // Trigger overuse, max framerate should be reduced.
2257 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2258 stats.input_frame_rate = kLowFramerate;
2259 stats_proxy_->SetMockStats(stats);
2260 video_stream_encoder_->TriggerCpuOveruse();
2261 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2262 int adapted_framerate =
2263 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2264 EXPECT_LT(adapted_framerate, kLowFramerate);
2265
2266 // Reconfigure the encoder with a new (higher max framerate), max fps should
2267 // still respect the adaptation.
2268 video_encoder_config.video_stream_factory =
2269 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2270 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2271 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002272 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002273 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2274
2275 EXPECT_EQ(
2276 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2277 adapted_framerate);
2278
2279 // Trigger underuse, max framerate should go back to codec configured fps.
2280 stats = stats_proxy_->GetStats();
2281 stats.input_frame_rate = adapted_framerate;
2282 stats_proxy_->SetMockStats(stats);
2283 video_stream_encoder_->TriggerCpuNormalUsage();
2284 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2285 EXPECT_EQ(
2286 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2287 kHighFramerate);
2288
2289 video_stream_encoder_->Stop();
2290}
2291
mflodmancc3d4422017-08-03 08:27:51 -07002292TEST_F(VideoStreamEncoderTest,
2293 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002294 const int kFrameWidth = 1280;
2295 const int kFrameHeight = 720;
2296 const int kFramerate = 24;
2297
mflodmancc3d4422017-08-03 08:27:51 -07002298 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002299 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002300 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002301 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangfda496a2017-06-15 04:21:07 -07002302
2303 // Trigger initial configuration.
2304 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002305 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002306 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2307 video_encoder_config.number_of_streams = 1;
2308 video_encoder_config.video_stream_factory =
2309 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2310 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002311 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002312 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002313 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002314
Niels Möller7dc26b72017-12-06 10:27:48 +01002315 EXPECT_EQ(
2316 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2317 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002318
2319 // Trigger overuse, max framerate should be reduced.
2320 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2321 stats.input_frame_rate = kFramerate;
2322 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002323 video_stream_encoder_->TriggerCpuOveruse();
2324 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002325 int adapted_framerate =
2326 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002327 EXPECT_LT(adapted_framerate, kFramerate);
2328
2329 // Change degradation preference to not enable framerate scaling. Target
2330 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002331 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002332 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -07002333 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002334 EXPECT_EQ(
2335 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2336 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002337
mflodmancc3d4422017-08-03 08:27:51 -07002338 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002339}
2340
mflodmancc3d4422017-08-03 08:27:51 -07002341TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002342 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002343 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002344 const int kWidth = 640;
2345 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002346
asaperssonfab67072017-04-04 05:51:49 -07002347 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002348
2349 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002350 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002351
2352 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002353 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002354
sprangc5d62e22017-04-02 23:53:04 -07002355 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002356
asaperssonfab67072017-04-04 05:51:49 -07002357 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002358 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002359 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002360
2361 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002362 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002363
sprangc5d62e22017-04-02 23:53:04 -07002364 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002365
mflodmancc3d4422017-08-03 08:27:51 -07002366 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002367}
2368
mflodmancc3d4422017-08-03 08:27:51 -07002369TEST_F(VideoStreamEncoderTest,
2370 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002371 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002372 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002373 const int kWidth = 640;
2374 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002375
2376 // We expect the n initial frames to get dropped.
2377 int i;
2378 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002379 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002380 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002381 }
2382 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002383 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002384 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002385
2386 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002387 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002388
mflodmancc3d4422017-08-03 08:27:51 -07002389 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002390}
2391
mflodmancc3d4422017-08-03 08:27:51 -07002392TEST_F(VideoStreamEncoderTest,
2393 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002394 const int kWidth = 640;
2395 const int kHeight = 360;
mflodmancc3d4422017-08-03 08:27:51 -07002396 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002397
2398 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002399 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002400 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason2bc68642017-02-07 07:02:22 -08002401
asaperssonfab67072017-04-04 05:51:49 -07002402 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002403 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002404 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002405
mflodmancc3d4422017-08-03 08:27:51 -07002406 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002407}
2408
mflodmancc3d4422017-08-03 08:27:51 -07002409TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002410 const int kWidth = 640;
2411 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002412 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02002413
2414 VideoEncoderConfig video_encoder_config;
2415 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
2416 // Make format different, to force recreation of encoder.
2417 video_encoder_config.video_format.parameters["foo"] = "foo";
2418 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002419 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002420 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002421
kthelgasonb83797b2017-02-14 11:57:25 -08002422 // Force quality scaler reconfiguration by resetting the source.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002423 video_stream_encoder_->SetSource(&video_source_,
2424 webrtc::DegradationPreference::BALANCED);
kthelgasonad9010c2017-02-14 00:46:51 -08002425
asaperssonfab67072017-04-04 05:51:49 -07002426 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002427 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002428 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002429
mflodmancc3d4422017-08-03 08:27:51 -07002430 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002431 fake_encoder_.SetQualityScaling(true);
2432}
2433
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002434TEST_F(VideoStreamEncoderTest, InitialFrameDropActivatesWhenBWEstimateReady) {
2435 webrtc::test::ScopedFieldTrials field_trials(
2436 "WebRTC-InitialFramedrop/Enabled/");
2437 // Reset encoder for field trials to take effect.
2438 ConfigureEncoder(video_encoder_config_.Copy());
2439 const int kTooLowBitrateForFrameSizeBps = 10000;
2440 const int kWidth = 640;
2441 const int kHeight = 360;
2442
2443 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2444 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2445 // Frame should not be dropped.
2446 WaitForEncodedFrame(1);
2447
2448 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
2449 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
2450 // Expect to drop this frame, the wait should time out.
2451 ExpectDroppedFrame();
2452
2453 // Expect the sink_wants to specify a scaled frame.
2454 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
2455 video_stream_encoder_->Stop();
2456}
2457
mflodmancc3d4422017-08-03 08:27:51 -07002458TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002459 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2460 const int kTooSmallWidth = 10;
2461 const int kTooSmallHeight = 10;
mflodmancc3d4422017-08-03 08:27:51 -07002462 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002463
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002464 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002465 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002466 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002467 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002468 VerifyNoLimitation(source.sink_wants());
2469 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2470
2471 // Trigger adapt down, too small frame, expect no change.
2472 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002473 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002474 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002475 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002476 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2477 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2478
mflodmancc3d4422017-08-03 08:27:51 -07002479 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002480}
2481
mflodmancc3d4422017-08-03 08:27:51 -07002482TEST_F(VideoStreamEncoderTest,
2483 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002484 const int kTooSmallWidth = 10;
2485 const int kTooSmallHeight = 10;
2486 const int kFpsLimit = 7;
mflodmancc3d4422017-08-03 08:27:51 -07002487 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002488
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002489 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002490 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002491 video_stream_encoder_->SetSource(&source,
2492 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002493 VerifyNoLimitation(source.sink_wants());
2494 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2495 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2496
2497 // Trigger adapt down, expect limited framerate.
2498 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002499 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002500 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002501 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2502 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2503 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2504 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2505
2506 // Trigger adapt down, too small frame, expect no change.
2507 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002508 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002509 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002510 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2511 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2512 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2513 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2514
mflodmancc3d4422017-08-03 08:27:51 -07002515 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002516}
2517
mflodmancc3d4422017-08-03 08:27:51 -07002518TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002519 fake_encoder_.ForceInitEncodeFailure(true);
mflodmancc3d4422017-08-03 08:27:51 -07002520 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Niels Möllerf1338562018-04-26 09:51:47 +02002521 ResetEncoder("VP8", 2, 1, 1, false);
asapersson02465b82017-04-10 01:12:52 -07002522 const int kFrameWidth = 1280;
2523 const int kFrameHeight = 720;
2524 video_source_.IncomingCapturedFrame(
2525 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002526 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002527 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002528}
2529
sprangb1ca0732017-02-01 08:38:12 -08002530// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002531TEST_F(VideoStreamEncoderTest,
2532 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
2533 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002534
2535 const int kFrameWidth = 1280;
2536 const int kFrameHeight = 720;
2537 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002538 // requested by
2539 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002540 video_source_.set_adaptation_enabled(true);
2541
2542 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002543 CreateFrame(1 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002544 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002545
2546 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002547 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002548 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002549 CreateFrame(2 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002550 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002551
asaperssonfab67072017-04-04 05:51:49 -07002552 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002553 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002554 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002555 CreateFrame(3 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002556 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002557
mflodmancc3d4422017-08-03 08:27:51 -07002558 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002559}
sprangfe627f32017-03-29 08:24:59 -07002560
mflodmancc3d4422017-08-03 08:27:51 -07002561TEST_F(VideoStreamEncoderTest,
2562 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002563 const int kFrameWidth = 1280;
2564 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07002565
mflodmancc3d4422017-08-03 08:27:51 -07002566 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2567 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002568 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002569 video_source_.set_adaptation_enabled(true);
2570
sprang4847ae62017-06-27 07:06:52 -07002571 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002572
2573 video_source_.IncomingCapturedFrame(
2574 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002575 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002576
2577 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002578 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002579
2580 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002581 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002582 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002583 video_source_.IncomingCapturedFrame(
2584 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002585 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002586 }
2587
2588 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002589 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002590 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002591 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002592 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002593 video_source_.IncomingCapturedFrame(
2594 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002595 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002596 ++num_frames_dropped;
2597 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002598 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002599 }
2600 }
2601
sprang4847ae62017-06-27 07:06:52 -07002602 // Add some slack to account for frames dropped by the frame dropper.
2603 const int kErrorMargin = 1;
2604 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002605 kErrorMargin);
2606
2607 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002608 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002609 num_frames_dropped = 0;
Åsa Persson8c1bf952018-09-13 10:42:19 +02002610 for (int i = 0; i <= max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002611 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002612 video_source_.IncomingCapturedFrame(
2613 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002614 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002615 ++num_frames_dropped;
2616 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002617 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002618 }
2619 }
sprang4847ae62017-06-27 07:06:52 -07002620 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002621 kErrorMargin);
2622
2623 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002624 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002625 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002626 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002627 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002628 video_source_.IncomingCapturedFrame(
2629 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002630 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002631 ++num_frames_dropped;
2632 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002633 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002634 }
2635 }
sprang4847ae62017-06-27 07:06:52 -07002636 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002637 kErrorMargin);
2638
2639 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002640 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002641 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002642 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002643 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002644 video_source_.IncomingCapturedFrame(
2645 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002646 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002647 ++num_frames_dropped;
2648 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002649 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002650 }
2651 }
2652 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2653
mflodmancc3d4422017-08-03 08:27:51 -07002654 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002655}
2656
mflodmancc3d4422017-08-03 08:27:51 -07002657TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002658 const int kFramerateFps = 5;
2659 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002660 const int kFrameWidth = 1280;
2661 const int kFrameHeight = 720;
2662
sprang4847ae62017-06-27 07:06:52 -07002663 // Reconfigure encoder with two temporal layers and screensharing, which will
2664 // disable frame dropping and make testing easier.
Niels Möllerf1338562018-04-26 09:51:47 +02002665 ResetEncoder("VP8", 1, 2, 1, true);
sprang4847ae62017-06-27 07:06:52 -07002666
mflodmancc3d4422017-08-03 08:27:51 -07002667 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2668 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002669 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002670 video_source_.set_adaptation_enabled(true);
2671
sprang4847ae62017-06-27 07:06:52 -07002672 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002673
2674 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08002675 rtc::VideoSinkWants last_wants;
2676 do {
2677 last_wants = video_source_.sink_wants();
2678
sprangc5d62e22017-04-02 23:53:04 -07002679 // Insert frames to get a new fps estimate...
2680 for (int j = 0; j < kFramerateFps; ++j) {
2681 video_source_.IncomingCapturedFrame(
2682 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08002683 if (video_source_.last_sent_width()) {
2684 sink_.WaitForEncodedFrame(timestamp_ms);
2685 }
sprangc5d62e22017-04-02 23:53:04 -07002686 timestamp_ms += kFrameIntervalMs;
Yves Gerey665174f2018-06-19 15:03:05 +02002687 fake_clock_.AdvanceTimeMicros(kFrameIntervalMs *
2688 rtc::kNumMicrosecsPerMillisec);
sprangc5d62e22017-04-02 23:53:04 -07002689 }
2690 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002691 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08002692 } while (video_source_.sink_wants().max_framerate_fps <
2693 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07002694
Jonathan Yubc771b72017-12-08 17:04:29 -08002695 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07002696
mflodmancc3d4422017-08-03 08:27:51 -07002697 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002698}
asaperssonf7e294d2017-06-13 23:25:22 -07002699
mflodmancc3d4422017-08-03 08:27:51 -07002700TEST_F(VideoStreamEncoderTest,
2701 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002702 const int kWidth = 1280;
2703 const int kHeight = 720;
2704 const int64_t kFrameIntervalMs = 150;
2705 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002706 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002707
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002708 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002709 AdaptingFrameForwarder source;
2710 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002711 video_stream_encoder_->SetSource(&source,
2712 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002713 timestamp_ms += kFrameIntervalMs;
2714 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002715 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002716 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002717 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2718 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2719 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2720
2721 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002722 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002723 timestamp_ms += kFrameIntervalMs;
2724 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002725 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002726 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2727 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2728 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2729 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2730
2731 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002732 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002733 timestamp_ms += kFrameIntervalMs;
2734 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002735 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002736 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2737 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2738 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2739 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2740
2741 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002742 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002743 timestamp_ms += kFrameIntervalMs;
2744 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002745 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002746 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2747 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2748 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2749 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2750
2751 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002752 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002753 timestamp_ms += kFrameIntervalMs;
2754 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002755 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002756 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2757 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2758 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2759 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2760
2761 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002762 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002763 timestamp_ms += kFrameIntervalMs;
2764 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002765 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002766 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2767 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2768 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2769 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2770
2771 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002772 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002773 timestamp_ms += kFrameIntervalMs;
2774 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002775 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002776 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2777 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2778 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2779 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2780
2781 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002782 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002783 timestamp_ms += kFrameIntervalMs;
2784 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002785 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002786 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2787 rtc::VideoSinkWants last_wants = source.sink_wants();
2788 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2789 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2790 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2791
2792 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002793 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002794 timestamp_ms += kFrameIntervalMs;
2795 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002796 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002797 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2798 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2799 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2800 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2801
2802 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002803 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002804 timestamp_ms += kFrameIntervalMs;
2805 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002806 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002807 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2808 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2809 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2810 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2811
2812 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002813 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002814 timestamp_ms += kFrameIntervalMs;
2815 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002816 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002817 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2818 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2819 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2820 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2821
2822 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002823 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002824 timestamp_ms += kFrameIntervalMs;
2825 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002826 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002827 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2828 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2829 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2830 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2831
2832 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002833 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002834 timestamp_ms += kFrameIntervalMs;
2835 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002836 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002837 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2838 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2839 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2840 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2841
2842 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002843 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002844 timestamp_ms += kFrameIntervalMs;
2845 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002846 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002847 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2848 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2849 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2850 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2851
2852 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002853 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002854 timestamp_ms += kFrameIntervalMs;
2855 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002856 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002857 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2858 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2859 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2860 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2861
2862 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002863 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002864 timestamp_ms += kFrameIntervalMs;
2865 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002866 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002867 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002868 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002869 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2870 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2871 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2872
2873 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002874 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002875 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002876 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2877
mflodmancc3d4422017-08-03 08:27:51 -07002878 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002879}
2880
mflodmancc3d4422017-08-03 08:27:51 -07002881TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07002882 const int kWidth = 1280;
2883 const int kHeight = 720;
2884 const int64_t kFrameIntervalMs = 150;
2885 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002886 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002887
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002888 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002889 AdaptingFrameForwarder source;
2890 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002891 video_stream_encoder_->SetSource(&source,
2892 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002893 timestamp_ms += kFrameIntervalMs;
2894 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002895 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002896 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002897 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2898 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2899 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2900 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2901 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2902 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2903
2904 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002905 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002906 timestamp_ms += kFrameIntervalMs;
2907 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002908 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002909 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2910 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2911 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2912 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2913 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2914 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2915 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2916
2917 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002918 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002919 timestamp_ms += kFrameIntervalMs;
2920 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002921 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002922 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2923 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2924 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2925 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2926 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2927 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2928 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2929
2930 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002931 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002932 timestamp_ms += kFrameIntervalMs;
2933 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002934 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002935 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2936 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2937 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2938 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2939 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2940 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2941 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2942
2943 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002944 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002945 timestamp_ms += kFrameIntervalMs;
2946 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002947 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002948 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2949 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2950 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2951 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2952 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2953 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2954 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2955
2956 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002957 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002958 timestamp_ms += kFrameIntervalMs;
2959 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002960 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002961 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2962 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2963 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2964 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2965 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2966 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2967 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2968
2969 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002970 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002971 timestamp_ms += kFrameIntervalMs;
2972 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002973 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002974 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002975 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002976 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2977 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2978 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2979 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2980 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2981 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2982
2983 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002984 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002985 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002986 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2987 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2988
mflodmancc3d4422017-08-03 08:27:51 -07002989 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002990}
2991
mflodmancc3d4422017-08-03 08:27:51 -07002992TEST_F(VideoStreamEncoderTest,
2993 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07002994 const int kWidth = 640;
2995 const int kHeight = 360;
2996 const int kFpsLimit = 15;
2997 const int64_t kFrameIntervalMs = 150;
2998 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002999 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07003000
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003001 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07003002 AdaptingFrameForwarder source;
3003 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003004 video_stream_encoder_->SetSource(&source,
3005 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07003006 timestamp_ms += kFrameIntervalMs;
3007 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003008 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003009 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003010 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3011 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3012 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3013 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3014 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3015 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3016
3017 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003018 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003019 timestamp_ms += kFrameIntervalMs;
3020 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003021 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003022 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
3023 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3024 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3025 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3026 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3027 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3028 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3029
3030 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003031 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003032 timestamp_ms += kFrameIntervalMs;
3033 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003034 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003035 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
3036 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3037 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3038 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3039 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3040 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3041 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3042
3043 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003044 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003045 timestamp_ms += kFrameIntervalMs;
3046 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003047 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003048 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3049 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3050 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3051 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3052 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3053 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3054 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3055
3056 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003057 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003058 timestamp_ms += kFrameIntervalMs;
3059 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003060 WaitForEncodedFrame(timestamp_ms);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003061 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003062 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3063 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3064 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3065 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3066 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3067 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3068
3069 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003070 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003071 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003072 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3073 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3074
mflodmancc3d4422017-08-03 08:27:51 -07003075 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003076}
3077
mflodmancc3d4422017-08-03 08:27:51 -07003078TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003079 // Simulates simulcast behavior and makes highest stream resolutions divisible
3080 // by 4.
3081 class CroppingVideoStreamFactory
3082 : public VideoEncoderConfig::VideoStreamFactoryInterface {
3083 public:
3084 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
3085 int framerate)
3086 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
3087 EXPECT_GT(num_temporal_layers, 0u);
3088 EXPECT_GT(framerate, 0);
3089 }
3090
3091 private:
3092 std::vector<VideoStream> CreateEncoderStreams(
3093 int width,
3094 int height,
3095 const VideoEncoderConfig& encoder_config) override {
Yves Gerey665174f2018-06-19 15:03:05 +02003096 std::vector<VideoStream> streams = test::CreateVideoStreams(
3097 width - width % 4, height - height % 4, encoder_config);
ilnik6b826ef2017-06-16 06:53:48 -07003098 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +01003099 stream.num_temporal_layers = num_temporal_layers_;
ilnik6b826ef2017-06-16 06:53:48 -07003100 stream.max_framerate = framerate_;
3101 }
3102 return streams;
3103 }
3104
3105 const size_t num_temporal_layers_;
3106 const int framerate_;
3107 };
3108
3109 const int kFrameWidth = 1920;
3110 const int kFrameHeight = 1080;
3111 // 3/4 of 1920.
3112 const int kAdaptedFrameWidth = 1440;
3113 // 3/4 of 1080 rounded down to multiple of 4.
3114 const int kAdaptedFrameHeight = 808;
3115 const int kFramerate = 24;
3116
mflodmancc3d4422017-08-03 08:27:51 -07003117 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003118 // Trigger reconfigure encoder (without resetting the entire instance).
3119 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02003120 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07003121 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3122 video_encoder_config.number_of_streams = 1;
3123 video_encoder_config.video_stream_factory =
3124 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003125 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02003126 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07003127 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003128
3129 video_source_.set_adaptation_enabled(true);
3130
3131 video_source_.IncomingCapturedFrame(
3132 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003133 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003134
3135 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003136 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003137 video_source_.IncomingCapturedFrame(
3138 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003139 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003140
mflodmancc3d4422017-08-03 08:27:51 -07003141 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003142}
3143
mflodmancc3d4422017-08-03 08:27:51 -07003144TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003145 const int kFrameWidth = 1280;
3146 const int kFrameHeight = 720;
3147 const int kLowFps = 2;
3148 const int kHighFps = 30;
3149
mflodmancc3d4422017-08-03 08:27:51 -07003150 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003151
3152 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3153 max_framerate_ = kLowFps;
3154
3155 // Insert 2 seconds of 2fps video.
3156 for (int i = 0; i < kLowFps * 2; ++i) {
3157 video_source_.IncomingCapturedFrame(
3158 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3159 WaitForEncodedFrame(timestamp_ms);
3160 timestamp_ms += 1000 / kLowFps;
3161 }
3162
3163 // Make sure encoder is updated with new target.
mflodmancc3d4422017-08-03 08:27:51 -07003164 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003165 video_source_.IncomingCapturedFrame(
3166 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3167 WaitForEncodedFrame(timestamp_ms);
3168 timestamp_ms += 1000 / kLowFps;
3169
3170 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3171
3172 // Insert 30fps frames for just a little more than the forced update period.
3173 const int kVcmTimerIntervalFrames =
3174 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3175 const int kFrameIntervalMs = 1000 / kHighFps;
3176 max_framerate_ = kHighFps;
3177 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3178 video_source_.IncomingCapturedFrame(
3179 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3180 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3181 // be dropped if the encoder hans't been updated with the new higher target
3182 // framerate yet, causing it to overshoot the target bitrate and then
3183 // suffering the wrath of the media optimizer.
3184 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3185 timestamp_ms += kFrameIntervalMs;
3186 }
3187
3188 // Don expect correct measurement just yet, but it should be higher than
3189 // before.
3190 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3191
mflodmancc3d4422017-08-03 08:27:51 -07003192 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003193}
3194
mflodmancc3d4422017-08-03 08:27:51 -07003195TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003196 const int kFrameWidth = 1280;
3197 const int kFrameHeight = 720;
3198 const int kTargetBitrateBps = 1000000;
3199
3200 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02003201 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
mflodmancc3d4422017-08-03 08:27:51 -07003202 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3203 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003204
3205 // Insert a first video frame, causes another bitrate update.
3206 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3207 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3208 video_source_.IncomingCapturedFrame(
3209 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3210 WaitForEncodedFrame(timestamp_ms);
3211
3212 // Next, simulate video suspension due to pacer queue overrun.
mflodmancc3d4422017-08-03 08:27:51 -07003213 video_stream_encoder_->OnBitrateUpdated(0, 0, 1);
sprang4847ae62017-06-27 07:06:52 -07003214
3215 // Skip ahead until a new periodic parameter update should have occured.
3216 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3217 fake_clock_.AdvanceTimeMicros(
3218 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3219 rtc::kNumMicrosecsPerMillisec);
3220
3221 // Bitrate observer should not be called.
3222 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3223 video_source_.IncomingCapturedFrame(
3224 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3225 ExpectDroppedFrame();
3226
mflodmancc3d4422017-08-03 08:27:51 -07003227 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003228}
ilnik6b826ef2017-06-16 06:53:48 -07003229
Niels Möller4db138e2018-04-19 09:04:13 +02003230TEST_F(VideoStreamEncoderTest,
3231 DefaultCpuAdaptationThresholdsForSoftwareEncoder) {
3232 const int kFrameWidth = 1280;
3233 const int kFrameHeight = 720;
3234 const CpuOveruseOptions default_options;
3235 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3236 video_source_.IncomingCapturedFrame(
3237 CreateFrame(1, kFrameWidth, kFrameHeight));
3238 WaitForEncodedFrame(1);
3239 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3240 .low_encode_usage_threshold_percent,
3241 default_options.low_encode_usage_threshold_percent);
3242 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3243 .high_encode_usage_threshold_percent,
3244 default_options.high_encode_usage_threshold_percent);
3245 video_stream_encoder_->Stop();
3246}
3247
3248TEST_F(VideoStreamEncoderTest,
3249 HigherCpuAdaptationThresholdsForHardwareEncoder) {
3250 const int kFrameWidth = 1280;
3251 const int kFrameHeight = 720;
3252 CpuOveruseOptions hardware_options;
3253 hardware_options.low_encode_usage_threshold_percent = 150;
3254 hardware_options.high_encode_usage_threshold_percent = 200;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +01003255 fake_encoder_.SetIsHardwareAccelerated(true);
Niels Möller4db138e2018-04-19 09:04:13 +02003256
3257 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3258 video_source_.IncomingCapturedFrame(
3259 CreateFrame(1, kFrameWidth, kFrameHeight));
3260 WaitForEncodedFrame(1);
3261 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3262 .low_encode_usage_threshold_percent,
3263 hardware_options.low_encode_usage_threshold_percent);
3264 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3265 .high_encode_usage_threshold_percent,
3266 hardware_options.high_encode_usage_threshold_percent);
3267 video_stream_encoder_->Stop();
3268}
3269
Niels Möller6bb5ab92019-01-11 11:11:10 +01003270TEST_F(VideoStreamEncoderTest, DropsFramesWhenEncoderOvershoots) {
3271 const int kFrameWidth = 320;
3272 const int kFrameHeight = 240;
3273 const int kFps = 30;
3274 const int kTargetBitrateBps = 120000;
3275 const int kNumFramesInRun = kFps * 5; // Runs of five seconds.
3276
3277 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3278
3279 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3280 max_framerate_ = kFps;
3281
3282 // Insert 3 seconds of video, verify number of drops with normal bitrate.
3283 fake_encoder_.SimulateOvershoot(1.0);
3284 int num_dropped = 0;
3285 for (int i = 0; i < kNumFramesInRun; ++i) {
3286 video_source_.IncomingCapturedFrame(
3287 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3288 // Wait up to two frame durations for a frame to arrive.
3289 if (!TimedWaitForEncodedFrame(timestamp_ms, 2 * 1000 / kFps)) {
3290 ++num_dropped;
3291 }
3292 timestamp_ms += 1000 / kFps;
3293 }
3294
3295 // Frame drops should be less than 5%
3296 EXPECT_LT(num_dropped, 5 * kNumFramesInRun / 100);
3297
3298 // Make encoder produce frames at double the expected bitrate during 3 seconds
3299 // of video, verify number of drops. Rate needs to be slightly changed in
3300 // order to force the rate to be reconfigured.
3301 fake_encoder_.SimulateOvershoot(2.0);
3302 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps + 1000, 0, 0);
3303 num_dropped = 0;
3304 for (int i = 0; i < kNumFramesInRun; ++i) {
3305 video_source_.IncomingCapturedFrame(
3306 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3307 // Wait up to two frame durations for a frame to arrive.
3308 if (!TimedWaitForEncodedFrame(timestamp_ms, 2 * 1000 / kFps)) {
3309 ++num_dropped;
3310 }
3311 timestamp_ms += 1000 / kFps;
3312 }
3313
3314 // Frame drops should be more than 40%.
3315 EXPECT_GT(num_dropped, 40 * kNumFramesInRun / 100);
3316
3317 video_stream_encoder_->Stop();
3318}
3319
3320TEST_F(VideoStreamEncoderTest, ConfiguresCorrectFrameRate) {
3321 const int kFrameWidth = 320;
3322 const int kFrameHeight = 240;
3323 const int kActualInputFps = 24;
3324 const int kTargetBitrateBps = 120000;
3325
3326 ASSERT_GT(max_framerate_, kActualInputFps);
3327
3328 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3329 max_framerate_ = kActualInputFps;
3330 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3331
3332 // Insert 3 seconds of video, with an input fps lower than configured max.
3333 for (int i = 0; i < kActualInputFps * 3; ++i) {
3334 video_source_.IncomingCapturedFrame(
3335 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3336 // Wait up to two frame durations for a frame to arrive.
3337 WaitForEncodedFrame(timestamp_ms);
3338 timestamp_ms += 1000 / kActualInputFps;
3339 }
3340
3341 EXPECT_NEAR(kActualInputFps, fake_encoder_.GetLastFramerate(), 1);
3342
3343 video_stream_encoder_->Stop();
3344}
3345
perkj26091b12016-09-01 01:17:40 -07003346} // namespace webrtc