blob: a9f1c4d9befdc8e98dc94bee88516d25f0277f8d [file] [log] [blame]
perkj26091b12016-09-01 01:17:40 -07001/*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Erik Språng4529fbc2018-10-12 10:30:31 +020011#include "video/video_stream_encoder.h"
12
sprangfe627f32017-03-29 08:24:59 -070013#include <algorithm>
perkj803d97f2016-11-01 11:45:46 -070014#include <limits>
Per512ecb32016-09-23 15:52:06 +020015#include <utility>
16
Sebastian Jansson74682c12019-03-01 11:50:20 +010017#include "api/task_queue/global_task_queue_factory.h"
Jiawei Ouc2ebe212018-11-08 10:02:56 -080018#include "api/video/builtin_video_bitrate_allocator_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "api/video/i420_buffer.h"
Erik Språngf93eda12019-01-16 17:10:57 +010020#include "api/video/video_bitrate_allocation.h"
Erik Språng4529fbc2018-10-12 10:30:31 +020021#include "api/video_codecs/vp8_temporal_layers.h"
Elad Aloncde8ab22019-03-20 11:56:20 +010022#include "api/video_codecs/vp8_temporal_layers_factory.h"
Steve Anton10542f22019-01-11 09:11:00 -080023#include "media/base/video_adapter.h"
Sergey Silkin86684962018-03-28 19:32:37 +020024#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
Steve Anton10542f22019-01-11 09:11:00 -080026#include "rtc_base/fake_clock.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020027#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080028#include "rtc_base/ref_counted_object.h"
Erik Språng7ca375c2019-02-06 16:20:17 +010029#include "system_wrappers/include/field_trial.h"
Mirko Bonadei17f48782018-09-28 08:51:10 +020030#include "system_wrappers/include/metrics.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020031#include "system_wrappers/include/sleep.h"
32#include "test/encoder_settings.h"
33#include "test/fake_encoder.h"
Kári Tristan Helgason639602a2018-08-02 10:51:40 +020034#include "test/field_trial.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020035#include "test/frame_generator.h"
36#include "test/gmock.h"
37#include "test/gtest.h"
Niels Möllercbcbc222018-09-28 09:07:24 +020038#include "test/video_encoder_proxy_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020039#include "video/send_statistics_proxy.h"
perkj26091b12016-09-01 01:17:40 -070040
41namespace webrtc {
42
sprangb1ca0732017-02-01 08:38:12 -080043using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080044using ::testing::_;
kthelgason876222f2016-11-29 01:44:11 -080045
perkj803d97f2016-11-01 11:45:46 -070046namespace {
Åsa Persson8c1bf952018-09-13 10:42:19 +020047const int kMinPixelsPerFrame = 320 * 180;
48const int kMinFramerateFps = 2;
49const int kMinBalancedFramerateFps = 7;
50const int64_t kFrameTimeoutMs = 100;
asapersson5f7226f2016-11-25 04:37:00 -080051const size_t kMaxPayloadLength = 1440;
Erik Språngd7329ca2019-02-21 21:19:53 +010052const uint32_t kTargetBitrateBps = 1000000;
53const uint32_t kSimulcastTargetBitrateBps = 3150000;
54const uint32_t kLowTargetBitrateBps = kTargetBitrateBps / 10;
kthelgason2bc68642017-02-07 07:02:22 -080055const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070056const int kDefaultFramerate = 30;
Åsa Persson8c1bf952018-09-13 10:42:19 +020057const int64_t kFrameIntervalMs = rtc::kNumMillisecsPerSec / kDefaultFramerate;
asapersson5f7226f2016-11-25 04:37:00 -080058
perkj803d97f2016-11-01 11:45:46 -070059class TestBuffer : public webrtc::I420Buffer {
60 public:
61 TestBuffer(rtc::Event* event, int width, int height)
62 : I420Buffer(width, height), event_(event) {}
63
64 private:
65 friend class rtc::RefCountedObject<TestBuffer>;
66 ~TestBuffer() override {
67 if (event_)
68 event_->Set();
69 }
70 rtc::Event* const event_;
71};
72
Niels Möller7dc26b72017-12-06 10:27:48 +010073class CpuOveruseDetectorProxy : public OveruseFrameDetector {
74 public:
Niels Möllerd1f7eb62018-03-28 16:40:58 +020075 explicit CpuOveruseDetectorProxy(CpuOveruseMetricsObserver* metrics_observer)
76 : OveruseFrameDetector(metrics_observer),
Niels Möller7dc26b72017-12-06 10:27:48 +010077 last_target_framerate_fps_(-1) {}
78 virtual ~CpuOveruseDetectorProxy() {}
79
80 void OnTargetFramerateUpdated(int framerate_fps) override {
81 rtc::CritScope cs(&lock_);
82 last_target_framerate_fps_ = framerate_fps;
83 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
84 }
85
86 int GetLastTargetFramerate() {
87 rtc::CritScope cs(&lock_);
88 return last_target_framerate_fps_;
89 }
90
Niels Möller4db138e2018-04-19 09:04:13 +020091 CpuOveruseOptions GetOptions() { return options_; }
92
Niels Möller7dc26b72017-12-06 10:27:48 +010093 private:
94 rtc::CriticalSection lock_;
95 int last_target_framerate_fps_ RTC_GUARDED_BY(lock_);
96};
97
mflodmancc3d4422017-08-03 08:27:51 -070098class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -070099 public:
Niels Möller213618e2018-07-24 09:29:58 +0200100 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
101 const VideoStreamEncoderSettings& settings)
Sebastian Jansson572c60f2019-03-04 18:30:41 +0100102 : VideoStreamEncoder(Clock::GetRealTimeClock(),
103 1 /* number_of_cores */,
Yves Gerey665174f2018-06-19 15:03:05 +0200104 stats_proxy,
105 settings,
Yves Gerey665174f2018-06-19 15:03:05 +0200106 std::unique_ptr<OveruseFrameDetector>(
107 overuse_detector_proxy_ =
Sebastian Jansson74682c12019-03-01 11:50:20 +0100108 new CpuOveruseDetectorProxy(stats_proxy)),
109 &GlobalTaskQueueFactory()) {}
perkj803d97f2016-11-01 11:45:46 -0700110
sprangb1ca0732017-02-01 08:38:12 -0800111 void PostTaskAndWait(bool down, AdaptReason reason) {
Niels Möllerc572ff32018-11-07 08:43:50 +0100112 rtc::Event event;
kthelgason876222f2016-11-29 01:44:11 -0800113 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800114 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700115 event.Set();
116 });
perkj070ba852017-02-16 15:46:27 -0800117 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700118 }
119
kthelgason2fc52542017-03-03 00:24:41 -0800120 // This is used as a synchronisation mechanism, to make sure that the
121 // encoder queue is not blocked before we start sending it frames.
122 void WaitUntilTaskQueueIsIdle() {
Niels Möllerc572ff32018-11-07 08:43:50 +0100123 rtc::Event event;
Yves Gerey665174f2018-06-19 15:03:05 +0200124 encoder_queue()->PostTask([&event] { event.Set(); });
kthelgason2fc52542017-03-03 00:24:41 -0800125 ASSERT_TRUE(event.Wait(5000));
126 }
127
sprangb1ca0732017-02-01 08:38:12 -0800128 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800129
sprangb1ca0732017-02-01 08:38:12 -0800130 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800131
sprangb1ca0732017-02-01 08:38:12 -0800132 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800133
sprangb1ca0732017-02-01 08:38:12 -0800134 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700135
Niels Möller7dc26b72017-12-06 10:27:48 +0100136 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700137};
138
asapersson5f7226f2016-11-25 04:37:00 -0800139class VideoStreamFactory
140 : public VideoEncoderConfig::VideoStreamFactoryInterface {
141 public:
sprangfda496a2017-06-15 04:21:07 -0700142 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
143 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800144 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700145 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800146 }
147
148 private:
149 std::vector<VideoStream> CreateEncoderStreams(
150 int width,
151 int height,
152 const VideoEncoderConfig& encoder_config) override {
153 std::vector<VideoStream> streams =
154 test::CreateVideoStreams(width, height, encoder_config);
155 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +0100156 stream.num_temporal_layers = num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700157 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800158 }
159 return streams;
160 }
sprangfda496a2017-06-15 04:21:07 -0700161
asapersson5f7226f2016-11-25 04:37:00 -0800162 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700163 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800164};
165
sprangb1ca0732017-02-01 08:38:12 -0800166class AdaptingFrameForwarder : public test::FrameForwarder {
167 public:
168 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700169 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800170
171 void set_adaptation_enabled(bool enabled) {
172 rtc::CritScope cs(&crit_);
173 adaptation_enabled_ = enabled;
174 }
175
asaperssonfab67072017-04-04 05:51:49 -0700176 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800177 rtc::CritScope cs(&crit_);
178 return adaptation_enabled_;
179 }
180
asapersson09f05612017-05-15 23:40:18 -0700181 rtc::VideoSinkWants last_wants() const {
182 rtc::CritScope cs(&crit_);
183 return last_wants_;
184 }
185
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200186 absl::optional<int> last_sent_width() const { return last_width_; }
187 absl::optional<int> last_sent_height() const { return last_height_; }
Jonathan Yubc771b72017-12-08 17:04:29 -0800188
sprangb1ca0732017-02-01 08:38:12 -0800189 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
190 int cropped_width = 0;
191 int cropped_height = 0;
192 int out_width = 0;
193 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700194 if (adaption_enabled()) {
195 if (adapter_.AdaptFrameResolution(
196 video_frame.width(), video_frame.height(),
197 video_frame.timestamp_us() * 1000, &cropped_width,
198 &cropped_height, &out_width, &out_height)) {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100199 VideoFrame adapted_frame =
200 VideoFrame::Builder()
201 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
202 nullptr, out_width, out_height))
203 .set_timestamp_rtp(99)
204 .set_timestamp_ms(99)
205 .set_rotation(kVideoRotation_0)
206 .build();
sprangc5d62e22017-04-02 23:53:04 -0700207 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
208 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800209 last_width_.emplace(adapted_frame.width());
210 last_height_.emplace(adapted_frame.height());
211 } else {
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200212 last_width_ = absl::nullopt;
213 last_height_ = absl::nullopt;
sprangc5d62e22017-04-02 23:53:04 -0700214 }
sprangb1ca0732017-02-01 08:38:12 -0800215 } else {
216 test::FrameForwarder::IncomingCapturedFrame(video_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800217 last_width_.emplace(video_frame.width());
218 last_height_.emplace(video_frame.height());
sprangb1ca0732017-02-01 08:38:12 -0800219 }
220 }
221
222 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
223 const rtc::VideoSinkWants& wants) override {
224 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700225 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700226 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
227 wants.max_pixel_count,
228 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800229 test::FrameForwarder::AddOrUpdateSink(sink, wants);
230 }
sprangb1ca0732017-02-01 08:38:12 -0800231 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700232 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
233 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200234 absl::optional<int> last_width_;
235 absl::optional<int> last_height_;
sprangb1ca0732017-02-01 08:38:12 -0800236};
sprangc5d62e22017-04-02 23:53:04 -0700237
Niels Möller213618e2018-07-24 09:29:58 +0200238// TODO(nisse): Mock only VideoStreamEncoderObserver.
sprangc5d62e22017-04-02 23:53:04 -0700239class MockableSendStatisticsProxy : public SendStatisticsProxy {
240 public:
241 MockableSendStatisticsProxy(Clock* clock,
242 const VideoSendStream::Config& config,
243 VideoEncoderConfig::ContentType content_type)
244 : SendStatisticsProxy(clock, config, content_type) {}
245
246 VideoSendStream::Stats GetStats() override {
247 rtc::CritScope cs(&lock_);
248 if (mock_stats_)
249 return *mock_stats_;
250 return SendStatisticsProxy::GetStats();
251 }
252
Niels Möller213618e2018-07-24 09:29:58 +0200253 int GetInputFrameRate() const override {
254 rtc::CritScope cs(&lock_);
255 if (mock_stats_)
256 return mock_stats_->input_frame_rate;
257 return SendStatisticsProxy::GetInputFrameRate();
258 }
sprangc5d62e22017-04-02 23:53:04 -0700259 void SetMockStats(const VideoSendStream::Stats& stats) {
260 rtc::CritScope cs(&lock_);
261 mock_stats_.emplace(stats);
262 }
263
264 void ResetMockStats() {
265 rtc::CritScope cs(&lock_);
266 mock_stats_.reset();
267 }
268
269 private:
270 rtc::CriticalSection lock_;
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200271 absl::optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700272};
273
sprang4847ae62017-06-27 07:06:52 -0700274class MockBitrateObserver : public VideoBitrateAllocationObserver {
275 public:
Erik Språng566124a2018-04-23 12:32:22 +0200276 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const VideoBitrateAllocation&));
sprang4847ae62017-06-27 07:06:52 -0700277};
278
perkj803d97f2016-11-01 11:45:46 -0700279} // namespace
280
mflodmancc3d4422017-08-03 08:27:51 -0700281class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700282 public:
283 static const int kDefaultTimeoutMs = 30 * 1000;
284
mflodmancc3d4422017-08-03 08:27:51 -0700285 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700286 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700287 codec_width_(320),
288 codec_height_(240),
Åsa Persson8c1bf952018-09-13 10:42:19 +0200289 max_framerate_(kDefaultFramerate),
perkj26091b12016-09-01 01:17:40 -0700290 fake_encoder_(),
Niels Möller4db138e2018-04-19 09:04:13 +0200291 encoder_factory_(&fake_encoder_),
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800292 bitrate_allocator_factory_(CreateBuiltinVideoBitrateAllocatorFactory()),
sprangc5d62e22017-04-02 23:53:04 -0700293 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700294 Clock::GetRealTimeClock(),
295 video_send_config_,
296 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700297 sink_(&fake_encoder_) {}
298
299 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700300 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700301 video_send_config_ = VideoSendStream::Config(nullptr);
Niels Möller4db138e2018-04-19 09:04:13 +0200302 video_send_config_.encoder_settings.encoder_factory = &encoder_factory_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800303 video_send_config_.encoder_settings.bitrate_allocator_factory =
304 bitrate_allocator_factory_.get();
Niels Möller259a4972018-04-05 15:36:51 +0200305 video_send_config_.rtp.payload_name = "FAKE";
306 video_send_config_.rtp.payload_type = 125;
perkj26091b12016-09-01 01:17:40 -0700307
Per512ecb32016-09-23 15:52:06 +0200308 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200309 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700310 video_encoder_config.video_stream_factory =
311 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100312 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700313
314 // Framerate limit is specified by the VideoStreamFactory.
315 std::vector<VideoStream> streams =
316 video_encoder_config.video_stream_factory->CreateEncoderStreams(
317 codec_width_, codec_height_, video_encoder_config);
318 max_framerate_ = streams[0].max_framerate;
319 fake_clock_.SetTimeMicros(1234);
320
Niels Möllerf1338562018-04-26 09:51:47 +0200321 ConfigureEncoder(std::move(video_encoder_config));
asapersson5f7226f2016-11-25 04:37:00 -0800322 }
323
Niels Möllerf1338562018-04-26 09:51:47 +0200324 void ConfigureEncoder(VideoEncoderConfig video_encoder_config) {
mflodmancc3d4422017-08-03 08:27:51 -0700325 if (video_stream_encoder_)
326 video_stream_encoder_->Stop();
327 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700328 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700329 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
330 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700331 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -0700332 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
333 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200334 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -0700335 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800336 }
337
338 void ResetEncoder(const std::string& payload_name,
339 size_t num_streams,
340 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700341 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700342 bool screenshare) {
Niels Möller259a4972018-04-05 15:36:51 +0200343 video_send_config_.rtp.payload_name = payload_name;
asapersson5f7226f2016-11-25 04:37:00 -0800344
345 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200346 video_encoder_config.codec_type = PayloadStringToCodecType(payload_name);
asapersson5f7226f2016-11-25 04:37:00 -0800347 video_encoder_config.number_of_streams = num_streams;
Erik Språngd7329ca2019-02-21 21:19:53 +0100348 video_encoder_config.max_bitrate_bps =
349 num_streams == 1 ? kTargetBitrateBps : kSimulcastTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800350 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700351 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
352 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700353 video_encoder_config.content_type =
354 screenshare ? VideoEncoderConfig::ContentType::kScreen
355 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700356 if (payload_name == "VP9") {
357 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
358 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
359 video_encoder_config.encoder_specific_settings =
360 new rtc::RefCountedObject<
361 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
362 }
Niels Möllerf1338562018-04-26 09:51:47 +0200363 ConfigureEncoder(std::move(video_encoder_config));
perkj26091b12016-09-01 01:17:40 -0700364 }
365
sprang57c2fff2017-01-16 06:24:02 -0800366 VideoFrame CreateFrame(int64_t ntp_time_ms,
367 rtc::Event* destruction_event) const {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100368 VideoFrame frame =
369 VideoFrame::Builder()
370 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
371 destruction_event, codec_width_, codec_height_))
372 .set_timestamp_rtp(99)
373 .set_timestamp_ms(99)
374 .set_rotation(kVideoRotation_0)
375 .build();
sprang57c2fff2017-01-16 06:24:02 -0800376 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700377 return frame;
378 }
379
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100380 VideoFrame CreateFrameWithUpdatedPixel(int64_t ntp_time_ms,
381 rtc::Event* destruction_event,
382 int offset_x) const {
383 VideoFrame frame =
384 VideoFrame::Builder()
385 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
386 destruction_event, codec_width_, codec_height_))
387 .set_timestamp_rtp(99)
388 .set_timestamp_ms(99)
389 .set_rotation(kVideoRotation_0)
390 .set_update_rect({offset_x, 0, 1, 1})
391 .build();
392 frame.set_ntp_time_ms(ntp_time_ms);
393 return frame;
394 }
395
sprang57c2fff2017-01-16 06:24:02 -0800396 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100397 VideoFrame frame =
398 VideoFrame::Builder()
399 .set_video_frame_buffer(
400 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height))
401 .set_timestamp_rtp(99)
402 .set_timestamp_ms(99)
403 .set_rotation(kVideoRotation_0)
404 .build();
sprang57c2fff2017-01-16 06:24:02 -0800405 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700406 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700407 return frame;
408 }
409
asapersson02465b82017-04-10 01:12:52 -0700410 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700411 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700412 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
413 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700414 }
415
asapersson09f05612017-05-15 23:40:18 -0700416 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
417 const rtc::VideoSinkWants& wants2) {
418 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
419 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
420 }
421
Åsa Persson8c1bf952018-09-13 10:42:19 +0200422 void VerifyFpsMaxResolutionMax(const rtc::VideoSinkWants& wants) {
423 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
424 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
425 EXPECT_FALSE(wants.target_pixel_count);
426 }
427
asapersson09f05612017-05-15 23:40:18 -0700428 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
429 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200430 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700431 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
432 EXPECT_GT(wants1.max_pixel_count, 0);
433 }
434
435 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
436 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200437 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700438 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
439 }
440
asaperssonf7e294d2017-06-13 23:25:22 -0700441 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
442 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200443 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700444 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
445 }
446
447 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
448 const rtc::VideoSinkWants& wants2) {
449 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
450 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
451 }
452
453 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
454 const rtc::VideoSinkWants& wants2) {
455 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
456 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
457 }
458
459 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
460 const rtc::VideoSinkWants& wants2) {
461 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
462 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
463 EXPECT_GT(wants1.max_pixel_count, 0);
464 }
465
466 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
467 const rtc::VideoSinkWants& wants2) {
468 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
469 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
470 }
471
asapersson09f05612017-05-15 23:40:18 -0700472 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
473 int pixel_count) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200474 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700475 EXPECT_LT(wants.max_pixel_count, pixel_count);
476 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700477 }
478
479 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
480 EXPECT_LT(wants.max_framerate_fps, fps);
481 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
482 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700483 }
484
asaperssonf7e294d2017-06-13 23:25:22 -0700485 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
486 int expected_fps) {
487 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
488 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
489 EXPECT_FALSE(wants.target_pixel_count);
490 }
491
Jonathan Yubc771b72017-12-08 17:04:29 -0800492 void VerifyBalancedModeFpsRange(const rtc::VideoSinkWants& wants,
493 int last_frame_pixels) {
494 // Balanced mode should always scale FPS to the desired range before
495 // attempting to scale resolution.
496 int fps_limit = wants.max_framerate_fps;
497 if (last_frame_pixels <= 320 * 240) {
498 EXPECT_TRUE(7 <= fps_limit && fps_limit <= 10);
499 } else if (last_frame_pixels <= 480 * 270) {
500 EXPECT_TRUE(10 <= fps_limit && fps_limit <= 15);
501 } else if (last_frame_pixels <= 640 * 480) {
502 EXPECT_LE(15, fps_limit);
503 } else {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200504 EXPECT_EQ(kDefaultFramerate, fps_limit);
Jonathan Yubc771b72017-12-08 17:04:29 -0800505 }
506 }
507
sprang4847ae62017-06-27 07:06:52 -0700508 void WaitForEncodedFrame(int64_t expected_ntp_time) {
509 sink_.WaitForEncodedFrame(expected_ntp_time);
510 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
511 }
512
513 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
514 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
515 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
516 return ok;
517 }
518
519 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
520 sink_.WaitForEncodedFrame(expected_width, expected_height);
521 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
522 }
523
524 void ExpectDroppedFrame() {
525 sink_.ExpectDroppedFrame();
526 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
527 }
528
529 bool WaitForFrame(int64_t timeout_ms) {
530 bool ok = sink_.WaitForFrame(timeout_ms);
531 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
532 return ok;
533 }
534
perkj26091b12016-09-01 01:17:40 -0700535 class TestEncoder : public test::FakeEncoder {
536 public:
Niels Möllerc572ff32018-11-07 08:43:50 +0100537 TestEncoder() : FakeEncoder(Clock::GetRealTimeClock()) {}
perkj26091b12016-09-01 01:17:40 -0700538
asaperssonfab67072017-04-04 05:51:49 -0700539 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800540 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700541 return config_;
542 }
543
544 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800545 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700546 block_next_encode_ = true;
547 }
548
Erik Språngaed30702018-11-05 12:57:17 +0100549 VideoEncoder::EncoderInfo GetEncoderInfo() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800550 rtc::CritScope lock(&local_crit_sect_);
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100551 EncoderInfo info;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100552 if (initialized_ == EncoderState::kInitialized) {
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100553 if (quality_scaling_) {
554 info.scaling_settings =
555 VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
556 }
557 info.is_hardware_accelerated = is_hardware_accelerated_;
Erik Språngaed30702018-11-05 12:57:17 +0100558 }
559 return info;
kthelgason876222f2016-11-29 01:44:11 -0800560 }
561
Erik Språngb7cb7b52019-02-26 15:52:33 +0100562 int32_t RegisterEncodeCompleteCallback(
563 EncodedImageCallback* callback) override {
564 rtc::CritScope lock(&local_crit_sect_);
565 encoded_image_callback_ = callback;
566 return FakeEncoder::RegisterEncodeCompleteCallback(callback);
567 }
568
perkjfa10b552016-10-02 23:45:26 -0700569 void ContinueEncode() { continue_encode_event_.Set(); }
570
571 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
572 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800573 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700574 EXPECT_EQ(timestamp_, timestamp);
575 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
576 }
577
kthelgason2fc52542017-03-03 00:24:41 -0800578 void SetQualityScaling(bool b) {
579 rtc::CritScope lock(&local_crit_sect_);
580 quality_scaling_ = b;
581 }
kthelgasonad9010c2017-02-14 00:46:51 -0800582
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100583 void SetIsHardwareAccelerated(bool is_hardware_accelerated) {
584 rtc::CritScope lock(&local_crit_sect_);
585 is_hardware_accelerated_ = is_hardware_accelerated;
586 }
587
sprangfe627f32017-03-29 08:24:59 -0700588 void ForceInitEncodeFailure(bool force_failure) {
589 rtc::CritScope lock(&local_crit_sect_);
590 force_init_encode_failed_ = force_failure;
591 }
592
Niels Möller6bb5ab92019-01-11 11:11:10 +0100593 void SimulateOvershoot(double rate_factor) {
594 rtc::CritScope lock(&local_crit_sect_);
595 rate_factor_ = rate_factor;
596 }
597
Erik Språngd7329ca2019-02-21 21:19:53 +0100598 uint32_t GetLastFramerate() const {
Niels Möller6bb5ab92019-01-11 11:11:10 +0100599 rtc::CritScope lock(&local_crit_sect_);
600 return last_framerate_;
601 }
602
Erik Språngd7329ca2019-02-21 21:19:53 +0100603 VideoFrame::UpdateRect GetLastUpdateRect() const {
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100604 rtc::CritScope lock(&local_crit_sect_);
605 return last_update_rect_;
606 }
607
Niels Möller87e2d782019-03-07 10:18:23 +0100608 const std::vector<VideoFrameType>& LastFrameTypes() const {
Erik Språngd7329ca2019-02-21 21:19:53 +0100609 rtc::CritScope lock(&local_crit_sect_);
610 return last_frame_types_;
611 }
612
613 void InjectFrame(const VideoFrame& input_image, bool keyframe) {
Niels Möller87e2d782019-03-07 10:18:23 +0100614 const std::vector<VideoFrameType> frame_type = {
615 keyframe ? kVideoFrameKey : kVideoFrameDelta};
Erik Språngd7329ca2019-02-21 21:19:53 +0100616 {
617 rtc::CritScope lock(&local_crit_sect_);
618 last_frame_types_ = frame_type;
619 }
Niels Möllerb859b322019-03-07 12:40:01 +0100620 FakeEncoder::Encode(input_image, &frame_type);
Erik Språngd7329ca2019-02-21 21:19:53 +0100621 }
622
Erik Språngb7cb7b52019-02-26 15:52:33 +0100623 void InjectEncodedImage(const EncodedImage& image) {
624 rtc::CritScope lock(&local_crit_sect_);
625 encoded_image_callback_->OnEncodedImage(image, nullptr, nullptr);
626 }
627
Erik Språngd7329ca2019-02-21 21:19:53 +0100628 void ExpectNullFrame() {
629 rtc::CritScope lock(&local_crit_sect_);
630 expect_null_frame_ = true;
631 }
632
633 absl::optional<VideoBitrateAllocation> GetAndResetLastBitrateAllocation() {
634 auto allocation = last_bitrate_allocation_;
635 last_bitrate_allocation_.reset();
636 return allocation;
637 }
638
perkjfa10b552016-10-02 23:45:26 -0700639 private:
perkj26091b12016-09-01 01:17:40 -0700640 int32_t Encode(const VideoFrame& input_image,
Niels Möller87e2d782019-03-07 10:18:23 +0100641 const std::vector<VideoFrameType>* frame_types) override {
perkj26091b12016-09-01 01:17:40 -0700642 bool block_encode;
643 {
brandtre78d2662017-01-16 05:57:16 -0800644 rtc::CritScope lock(&local_crit_sect_);
Erik Språngd7329ca2019-02-21 21:19:53 +0100645 if (expect_null_frame_) {
646 EXPECT_EQ(input_image.timestamp(), 0u);
647 EXPECT_EQ(input_image.width(), 1);
648 last_frame_types_ = *frame_types;
649 expect_null_frame_ = false;
650 } else {
651 EXPECT_GT(input_image.timestamp(), timestamp_);
652 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
653 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
654 }
perkj26091b12016-09-01 01:17:40 -0700655
656 timestamp_ = input_image.timestamp();
657 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700658 last_input_width_ = input_image.width();
659 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700660 block_encode = block_next_encode_;
661 block_next_encode_ = false;
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100662 last_update_rect_ = input_image.update_rect();
Erik Språngd7329ca2019-02-21 21:19:53 +0100663 last_frame_types_ = *frame_types;
perkj26091b12016-09-01 01:17:40 -0700664 }
Niels Möllerb859b322019-03-07 12:40:01 +0100665 int32_t result = FakeEncoder::Encode(input_image, frame_types);
perkj26091b12016-09-01 01:17:40 -0700666 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700667 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700668 return result;
669 }
670
sprangfe627f32017-03-29 08:24:59 -0700671 int32_t InitEncode(const VideoCodec* config,
672 int32_t number_of_cores,
673 size_t max_payload_size) override {
674 int res =
675 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
676 rtc::CritScope lock(&local_crit_sect_);
Erik Språngb7cb7b52019-02-26 15:52:33 +0100677 EXPECT_EQ(initialized_, EncoderState::kUninitialized);
Erik Språng82fad3d2018-03-21 09:57:23 +0100678 if (config->codecType == kVideoCodecVP8) {
sprangfe627f32017-03-29 08:24:59 -0700679 // Simulate setting up temporal layers, in order to validate the life
680 // cycle of these objects.
Elad Aloncde8ab22019-03-20 11:56:20 +0100681 Vp8TemporalLayersFactory factory;
682 frame_buffer_controller_ = factory.Create(*config);
sprangfe627f32017-03-29 08:24:59 -0700683 }
Erik Språngb7cb7b52019-02-26 15:52:33 +0100684 if (force_init_encode_failed_) {
685 initialized_ = EncoderState::kInitializationFailed;
sprangfe627f32017-03-29 08:24:59 -0700686 return -1;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100687 }
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100688
Erik Språngb7cb7b52019-02-26 15:52:33 +0100689 initialized_ = EncoderState::kInitialized;
sprangfe627f32017-03-29 08:24:59 -0700690 return res;
691 }
692
Erik Språngb7cb7b52019-02-26 15:52:33 +0100693 int32_t Release() override {
694 rtc::CritScope lock(&local_crit_sect_);
695 EXPECT_NE(initialized_, EncoderState::kUninitialized);
696 initialized_ = EncoderState::kUninitialized;
697 return FakeEncoder::Release();
698 }
699
Niels Möller6bb5ab92019-01-11 11:11:10 +0100700 int32_t SetRateAllocation(const VideoBitrateAllocation& rate_allocation,
701 uint32_t framerate) {
702 rtc::CritScope lock(&local_crit_sect_);
703 VideoBitrateAllocation adjusted_rate_allocation;
704 for (size_t si = 0; si < kMaxSpatialLayers; ++si) {
705 for (size_t ti = 0; ti < kMaxTemporalStreams; ++ti) {
706 if (rate_allocation.HasBitrate(si, ti)) {
707 adjusted_rate_allocation.SetBitrate(
708 si, ti,
709 static_cast<uint32_t>(rate_allocation.GetBitrate(si, ti) *
710 rate_factor_));
711 }
712 }
713 }
714 last_framerate_ = framerate;
Erik Språngd7329ca2019-02-21 21:19:53 +0100715 last_bitrate_allocation_ = rate_allocation;
Niels Möller6bb5ab92019-01-11 11:11:10 +0100716 return FakeEncoder::SetRateAllocation(adjusted_rate_allocation,
717 framerate);
718 }
719
brandtre78d2662017-01-16 05:57:16 -0800720 rtc::CriticalSection local_crit_sect_;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100721 enum class EncoderState {
722 kUninitialized,
723 kInitializationFailed,
724 kInitialized
725 } initialized_ RTC_GUARDED_BY(local_crit_sect_) =
726 EncoderState::kUninitialized;
danilchapa37de392017-09-09 04:17:22 -0700727 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700728 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700729 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
730 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
731 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
732 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
733 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100734 bool is_hardware_accelerated_ RTC_GUARDED_BY(local_crit_sect_) = false;
Elad Aloncde8ab22019-03-20 11:56:20 +0100735 std::unique_ptr<Vp8FrameBufferController> frame_buffer_controller_
danilchapa37de392017-09-09 04:17:22 -0700736 RTC_GUARDED_BY(local_crit_sect_);
737 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
Niels Möller6bb5ab92019-01-11 11:11:10 +0100738 double rate_factor_ RTC_GUARDED_BY(local_crit_sect_) = 1.0;
739 uint32_t last_framerate_ RTC_GUARDED_BY(local_crit_sect_) = 0;
Erik Språngd7329ca2019-02-21 21:19:53 +0100740 absl::optional<VideoBitrateAllocation> last_bitrate_allocation_;
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100741 VideoFrame::UpdateRect last_update_rect_
742 RTC_GUARDED_BY(local_crit_sect_) = {0, 0, 0, 0};
Niels Möller87e2d782019-03-07 10:18:23 +0100743 std::vector<VideoFrameType> last_frame_types_;
Erik Språngd7329ca2019-02-21 21:19:53 +0100744 bool expect_null_frame_ = false;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100745 EncodedImageCallback* encoded_image_callback_
746 RTC_GUARDED_BY(local_crit_sect_) = nullptr;
perkj26091b12016-09-01 01:17:40 -0700747 };
748
mflodmancc3d4422017-08-03 08:27:51 -0700749 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700750 public:
751 explicit TestSink(TestEncoder* test_encoder)
Niels Möllerc572ff32018-11-07 08:43:50 +0100752 : test_encoder_(test_encoder) {}
perkj26091b12016-09-01 01:17:40 -0700753
perkj26091b12016-09-01 01:17:40 -0700754 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700755 EXPECT_TRUE(
756 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
757 }
758
759 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
760 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700761 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700762 if (!encoded_frame_event_.Wait(timeout_ms))
763 return false;
perkj26091b12016-09-01 01:17:40 -0700764 {
765 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800766 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700767 }
768 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700769 return true;
perkj26091b12016-09-01 01:17:40 -0700770 }
771
sprangb1ca0732017-02-01 08:38:12 -0800772 void WaitForEncodedFrame(uint32_t expected_width,
773 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700774 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100775 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700776 }
777
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100778 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700779 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800780 uint32_t width = 0;
781 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800782 {
783 rtc::CritScope lock(&crit_);
784 width = last_width_;
785 height = last_height_;
786 }
787 EXPECT_EQ(expected_height, height);
788 EXPECT_EQ(expected_width, width);
789 }
790
kthelgason2fc52542017-03-03 00:24:41 -0800791 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800792
sprangc5d62e22017-04-02 23:53:04 -0700793 bool WaitForFrame(int64_t timeout_ms) {
794 return encoded_frame_event_.Wait(timeout_ms);
795 }
796
perkj26091b12016-09-01 01:17:40 -0700797 void SetExpectNoFrames() {
798 rtc::CritScope lock(&crit_);
799 expect_frames_ = false;
800 }
801
asaperssonfab67072017-04-04 05:51:49 -0700802 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200803 rtc::CritScope lock(&crit_);
804 return number_of_reconfigurations_;
805 }
806
asaperssonfab67072017-04-04 05:51:49 -0700807 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200808 rtc::CritScope lock(&crit_);
809 return min_transmit_bitrate_bps_;
810 }
811
Erik Språngd7329ca2019-02-21 21:19:53 +0100812 void SetNumExpectedLayers(size_t num_layers) {
813 rtc::CritScope lock(&crit_);
814 num_expected_layers_ = num_layers;
815 }
816
Erik Språngb7cb7b52019-02-26 15:52:33 +0100817 int64_t GetLastCaptureTimeMs() const {
818 rtc::CritScope lock(&crit_);
819 return last_capture_time_ms_;
820 }
821
perkj26091b12016-09-01 01:17:40 -0700822 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700823 Result OnEncodedImage(
824 const EncodedImage& encoded_image,
825 const CodecSpecificInfo* codec_specific_info,
826 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200827 rtc::CritScope lock(&crit_);
828 EXPECT_TRUE(expect_frames_);
Erik Språngd7329ca2019-02-21 21:19:53 +0100829 uint32_t timestamp = encoded_image.Timestamp();
830 if (last_timestamp_ != timestamp) {
831 num_received_layers_ = 1;
832 } else {
833 ++num_received_layers_;
834 }
835 last_timestamp_ = timestamp;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100836 last_capture_time_ms_ = encoded_image.capture_time_ms_;
sprangb1ca0732017-02-01 08:38:12 -0800837 last_width_ = encoded_image._encodedWidth;
838 last_height_ = encoded_image._encodedHeight;
Erik Språngd7329ca2019-02-21 21:19:53 +0100839 if (num_received_layers_ == num_expected_layers_) {
840 encoded_frame_event_.Set();
841 }
sprangb1ca0732017-02-01 08:38:12 -0800842 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200843 }
844
Rasmus Brandtc402dbe2019-02-04 11:09:46 +0100845 void OnEncoderConfigurationChanged(
846 std::vector<VideoStream> streams,
847 VideoEncoderConfig::ContentType content_type,
848 int min_transmit_bitrate_bps) override {
Per512ecb32016-09-23 15:52:06 +0200849 rtc::CriticalSection crit_;
850 ++number_of_reconfigurations_;
851 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
852 }
853
perkj26091b12016-09-01 01:17:40 -0700854 rtc::CriticalSection crit_;
855 TestEncoder* test_encoder_;
856 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800857 uint32_t last_timestamp_ = 0;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100858 int64_t last_capture_time_ms_ = 0;
sprangb1ca0732017-02-01 08:38:12 -0800859 uint32_t last_height_ = 0;
860 uint32_t last_width_ = 0;
Erik Språngd7329ca2019-02-21 21:19:53 +0100861 size_t num_expected_layers_ = 1;
862 size_t num_received_layers_ = 0;
perkj26091b12016-09-01 01:17:40 -0700863 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200864 int number_of_reconfigurations_ = 0;
865 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700866 };
867
868 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100869 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200870 int codec_width_;
871 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700872 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700873 TestEncoder fake_encoder_;
Niels Möllercbcbc222018-09-28 09:07:24 +0200874 test::VideoEncoderProxyFactory encoder_factory_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800875 std::unique_ptr<VideoBitrateAllocatorFactory> bitrate_allocator_factory_;
sprangc5d62e22017-04-02 23:53:04 -0700876 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700877 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800878 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700879 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700880 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700881};
882
mflodmancc3d4422017-08-03 08:27:51 -0700883TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
Erik Språng610c7632019-03-06 15:37:33 +0100884 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
885 DataRate::Zero(), 0, 0);
Niels Möllerc572ff32018-11-07 08:43:50 +0100886 rtc::Event frame_destroyed_event;
perkja49cbd32016-09-16 07:53:41 -0700887 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700888 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700889 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700890 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700891}
892
mflodmancc3d4422017-08-03 08:27:51 -0700893TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700894 // Dropped since no target bitrate has been set.
Niels Möllerc572ff32018-11-07 08:43:50 +0100895 rtc::Event frame_destroyed_event;
Sebastian Janssona3177052018-04-10 13:05:49 +0200896 // The encoder will cache up to one frame for a short duration. Adding two
897 // frames means that the first frame will be dropped and the second frame will
898 // be sent when the encoder is enabled.
perkja49cbd32016-09-16 07:53:41 -0700899 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
Sebastian Janssona3177052018-04-10 13:05:49 +0200900 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkja49cbd32016-09-16 07:53:41 -0700901 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700902
Erik Språng610c7632019-03-06 15:37:33 +0100903 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
904 DataRate::Zero(), 0, 0);
perkj26091b12016-09-01 01:17:40 -0700905
Sebastian Janssona3177052018-04-10 13:05:49 +0200906 // The pending frame should be received.
sprang4847ae62017-06-27 07:06:52 -0700907 WaitForEncodedFrame(2);
Sebastian Janssona3177052018-04-10 13:05:49 +0200908 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
909
910 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700911 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700912}
913
mflodmancc3d4422017-08-03 08:27:51 -0700914TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
Erik Språng610c7632019-03-06 15:37:33 +0100915 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
916 DataRate::Zero(), 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700917 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700918 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700919
Erik Språng610c7632019-03-06 15:37:33 +0100920 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(0), DataRate::Zero(), 0,
921 0);
Sebastian Janssona3177052018-04-10 13:05:49 +0200922 // The encoder will cache up to one frame for a short duration. Adding two
923 // frames means that the first frame will be dropped and the second frame will
924 // be sent when the encoder is resumed.
perkja49cbd32016-09-16 07:53:41 -0700925 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Sebastian Janssona3177052018-04-10 13:05:49 +0200926 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700927
Erik Språng610c7632019-03-06 15:37:33 +0100928 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
929 DataRate::Zero(), 0, 0);
sprang4847ae62017-06-27 07:06:52 -0700930 WaitForEncodedFrame(3);
Sebastian Janssona3177052018-04-10 13:05:49 +0200931 video_source_.IncomingCapturedFrame(CreateFrame(4, nullptr));
932 WaitForEncodedFrame(4);
mflodmancc3d4422017-08-03 08:27:51 -0700933 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700934}
935
mflodmancc3d4422017-08-03 08:27:51 -0700936TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
Erik Språng610c7632019-03-06 15:37:33 +0100937 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
938 DataRate::Zero(), 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700939 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700940 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700941
942 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700943 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700944
perkja49cbd32016-09-16 07:53:41 -0700945 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700946 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700947 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700948}
949
mflodmancc3d4422017-08-03 08:27:51 -0700950TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
Erik Språng610c7632019-03-06 15:37:33 +0100951 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
952 DataRate::Zero(), 0, 0);
perkj26091b12016-09-01 01:17:40 -0700953
perkja49cbd32016-09-16 07:53:41 -0700954 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700955 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700956
mflodmancc3d4422017-08-03 08:27:51 -0700957 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700958 sink_.SetExpectNoFrames();
Niels Möllerc572ff32018-11-07 08:43:50 +0100959 rtc::Event frame_destroyed_event;
perkja49cbd32016-09-16 07:53:41 -0700960 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
961 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700962}
963
mflodmancc3d4422017-08-03 08:27:51 -0700964TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
Erik Språng610c7632019-03-06 15:37:33 +0100965 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
966 DataRate::Zero(), 0, 0);
perkj26091b12016-09-01 01:17:40 -0700967
968 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700969 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700970 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700971 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
972 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700973 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
974 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700975 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700976 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700977
mflodmancc3d4422017-08-03 08:27:51 -0700978 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700979}
980
mflodmancc3d4422017-08-03 08:27:51 -0700981TEST_F(VideoStreamEncoderTest,
982 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
Erik Språng610c7632019-03-06 15:37:33 +0100983 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
984 DataRate::Zero(), 0, 0);
Per21d45d22016-10-30 21:37:57 +0100985 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200986
987 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200988 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700989 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100990 // The encoder will have been configured once when the first frame is
991 // received.
992 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200993
994 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200995 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200996 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -0700997 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200998 kMaxPayloadLength);
Per512ecb32016-09-23 15:52:06 +0200999
1000 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +02001001 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001002 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +01001003 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -07001004 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -07001005
mflodmancc3d4422017-08-03 08:27:51 -07001006 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -07001007}
1008
mflodmancc3d4422017-08-03 08:27:51 -07001009TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
Erik Språng610c7632019-03-06 15:37:33 +01001010 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1011 DataRate::Zero(), 0, 0);
perkjfa10b552016-10-02 23:45:26 -07001012
1013 // Capture a frame and wait for it to synchronize with the encoder thread.
1014 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001015 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +01001016 // The encoder will have been configured once.
1017 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -07001018 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
1019 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
1020
1021 codec_width_ *= 2;
1022 codec_height_ *= 2;
1023 // Capture a frame with a higher resolution and wait for it to synchronize
1024 // with the encoder thread.
1025 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001026 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -07001027 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
1028 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +01001029 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -07001030
mflodmancc3d4422017-08-03 08:27:51 -07001031 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -07001032}
1033
mflodmancc3d4422017-08-03 08:27:51 -07001034TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -07001035 EXPECT_TRUE(video_source_.has_sinks());
1036 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001037 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001038 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001039 EXPECT_FALSE(video_source_.has_sinks());
1040 EXPECT_TRUE(new_video_source.has_sinks());
1041
mflodmancc3d4422017-08-03 08:27:51 -07001042 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001043}
1044
mflodmancc3d4422017-08-03 08:27:51 -07001045TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -07001046 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -07001047 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -07001048 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -07001049 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001050}
1051
Jonathan Yubc771b72017-12-08 17:04:29 -08001052TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
1053 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -07001054 const int kWidth = 1280;
1055 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -08001056
1057 // We rely on the automatic resolution adaptation, but we handle framerate
1058 // adaptation manually by mocking the stats proxy.
1059 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -07001060
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001061 // Enable BALANCED preference, no initial limitation.
Erik Språng610c7632019-03-06 15:37:33 +01001062 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1063 DataRate::Zero(), 0, 0);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001064 video_stream_encoder_->SetSource(&video_source_,
1065 webrtc::DegradationPreference::BALANCED);
Jonathan Yubc771b72017-12-08 17:04:29 -08001066 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001067 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001068 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -07001069 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1070
Jonathan Yubc771b72017-12-08 17:04:29 -08001071 // Adapt down as far as possible.
1072 rtc::VideoSinkWants last_wants;
1073 int64_t t = 1;
1074 int loop_count = 0;
1075 do {
1076 ++loop_count;
1077 last_wants = video_source_.sink_wants();
1078
1079 // Simulate the framerate we've been asked to adapt to.
1080 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
1081 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
1082 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1083 mock_stats.input_frame_rate = fps;
1084 stats_proxy_->SetMockStats(mock_stats);
1085
1086 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1087 sink_.WaitForEncodedFrame(t);
1088 t += frame_interval_ms;
1089
mflodmancc3d4422017-08-03 08:27:51 -07001090 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08001091 VerifyBalancedModeFpsRange(
1092 video_source_.sink_wants(),
1093 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1094 } while (video_source_.sink_wants().max_pixel_count <
1095 last_wants.max_pixel_count ||
1096 video_source_.sink_wants().max_framerate_fps <
1097 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001098
Jonathan Yubc771b72017-12-08 17:04:29 -08001099 // Verify that we've adapted all the way down.
1100 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001101 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001102 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
1103 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -07001104 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -08001105 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
1106 *video_source_.last_sent_height());
1107 EXPECT_EQ(kMinBalancedFramerateFps,
1108 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001109
Jonathan Yubc771b72017-12-08 17:04:29 -08001110 // Adapt back up the same number of times we adapted down.
1111 for (int i = 0; i < loop_count - 1; ++i) {
1112 last_wants = video_source_.sink_wants();
1113
1114 // Simulate the framerate we've been asked to adapt to.
1115 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
1116 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
1117 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1118 mock_stats.input_frame_rate = fps;
1119 stats_proxy_->SetMockStats(mock_stats);
1120
1121 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1122 sink_.WaitForEncodedFrame(t);
1123 t += frame_interval_ms;
1124
mflodmancc3d4422017-08-03 08:27:51 -07001125 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -08001126 VerifyBalancedModeFpsRange(
1127 video_source_.sink_wants(),
1128 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1129 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
1130 last_wants.max_pixel_count ||
1131 video_source_.sink_wants().max_framerate_fps >
1132 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001133 }
1134
Åsa Persson8c1bf952018-09-13 10:42:19 +02001135 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001136 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001137 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001138 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1139 EXPECT_EQ((loop_count - 1) * 2,
1140 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -07001141
mflodmancc3d4422017-08-03 08:27:51 -07001142 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001143}
mflodmancc3d4422017-08-03 08:27:51 -07001144TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
Erik Språng610c7632019-03-06 15:37:33 +01001145 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1146 DataRate::Zero(), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001147 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001148
sprangc5d62e22017-04-02 23:53:04 -07001149 const int kFrameWidth = 1280;
1150 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07001151
Åsa Persson8c1bf952018-09-13 10:42:19 +02001152 int64_t frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -07001153
kthelgason5e13d412016-12-01 03:59:51 -08001154 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001155 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001156 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001157 frame_timestamp += kFrameIntervalMs;
1158
perkj803d97f2016-11-01 11:45:46 -07001159 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001160 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001161 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001162 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001163 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001164 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -07001165
asapersson0944a802017-04-07 00:57:58 -07001166 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -07001167 // wanted resolution.
1168 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
1169 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
1170 kFrameWidth * kFrameHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001171 EXPECT_EQ(kDefaultFramerate, video_source_.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001172
1173 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -07001174 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001175 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001176 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001177
sprangc5d62e22017-04-02 23:53:04 -07001178 // Initially no degradation registered.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001179 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001180
sprangc5d62e22017-04-02 23:53:04 -07001181 // Force an input frame rate to be available, or the adaptation call won't
1182 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -07001183 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -07001184 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -07001185 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -07001186 stats_proxy_->SetMockStats(stats);
1187
mflodmancc3d4422017-08-03 08:27:51 -07001188 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001189 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001190 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001191 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001192 frame_timestamp += kFrameIntervalMs;
1193
1194 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001195 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001196 EXPECT_EQ(std::numeric_limits<int>::max(),
1197 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001198 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001199
asapersson02465b82017-04-10 01:12:52 -07001200 // Turn off degradation completely.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001201 video_stream_encoder_->SetSource(&new_video_source,
1202 webrtc::DegradationPreference::DISABLED);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001203 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001204
mflodmancc3d4422017-08-03 08:27:51 -07001205 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001206 new_video_source.IncomingCapturedFrame(
1207 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001208 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001209 frame_timestamp += kFrameIntervalMs;
1210
1211 // Still no degradation.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001212 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001213
1214 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001215 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001216 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
sprangc5d62e22017-04-02 23:53:04 -07001217 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1218 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001219 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001220 EXPECT_EQ(kDefaultFramerate, new_video_source.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001221
1222 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001223 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001224 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001225 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1226 EXPECT_EQ(std::numeric_limits<int>::max(),
1227 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001228 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001229
mflodmancc3d4422017-08-03 08:27:51 -07001230 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001231}
1232
mflodmancc3d4422017-08-03 08:27:51 -07001233TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
Erik Språng610c7632019-03-06 15:37:33 +01001234 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1235 DataRate::Zero(), 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001236
asaperssonfab67072017-04-04 05:51:49 -07001237 const int kWidth = 1280;
1238 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001239 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001240 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001241 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1242 EXPECT_FALSE(stats.bw_limited_resolution);
1243 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1244
1245 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001246 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001247 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001248 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001249
1250 stats = stats_proxy_->GetStats();
1251 EXPECT_TRUE(stats.bw_limited_resolution);
1252 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1253
1254 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001255 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001256 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001257 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001258
1259 stats = stats_proxy_->GetStats();
1260 EXPECT_FALSE(stats.bw_limited_resolution);
1261 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1262 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1263
mflodmancc3d4422017-08-03 08:27:51 -07001264 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001265}
1266
mflodmancc3d4422017-08-03 08:27:51 -07001267TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
Erik Språng610c7632019-03-06 15:37:33 +01001268 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1269 DataRate::Zero(), 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001270
1271 const int kWidth = 1280;
1272 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001273 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001274 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001275 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1276 EXPECT_FALSE(stats.cpu_limited_resolution);
1277 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1278
1279 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001280 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001281 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001282 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001283
1284 stats = stats_proxy_->GetStats();
1285 EXPECT_TRUE(stats.cpu_limited_resolution);
1286 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1287
1288 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001289 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001290 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001291 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001292
1293 stats = stats_proxy_->GetStats();
1294 EXPECT_FALSE(stats.cpu_limited_resolution);
1295 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001296 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001297
mflodmancc3d4422017-08-03 08:27:51 -07001298 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001299}
1300
mflodmancc3d4422017-08-03 08:27:51 -07001301TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
Erik Språng610c7632019-03-06 15:37:33 +01001302 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1303 DataRate::Zero(), 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001304
asaperssonfab67072017-04-04 05:51:49 -07001305 const int kWidth = 1280;
1306 const int kHeight = 720;
1307 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001308 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001309 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001310 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001311 EXPECT_FALSE(stats.cpu_limited_resolution);
1312 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1313
asaperssonfab67072017-04-04 05:51:49 -07001314 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001315 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001316 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001317 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001318 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001319 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001320 EXPECT_TRUE(stats.cpu_limited_resolution);
1321 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1322
1323 // Set new source with adaptation still enabled.
1324 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001325 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001326 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001327
asaperssonfab67072017-04-04 05:51:49 -07001328 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001329 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001330 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001331 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001332 EXPECT_TRUE(stats.cpu_limited_resolution);
1333 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1334
1335 // Set adaptation disabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001336 video_stream_encoder_->SetSource(&new_video_source,
1337 webrtc::DegradationPreference::DISABLED);
kthelgason876222f2016-11-29 01:44:11 -08001338
asaperssonfab67072017-04-04 05:51:49 -07001339 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001340 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001341 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001342 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001343 EXPECT_FALSE(stats.cpu_limited_resolution);
1344 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1345
1346 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001347 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001348 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001349
asaperssonfab67072017-04-04 05:51:49 -07001350 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001351 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001352 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001353 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001354 EXPECT_TRUE(stats.cpu_limited_resolution);
1355 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1356
asaperssonfab67072017-04-04 05:51:49 -07001357 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001358 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001359 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001360 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001361 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001362 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001363 EXPECT_FALSE(stats.cpu_limited_resolution);
1364 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001365 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001366
mflodmancc3d4422017-08-03 08:27:51 -07001367 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001368}
1369
mflodmancc3d4422017-08-03 08:27:51 -07001370TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
Erik Språng610c7632019-03-06 15:37:33 +01001371 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1372 DataRate::Zero(), 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001373
asaperssonfab67072017-04-04 05:51:49 -07001374 const int kWidth = 1280;
1375 const int kHeight = 720;
1376 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001377 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001378 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001379 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001380 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001381 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001382
1383 // Set new source with adaptation still enabled.
1384 test::FrameForwarder new_video_source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001385 video_stream_encoder_->SetSource(&new_video_source,
1386 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001387
asaperssonfab67072017-04-04 05:51:49 -07001388 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001389 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001390 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001391 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001392 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001393 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001394
asaperssonfab67072017-04-04 05:51:49 -07001395 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001396 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001397 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001398 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001399 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001400 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001401 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001402 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001403
asaperssonfab67072017-04-04 05:51:49 -07001404 // Set new source with adaptation still enabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001405 video_stream_encoder_->SetSource(&new_video_source,
1406 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001407
asaperssonfab67072017-04-04 05:51:49 -07001408 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001409 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001410 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001411 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001412 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001413 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001414
asapersson02465b82017-04-10 01:12:52 -07001415 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001416 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001417 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001418
asaperssonfab67072017-04-04 05:51:49 -07001419 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001420 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001421 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001422 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001423 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001424 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1425 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001426
mflodmancc3d4422017-08-03 08:27:51 -07001427 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001428}
1429
mflodmancc3d4422017-08-03 08:27:51 -07001430TEST_F(VideoStreamEncoderTest,
1431 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
Erik Språng610c7632019-03-06 15:37:33 +01001432 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1433 DataRate::Zero(), 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001434
1435 const int kWidth = 1280;
1436 const int kHeight = 720;
Åsa Persson8c1bf952018-09-13 10:42:19 +02001437 int64_t timestamp_ms = kFrameIntervalMs;
asapersson36e9eb42017-03-31 05:29:12 -07001438 video_source_.set_adaptation_enabled(true);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001439 video_source_.IncomingCapturedFrame(
1440 CreateFrame(timestamp_ms, kWidth, kHeight));
1441 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001442 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1443 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1444 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1445
1446 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001447 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001448 timestamp_ms += kFrameIntervalMs;
1449 video_source_.IncomingCapturedFrame(
1450 CreateFrame(timestamp_ms, kWidth, kHeight));
1451 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001452 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1453 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1454 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1455
1456 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001457 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001458 timestamp_ms += kFrameIntervalMs;
1459 video_source_.IncomingCapturedFrame(
1460 CreateFrame(timestamp_ms, kWidth, kHeight));
1461 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001462 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1463 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1464 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1465
Niels Möller4db138e2018-04-19 09:04:13 +02001466 // Leave source unchanged, but disable quality scaler.
asapersson36e9eb42017-03-31 05:29:12 -07001467 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02001468
1469 VideoEncoderConfig video_encoder_config;
1470 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
1471 // Make format different, to force recreation of encoder.
1472 video_encoder_config.video_format.parameters["foo"] = "foo";
1473 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001474 kMaxPayloadLength);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001475 timestamp_ms += kFrameIntervalMs;
1476 video_source_.IncomingCapturedFrame(
1477 CreateFrame(timestamp_ms, kWidth, kHeight));
1478 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001479 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1480 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1481 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1482
mflodmancc3d4422017-08-03 08:27:51 -07001483 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001484}
1485
mflodmancc3d4422017-08-03 08:27:51 -07001486TEST_F(VideoStreamEncoderTest,
1487 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
Erik Språng610c7632019-03-06 15:37:33 +01001488 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1489 DataRate::Zero(), 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001490
asapersson0944a802017-04-07 00:57:58 -07001491 const int kWidth = 1280;
1492 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001493 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001494
asaperssonfab67072017-04-04 05:51:49 -07001495 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001496 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001497 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001498 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001499 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001500 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1501
asapersson02465b82017-04-10 01:12:52 -07001502 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001503 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001504 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001505 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001506 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001507 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001508 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001509 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1510
1511 // Set new source with adaptation still enabled.
1512 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_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001515
1516 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001517 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001518 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001519 stats = stats_proxy_->GetStats();
1520 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001521 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001522 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1523
sprangc5d62e22017-04-02 23:53:04 -07001524 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001525 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001526 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001527 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001528 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001529 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001530 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001531 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001532 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001533 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001534 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1535
sprangc5d62e22017-04-02 23:53:04 -07001536 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001537 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001538 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1539 mock_stats.input_frame_rate = 30;
1540 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001541 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001542 stats_proxy_->ResetMockStats();
1543
1544 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001545 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001546 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001547
1548 // Framerate now adapted.
1549 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001550 EXPECT_FALSE(stats.cpu_limited_resolution);
1551 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001552 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1553
1554 // Disable CPU adaptation.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001555 video_stream_encoder_->SetSource(&new_video_source,
1556 webrtc::DegradationPreference::DISABLED);
sprangc5d62e22017-04-02 23:53:04 -07001557 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001558 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001559 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001560
1561 stats = stats_proxy_->GetStats();
1562 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001563 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001564 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1565
1566 // Try to trigger overuse. Should not succeed.
1567 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001568 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001569 stats_proxy_->ResetMockStats();
1570
1571 stats = stats_proxy_->GetStats();
1572 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001573 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001574 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1575
1576 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001577 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001578 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssonfab67072017-04-04 05:51:49 -07001579 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001580 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001581 stats = stats_proxy_->GetStats();
1582 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001583 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001584 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001585
1586 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001587 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001588 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001589 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001590 stats = stats_proxy_->GetStats();
1591 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001592 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001593 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1594
1595 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001596 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001597 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001598 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001599 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001600 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001601 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001602 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001603 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001604 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001605 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1606
1607 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001608 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001609 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001610 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001611 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001612 stats = stats_proxy_->GetStats();
1613 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001614 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001615 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001616 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001617
mflodmancc3d4422017-08-03 08:27:51 -07001618 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001619}
1620
mflodmancc3d4422017-08-03 08:27:51 -07001621TEST_F(VideoStreamEncoderTest,
1622 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001623 const int kWidth = 1280;
1624 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001625 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1626 DataRate::Zero(), 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001627
asaperssonfab67072017-04-04 05:51:49 -07001628 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001629 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001630
asaperssonfab67072017-04-04 05:51:49 -07001631 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001632 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001633
asaperssonfab67072017-04-04 05:51:49 -07001634 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001635 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001636
asaperssonfab67072017-04-04 05:51:49 -07001637 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001638 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001639
kthelgason876222f2016-11-29 01:44:11 -08001640 // Expect a scale down.
1641 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001642 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001643
asapersson02465b82017-04-10 01:12:52 -07001644 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001645 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001646 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001647 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001648
asaperssonfab67072017-04-04 05:51:49 -07001649 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001650 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001651 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001652 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001653
asaperssonfab67072017-04-04 05:51:49 -07001654 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001655 EXPECT_EQ(std::numeric_limits<int>::max(),
1656 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001657
asaperssonfab67072017-04-04 05:51:49 -07001658 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001659 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001660 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001661 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001662
asapersson02465b82017-04-10 01:12:52 -07001663 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001664 EXPECT_EQ(std::numeric_limits<int>::max(),
1665 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001666
mflodmancc3d4422017-08-03 08:27:51 -07001667 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001668}
1669
mflodmancc3d4422017-08-03 08:27:51 -07001670TEST_F(VideoStreamEncoderTest,
1671 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001672 const int kWidth = 1280;
1673 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001674 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1675 DataRate::Zero(), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001676
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001677 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001678 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001679 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001680 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001681
1682 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001683 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001684 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001685 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1686 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1687
1688 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001689 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001690 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001691 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1692 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1693 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1694
1695 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001696 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001697 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1698 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1699 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1700
mflodmancc3d4422017-08-03 08:27:51 -07001701 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001702}
1703
mflodmancc3d4422017-08-03 08:27:51 -07001704TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001705 const int kWidth = 1280;
1706 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001707 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1708 DataRate::Zero(), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001709
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001710 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001711 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001712 video_stream_encoder_->SetSource(&source,
1713 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001714 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1715 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001716 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001717
1718 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001719 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001720 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1721 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1722 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1723 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1724
1725 // Trigger adapt down for same input resolution, expect no change.
1726 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1727 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001728 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001729 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1730 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1731 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1732
1733 // Trigger adapt down for larger input resolution, expect no change.
1734 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1735 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001736 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001737 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1738 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1739 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1740
mflodmancc3d4422017-08-03 08:27:51 -07001741 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001742}
1743
mflodmancc3d4422017-08-03 08:27:51 -07001744TEST_F(VideoStreamEncoderTest,
1745 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001746 const int kWidth = 1280;
1747 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001748 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1749 DataRate::Zero(), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001750
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001751 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001752 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001753 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001754 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001755
1756 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001757 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001758 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001759 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1760 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1761
1762 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001763 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001764 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001765 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1766 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1767
mflodmancc3d4422017-08-03 08:27:51 -07001768 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001769}
1770
mflodmancc3d4422017-08-03 08:27:51 -07001771TEST_F(VideoStreamEncoderTest,
1772 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001773 const int kWidth = 1280;
1774 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001775 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1776 DataRate::Zero(), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001777
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001778 // Enable MAINTAIN_RESOLUTION preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001779 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001780 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001781 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
asapersson02465b82017-04-10 01:12:52 -07001782
1783 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001784 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001785 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001786 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001787 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1788
1789 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001790 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001791 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001792 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001793 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1794
mflodmancc3d4422017-08-03 08:27:51 -07001795 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001796}
1797
mflodmancc3d4422017-08-03 08:27:51 -07001798TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001799 const int kWidth = 1280;
1800 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001801 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1802 DataRate::Zero(), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001803
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001804 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001805 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001806 video_stream_encoder_->SetSource(&source,
1807 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001808
1809 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1810 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001811 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001812 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1813 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1814 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1815
1816 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001817 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001818 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001819 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1820 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1821 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1822
mflodmancc3d4422017-08-03 08:27:51 -07001823 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001824}
1825
mflodmancc3d4422017-08-03 08:27:51 -07001826TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001827 const int kWidth = 1280;
1828 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001829 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1830 DataRate::Zero(), 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001831
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001832 // Enable DISABLED preference, no initial limitation.
asapersson09f05612017-05-15 23:40:18 -07001833 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001834 video_stream_encoder_->SetSource(&source,
1835 webrtc::DegradationPreference::DISABLED);
asapersson09f05612017-05-15 23:40:18 -07001836
1837 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1838 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001839 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001840 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1841 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1842 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1843
1844 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001845 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001846 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001847 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1848 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1849 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1850
mflodmancc3d4422017-08-03 08:27:51 -07001851 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001852}
1853
mflodmancc3d4422017-08-03 08:27:51 -07001854TEST_F(VideoStreamEncoderTest,
1855 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001856 const int kWidth = 1280;
1857 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001858 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1859 DataRate::Zero(), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001860
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001861 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001862 AdaptingFrameForwarder source;
1863 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001864 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001865 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001866
1867 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001868 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001869 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001870 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1871 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1872
1873 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001874 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001875 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001876 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001877 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001878 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1879 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1880
1881 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001882 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001883 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001884 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1885 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1886 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1887
mflodmancc3d4422017-08-03 08:27:51 -07001888 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001889}
1890
mflodmancc3d4422017-08-03 08:27:51 -07001891TEST_F(VideoStreamEncoderTest,
1892 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001893 const int kWidth = 1280;
1894 const int kHeight = 720;
1895 const int kInputFps = 30;
Erik Språng610c7632019-03-06 15:37:33 +01001896 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1897 DataRate::Zero(), 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001898
1899 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1900 stats.input_frame_rate = kInputFps;
1901 stats_proxy_->SetMockStats(stats);
1902
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001903 // Expect no scaling to begin with (preference: MAINTAIN_FRAMERATE).
asapersson09f05612017-05-15 23:40:18 -07001904 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1905 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001906 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001907
1908 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001909 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001910 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1911 sink_.WaitForEncodedFrame(2);
1912 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1913
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001914 // Enable MAINTAIN_RESOLUTION preference.
asapersson09f05612017-05-15 23:40:18 -07001915 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001916 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001917 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001918 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001919
1920 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001921 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001922 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1923 sink_.WaitForEncodedFrame(3);
1924 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1925
1926 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001927 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001928 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001929
mflodmancc3d4422017-08-03 08:27:51 -07001930 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001931}
1932
mflodmancc3d4422017-08-03 08:27:51 -07001933TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001934 const int kWidth = 1280;
1935 const int kHeight = 720;
1936 const size_t kNumFrames = 10;
1937
Erik Språng610c7632019-03-06 15:37:33 +01001938 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1939 DataRate::Zero(), 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001940
asaperssond0de2952017-04-21 01:47:31 -07001941 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001942 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001943 video_source_.set_adaptation_enabled(true);
1944
1945 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1946 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1947
1948 int downscales = 0;
1949 for (size_t i = 1; i <= kNumFrames; i++) {
Åsa Persson8c1bf952018-09-13 10:42:19 +02001950 video_source_.IncomingCapturedFrame(
1951 CreateFrame(i * kFrameIntervalMs, kWidth, kHeight));
1952 WaitForEncodedFrame(i * kFrameIntervalMs);
asaperssond0de2952017-04-21 01:47:31 -07001953
asaperssonfab67072017-04-04 05:51:49 -07001954 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001955 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001956 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001957 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001958
1959 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1960 ++downscales;
1961
1962 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1963 EXPECT_EQ(downscales,
1964 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1965 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001966 }
mflodmancc3d4422017-08-03 08:27:51 -07001967 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001968}
1969
mflodmancc3d4422017-08-03 08:27:51 -07001970TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001971 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1972 const int kWidth = 1280;
1973 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001974 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1975 DataRate::Zero(), 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001976
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001977 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001978 AdaptingFrameForwarder source;
1979 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001980 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001981 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001982
Åsa Persson8c1bf952018-09-13 10:42:19 +02001983 int64_t timestamp_ms = kFrameIntervalMs;
1984 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001985 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001986 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001987 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1988 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1989
1990 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001991 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001992 timestamp_ms += kFrameIntervalMs;
1993 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1994 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001995 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001996 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1997 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1998
1999 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002000 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002001 timestamp_ms += kFrameIntervalMs;
2002 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002003 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002004 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002005 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2006 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2007
2008 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002009 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002010 timestamp_ms += kFrameIntervalMs;
2011 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2012 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002013 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002014 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2015 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2016
2017 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002018 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002019 timestamp_ms += kFrameIntervalMs;
2020 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asapersson09f05612017-05-15 23:40:18 -07002021 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002022 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002023 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2024 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2025
mflodmancc3d4422017-08-03 08:27:51 -07002026 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002027}
2028
mflodmancc3d4422017-08-03 08:27:51 -07002029TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07002030 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
2031 const int kWidth = 1280;
2032 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01002033 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2034 DataRate::Zero(), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002035
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002036 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002037 AdaptingFrameForwarder source;
2038 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002039 video_stream_encoder_->SetSource(&source,
2040 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002041
Åsa Persson8c1bf952018-09-13 10:42:19 +02002042 int64_t timestamp_ms = kFrameIntervalMs;
2043 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07002044 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002045 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002046 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2047 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2048
2049 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002050 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002051 timestamp_ms += kFrameIntervalMs;
2052 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2053 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002054 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2055 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2056 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2057
2058 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002059 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002060 timestamp_ms += kFrameIntervalMs;
2061 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07002062 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002063 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002064 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2065 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2066
2067 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002068 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002069 timestamp_ms += kFrameIntervalMs;
2070 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2071 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002072 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2073 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2074 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2075
2076 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002077 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002078 timestamp_ms += kFrameIntervalMs;
2079 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07002080 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002081 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002082 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2083 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2084
mflodmancc3d4422017-08-03 08:27:51 -07002085 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002086}
2087
mflodmancc3d4422017-08-03 08:27:51 -07002088TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002089 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
2090 const int kWidth = 1280;
2091 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01002092 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2093 DataRate::Zero(), 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002094
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002095 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002096 AdaptingFrameForwarder source;
2097 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002098 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002099 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002100
Åsa Persson8c1bf952018-09-13 10:42:19 +02002101 int64_t timestamp_ms = kFrameIntervalMs;
2102 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002103 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002104 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002105 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2106 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2107 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2108 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2109
2110 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002111 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002112 timestamp_ms += kFrameIntervalMs;
2113 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2114 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002115 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002116 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2117 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2118 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2119 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2120
2121 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07002122 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002123 timestamp_ms += kFrameIntervalMs;
2124 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2125 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002126 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002127 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2128 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2129 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2130 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2131
Jonathan Yubc771b72017-12-08 17:04:29 -08002132 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002133 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002134 timestamp_ms += kFrameIntervalMs;
2135 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2136 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002137 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002138 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2139 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002140 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002141 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2142
Jonathan Yubc771b72017-12-08 17:04:29 -08002143 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07002144 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002145 timestamp_ms += kFrameIntervalMs;
2146 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2147 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002148 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002149 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07002150 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2151 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2152 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2153 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2154
Jonathan Yubc771b72017-12-08 17:04:29 -08002155 // Trigger quality adapt down, expect no change (min resolution reached).
2156 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002157 timestamp_ms += kFrameIntervalMs;
2158 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2159 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002160 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
2161 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2162 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2163 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2164 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2165
2166 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002167 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002168 timestamp_ms += kFrameIntervalMs;
2169 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2170 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002171 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002172 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2173 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2174 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2175 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2176
2177 // Trigger cpu adapt up, expect upscaled resolution (640x360).
2178 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002179 timestamp_ms += kFrameIntervalMs;
2180 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2181 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002182 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2183 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2184 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2185 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2186 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2187
2188 // Trigger cpu adapt up, expect upscaled resolution (960x540).
2189 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002190 timestamp_ms += kFrameIntervalMs;
2191 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2192 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002193 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002194 last_wants = source.sink_wants();
2195 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2196 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002197 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002198 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2199
2200 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002201 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002202 timestamp_ms += kFrameIntervalMs;
2203 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2204 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002205 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002206 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2207 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002208 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002209 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2210
2211 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002212 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002213 timestamp_ms += kFrameIntervalMs;
2214 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002215 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002216 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002217 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002218 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2219 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002220 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002221 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002222
mflodmancc3d4422017-08-03 08:27:51 -07002223 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002224}
2225
mflodmancc3d4422017-08-03 08:27:51 -07002226TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002227 const int kWidth = 640;
2228 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002229
Erik Språng610c7632019-03-06 15:37:33 +01002230 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2231 DataRate::Zero(), 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002232
perkj803d97f2016-11-01 11:45:46 -07002233 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002234 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002235 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002236 }
2237
mflodmancc3d4422017-08-03 08:27:51 -07002238 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002239 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002240 video_source_.IncomingCapturedFrame(CreateFrame(
2241 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002242 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002243 }
2244
mflodmancc3d4422017-08-03 08:27:51 -07002245 video_stream_encoder_->Stop();
2246 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002247 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002248
perkj803d97f2016-11-01 11:45:46 -07002249 EXPECT_EQ(1,
2250 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2251 EXPECT_EQ(
2252 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2253}
2254
mflodmancc3d4422017-08-03 08:27:51 -07002255TEST_F(VideoStreamEncoderTest,
2256 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
Erik Språng610c7632019-03-06 15:37:33 +01002257 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2258 DataRate::Zero(), 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002259 const int kWidth = 640;
2260 const int kHeight = 360;
2261
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002262 video_stream_encoder_->SetSource(&video_source_,
2263 webrtc::DegradationPreference::DISABLED);
asaperssonf4e44af2017-04-19 02:01:06 -07002264
2265 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2266 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002267 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002268 }
2269
mflodmancc3d4422017-08-03 08:27:51 -07002270 video_stream_encoder_->Stop();
2271 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002272 stats_proxy_.reset();
2273
2274 EXPECT_EQ(0,
2275 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2276}
2277
mflodmancc3d4422017-08-03 08:27:51 -07002278TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002279 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02002280 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002281
2282 const int kDefaultFps = 30;
Erik Språng566124a2018-04-23 12:32:22 +02002283 const VideoBitrateAllocation expected_bitrate =
sprang57c2fff2017-01-16 06:24:02 -08002284 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002285 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002286
sprang57c2fff2017-01-16 06:24:02 -08002287 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
Niels Möller6bb5ab92019-01-11 11:11:10 +01002288 .Times(1);
Erik Språng610c7632019-03-06 15:37:33 +01002289 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kLowTargetBitrateBps),
2290 DataRate::Zero(), 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002291
sprang57c2fff2017-01-16 06:24:02 -08002292 video_source_.IncomingCapturedFrame(
Erik Språngd7329ca2019-02-21 21:19:53 +01002293 CreateFrame(rtc::TimeMillis(), codec_width_, codec_height_));
2294 WaitForEncodedFrame(rtc::TimeMillis());
2295 absl::optional<VideoBitrateAllocation> bitrate_allocation =
2296 fake_encoder_.GetAndResetLastBitrateAllocation();
2297 // Check that encoder has been updated too, not just allocation observer.
2298 EXPECT_EQ(bitrate_allocation->get_sum_bps(), kLowTargetBitrateBps);
2299 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec / kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002300
2301 // Not called on second frame.
2302 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2303 .Times(0);
2304 video_source_.IncomingCapturedFrame(
Erik Språngd7329ca2019-02-21 21:19:53 +01002305 CreateFrame(rtc::TimeMillis(), codec_width_, codec_height_));
2306 WaitForEncodedFrame(rtc::TimeMillis());
2307 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec / kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002308
2309 // Called after a process interval.
2310 const int64_t kProcessIntervalMs =
2311 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang57c2fff2017-01-16 06:24:02 -08002312 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2313 .Times(1);
Erik Språngd7329ca2019-02-21 21:19:53 +01002314 const int64_t start_time_ms = rtc::TimeMillis();
2315 while (rtc::TimeMillis() - start_time_ms < kProcessIntervalMs) {
2316 video_source_.IncomingCapturedFrame(
2317 CreateFrame(rtc::TimeMillis(), codec_width_, codec_height_));
2318 WaitForEncodedFrame(rtc::TimeMillis());
2319 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec / kDefaultFps);
2320 }
2321
2322 // Since rates are unchanged, encoder should not be reconfigured.
2323 EXPECT_FALSE(fake_encoder_.GetAndResetLastBitrateAllocation().has_value());
sprang57c2fff2017-01-16 06:24:02 -08002324
mflodmancc3d4422017-08-03 08:27:51 -07002325 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002326}
2327
Niels Möller7dc26b72017-12-06 10:27:48 +01002328TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2329 const int kFrameWidth = 1280;
2330 const int kFrameHeight = 720;
2331 const int kFramerate = 24;
2332
Erik Språng610c7632019-03-06 15:37:33 +01002333 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2334 DataRate::Zero(), 0, 0);
Niels Möller7dc26b72017-12-06 10:27:48 +01002335 test::FrameForwarder source;
2336 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002337 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002338
2339 // Insert a single frame, triggering initial configuration.
2340 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2341 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2342
2343 EXPECT_EQ(
2344 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2345 kDefaultFramerate);
2346
2347 // Trigger reconfigure encoder (without resetting the entire instance).
2348 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002349 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002350 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2351 video_encoder_config.number_of_streams = 1;
2352 video_encoder_config.video_stream_factory =
2353 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2354 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002355 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002356 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2357
2358 // Detector should be updated with fps limit from codec config.
2359 EXPECT_EQ(
2360 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2361 kFramerate);
2362
2363 // Trigger overuse, max framerate should be reduced.
2364 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2365 stats.input_frame_rate = kFramerate;
2366 stats_proxy_->SetMockStats(stats);
2367 video_stream_encoder_->TriggerCpuOveruse();
2368 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2369 int adapted_framerate =
2370 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2371 EXPECT_LT(adapted_framerate, kFramerate);
2372
2373 // Trigger underuse, max framerate should go back to codec configured fps.
2374 // Set extra low fps, to make sure it's actually reset, not just incremented.
2375 stats = stats_proxy_->GetStats();
2376 stats.input_frame_rate = adapted_framerate / 2;
2377 stats_proxy_->SetMockStats(stats);
2378 video_stream_encoder_->TriggerCpuNormalUsage();
2379 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2380 EXPECT_EQ(
2381 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2382 kFramerate);
2383
2384 video_stream_encoder_->Stop();
2385}
2386
2387TEST_F(VideoStreamEncoderTest,
2388 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2389 const int kFrameWidth = 1280;
2390 const int kFrameHeight = 720;
2391 const int kLowFramerate = 15;
2392 const int kHighFramerate = 25;
2393
Erik Språng610c7632019-03-06 15:37:33 +01002394 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2395 DataRate::Zero(), 0, 0);
Niels Möller7dc26b72017-12-06 10:27:48 +01002396 test::FrameForwarder source;
2397 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002398 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002399
2400 // Trigger initial configuration.
2401 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002402 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002403 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2404 video_encoder_config.number_of_streams = 1;
2405 video_encoder_config.video_stream_factory =
2406 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2407 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2408 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002409 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002410 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2411
2412 EXPECT_EQ(
2413 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2414 kLowFramerate);
2415
2416 // Trigger overuse, max framerate should be reduced.
2417 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2418 stats.input_frame_rate = kLowFramerate;
2419 stats_proxy_->SetMockStats(stats);
2420 video_stream_encoder_->TriggerCpuOveruse();
2421 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2422 int adapted_framerate =
2423 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2424 EXPECT_LT(adapted_framerate, kLowFramerate);
2425
2426 // Reconfigure the encoder with a new (higher max framerate), max fps should
2427 // still respect the adaptation.
2428 video_encoder_config.video_stream_factory =
2429 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2430 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2431 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002432 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002433 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2434
2435 EXPECT_EQ(
2436 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2437 adapted_framerate);
2438
2439 // Trigger underuse, max framerate should go back to codec configured fps.
2440 stats = stats_proxy_->GetStats();
2441 stats.input_frame_rate = adapted_framerate;
2442 stats_proxy_->SetMockStats(stats);
2443 video_stream_encoder_->TriggerCpuNormalUsage();
2444 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2445 EXPECT_EQ(
2446 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2447 kHighFramerate);
2448
2449 video_stream_encoder_->Stop();
2450}
2451
mflodmancc3d4422017-08-03 08:27:51 -07002452TEST_F(VideoStreamEncoderTest,
2453 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002454 const int kFrameWidth = 1280;
2455 const int kFrameHeight = 720;
2456 const int kFramerate = 24;
2457
Erik Språng610c7632019-03-06 15:37:33 +01002458 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2459 DataRate::Zero(), 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002460 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002461 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002462 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangfda496a2017-06-15 04:21:07 -07002463
2464 // Trigger initial configuration.
2465 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002466 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002467 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2468 video_encoder_config.number_of_streams = 1;
2469 video_encoder_config.video_stream_factory =
2470 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2471 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002472 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002473 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002474 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002475
Niels Möller7dc26b72017-12-06 10:27:48 +01002476 EXPECT_EQ(
2477 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2478 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002479
2480 // Trigger overuse, max framerate should be reduced.
2481 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2482 stats.input_frame_rate = kFramerate;
2483 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002484 video_stream_encoder_->TriggerCpuOveruse();
2485 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002486 int adapted_framerate =
2487 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002488 EXPECT_LT(adapted_framerate, kFramerate);
2489
2490 // Change degradation preference to not enable framerate scaling. Target
2491 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002492 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002493 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -07002494 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002495 EXPECT_EQ(
2496 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2497 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002498
mflodmancc3d4422017-08-03 08:27:51 -07002499 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002500}
2501
mflodmancc3d4422017-08-03 08:27:51 -07002502TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002503 const int kTooLowBitrateForFrameSizeBps = 10000;
Erik Språng610c7632019-03-06 15:37:33 +01002504 video_stream_encoder_->OnBitrateUpdated(
2505 DataRate::bps(kTooLowBitrateForFrameSizeBps), DataRate::Zero(), 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002506 const int kWidth = 640;
2507 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002508
asaperssonfab67072017-04-04 05:51:49 -07002509 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002510
2511 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002512 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002513
2514 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002515 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002516
sprangc5d62e22017-04-02 23:53:04 -07002517 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002518
asaperssonfab67072017-04-04 05:51:49 -07002519 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002520 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002521 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002522
2523 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002524 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002525
sprangc5d62e22017-04-02 23:53:04 -07002526 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002527
mflodmancc3d4422017-08-03 08:27:51 -07002528 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002529}
2530
mflodmancc3d4422017-08-03 08:27:51 -07002531TEST_F(VideoStreamEncoderTest,
2532 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002533 const int kTooLowBitrateForFrameSizeBps = 10000;
Erik Språng610c7632019-03-06 15:37:33 +01002534 video_stream_encoder_->OnBitrateUpdated(
2535 DataRate::bps(kTooLowBitrateForFrameSizeBps), DataRate::Zero(), 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002536 const int kWidth = 640;
2537 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002538
2539 // We expect the n initial frames to get dropped.
2540 int i;
2541 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002542 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002543 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002544 }
2545 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002546 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002547 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002548
2549 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002550 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002551
mflodmancc3d4422017-08-03 08:27:51 -07002552 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002553}
2554
mflodmancc3d4422017-08-03 08:27:51 -07002555TEST_F(VideoStreamEncoderTest,
2556 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002557 const int kWidth = 640;
2558 const int kHeight = 360;
Erik Språng610c7632019-03-06 15:37:33 +01002559 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kLowTargetBitrateBps),
2560 DataRate::Zero(), 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002561
2562 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002563 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002564 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason2bc68642017-02-07 07:02:22 -08002565
asaperssonfab67072017-04-04 05:51:49 -07002566 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002567 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002568 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002569
mflodmancc3d4422017-08-03 08:27:51 -07002570 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002571}
2572
mflodmancc3d4422017-08-03 08:27:51 -07002573TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002574 const int kWidth = 640;
2575 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002576 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02002577
2578 VideoEncoderConfig video_encoder_config;
2579 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
2580 // Make format different, to force recreation of encoder.
2581 video_encoder_config.video_format.parameters["foo"] = "foo";
2582 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002583 kMaxPayloadLength);
Erik Språng610c7632019-03-06 15:37:33 +01002584 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kLowTargetBitrateBps),
2585 DataRate::Zero(), 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002586
kthelgasonb83797b2017-02-14 11:57:25 -08002587 // Force quality scaler reconfiguration by resetting the source.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002588 video_stream_encoder_->SetSource(&video_source_,
2589 webrtc::DegradationPreference::BALANCED);
kthelgasonad9010c2017-02-14 00:46:51 -08002590
asaperssonfab67072017-04-04 05:51:49 -07002591 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002592 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002593 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002594
mflodmancc3d4422017-08-03 08:27:51 -07002595 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002596 fake_encoder_.SetQualityScaling(true);
2597}
2598
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002599TEST_F(VideoStreamEncoderTest, InitialFrameDropActivatesWhenBWEstimateReady) {
2600 webrtc::test::ScopedFieldTrials field_trials(
2601 "WebRTC-InitialFramedrop/Enabled/");
2602 // Reset encoder for field trials to take effect.
2603 ConfigureEncoder(video_encoder_config_.Copy());
2604 const int kTooLowBitrateForFrameSizeBps = 10000;
2605 const int kWidth = 640;
2606 const int kHeight = 360;
2607
Erik Språng610c7632019-03-06 15:37:33 +01002608 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2609 DataRate::Zero(), 0, 0);
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002610 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2611 // Frame should not be dropped.
2612 WaitForEncodedFrame(1);
2613
Erik Språng610c7632019-03-06 15:37:33 +01002614 video_stream_encoder_->OnBitrateUpdated(
2615 DataRate::bps(kTooLowBitrateForFrameSizeBps), DataRate::Zero(), 0, 0);
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002616 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
2617 // Expect to drop this frame, the wait should time out.
2618 ExpectDroppedFrame();
2619
2620 // Expect the sink_wants to specify a scaled frame.
2621 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
2622 video_stream_encoder_->Stop();
2623}
2624
mflodmancc3d4422017-08-03 08:27:51 -07002625TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002626 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2627 const int kTooSmallWidth = 10;
2628 const int kTooSmallHeight = 10;
Erik Språng610c7632019-03-06 15:37:33 +01002629 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2630 DataRate::Zero(), 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002631
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002632 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002633 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002634 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002635 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002636 VerifyNoLimitation(source.sink_wants());
2637 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2638
2639 // Trigger adapt down, too small frame, expect no change.
2640 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002641 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002642 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002643 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002644 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2645 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2646
mflodmancc3d4422017-08-03 08:27:51 -07002647 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002648}
2649
mflodmancc3d4422017-08-03 08:27:51 -07002650TEST_F(VideoStreamEncoderTest,
2651 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002652 const int kTooSmallWidth = 10;
2653 const int kTooSmallHeight = 10;
2654 const int kFpsLimit = 7;
Erik Språng610c7632019-03-06 15:37:33 +01002655 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2656 DataRate::Zero(), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002657
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002658 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002659 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002660 video_stream_encoder_->SetSource(&source,
2661 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002662 VerifyNoLimitation(source.sink_wants());
2663 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2664 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2665
2666 // Trigger adapt down, expect limited framerate.
2667 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002668 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002669 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002670 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2671 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2672 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2673 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2674
2675 // Trigger adapt down, too small frame, expect no change.
2676 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002677 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002678 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002679 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2680 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2681 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2682 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2683
mflodmancc3d4422017-08-03 08:27:51 -07002684 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002685}
2686
mflodmancc3d4422017-08-03 08:27:51 -07002687TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002688 fake_encoder_.ForceInitEncodeFailure(true);
Erik Språng610c7632019-03-06 15:37:33 +01002689 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2690 DataRate::Zero(), 0, 0);
Niels Möllerf1338562018-04-26 09:51:47 +02002691 ResetEncoder("VP8", 2, 1, 1, false);
asapersson02465b82017-04-10 01:12:52 -07002692 const int kFrameWidth = 1280;
2693 const int kFrameHeight = 720;
2694 video_source_.IncomingCapturedFrame(
2695 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002696 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002697 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002698}
2699
sprangb1ca0732017-02-01 08:38:12 -08002700// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002701TEST_F(VideoStreamEncoderTest,
2702 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
Erik Språng610c7632019-03-06 15:37:33 +01002703 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2704 DataRate::Zero(), 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002705
2706 const int kFrameWidth = 1280;
2707 const int kFrameHeight = 720;
2708 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002709 // requested by
2710 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002711 video_source_.set_adaptation_enabled(true);
2712
2713 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002714 CreateFrame(1 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002715 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002716
2717 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002718 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002719 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002720 CreateFrame(2 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002721 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002722
asaperssonfab67072017-04-04 05:51:49 -07002723 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002724 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002725 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002726 CreateFrame(3 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002727 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002728
mflodmancc3d4422017-08-03 08:27:51 -07002729 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002730}
sprangfe627f32017-03-29 08:24:59 -07002731
mflodmancc3d4422017-08-03 08:27:51 -07002732TEST_F(VideoStreamEncoderTest,
2733 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002734 const int kFrameWidth = 1280;
2735 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07002736
Erik Språng610c7632019-03-06 15:37:33 +01002737 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2738 DataRate::Zero(), 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -07002739 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002740 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002741 video_source_.set_adaptation_enabled(true);
2742
sprang4847ae62017-06-27 07:06:52 -07002743 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002744
2745 video_source_.IncomingCapturedFrame(
2746 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002747 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002748
2749 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002750 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002751
2752 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002753 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002754 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002755 video_source_.IncomingCapturedFrame(
2756 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002757 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002758 }
2759
2760 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002761 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002762 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002763 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002764 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002765 video_source_.IncomingCapturedFrame(
2766 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002767 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002768 ++num_frames_dropped;
2769 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002770 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002771 }
2772 }
2773
sprang4847ae62017-06-27 07:06:52 -07002774 // Add some slack to account for frames dropped by the frame dropper.
2775 const int kErrorMargin = 1;
2776 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002777 kErrorMargin);
2778
2779 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002780 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002781 num_frames_dropped = 0;
Åsa Persson8c1bf952018-09-13 10:42:19 +02002782 for (int i = 0; i <= max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002783 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002784 video_source_.IncomingCapturedFrame(
2785 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002786 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002787 ++num_frames_dropped;
2788 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002789 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002790 }
2791 }
sprang4847ae62017-06-27 07:06:52 -07002792 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002793 kErrorMargin);
2794
2795 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002796 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002797 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002798 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002799 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002800 video_source_.IncomingCapturedFrame(
2801 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002802 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002803 ++num_frames_dropped;
2804 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002805 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002806 }
2807 }
sprang4847ae62017-06-27 07:06:52 -07002808 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002809 kErrorMargin);
2810
2811 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002812 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002813 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002814 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002815 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002816 video_source_.IncomingCapturedFrame(
2817 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002818 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002819 ++num_frames_dropped;
2820 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002821 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002822 }
2823 }
2824 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2825
mflodmancc3d4422017-08-03 08:27:51 -07002826 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002827}
2828
mflodmancc3d4422017-08-03 08:27:51 -07002829TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002830 const int kFramerateFps = 5;
2831 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002832 const int kFrameWidth = 1280;
2833 const int kFrameHeight = 720;
2834
sprang4847ae62017-06-27 07:06:52 -07002835 // Reconfigure encoder with two temporal layers and screensharing, which will
2836 // disable frame dropping and make testing easier.
Niels Möllerf1338562018-04-26 09:51:47 +02002837 ResetEncoder("VP8", 1, 2, 1, true);
sprang4847ae62017-06-27 07:06:52 -07002838
Erik Språng610c7632019-03-06 15:37:33 +01002839 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2840 DataRate::Zero(), 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -07002841 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002842 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002843 video_source_.set_adaptation_enabled(true);
2844
sprang4847ae62017-06-27 07:06:52 -07002845 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002846
2847 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08002848 rtc::VideoSinkWants last_wants;
2849 do {
2850 last_wants = video_source_.sink_wants();
2851
sprangc5d62e22017-04-02 23:53:04 -07002852 // Insert frames to get a new fps estimate...
2853 for (int j = 0; j < kFramerateFps; ++j) {
2854 video_source_.IncomingCapturedFrame(
2855 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08002856 if (video_source_.last_sent_width()) {
2857 sink_.WaitForEncodedFrame(timestamp_ms);
2858 }
sprangc5d62e22017-04-02 23:53:04 -07002859 timestamp_ms += kFrameIntervalMs;
Yves Gerey665174f2018-06-19 15:03:05 +02002860 fake_clock_.AdvanceTimeMicros(kFrameIntervalMs *
2861 rtc::kNumMicrosecsPerMillisec);
sprangc5d62e22017-04-02 23:53:04 -07002862 }
2863 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002864 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08002865 } while (video_source_.sink_wants().max_framerate_fps <
2866 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07002867
Jonathan Yubc771b72017-12-08 17:04:29 -08002868 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07002869
mflodmancc3d4422017-08-03 08:27:51 -07002870 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002871}
asaperssonf7e294d2017-06-13 23:25:22 -07002872
mflodmancc3d4422017-08-03 08:27:51 -07002873TEST_F(VideoStreamEncoderTest,
2874 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002875 const int kWidth = 1280;
2876 const int kHeight = 720;
2877 const int64_t kFrameIntervalMs = 150;
2878 int64_t timestamp_ms = kFrameIntervalMs;
Erik Språng610c7632019-03-06 15:37:33 +01002879 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2880 DataRate::Zero(), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002881
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002882 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002883 AdaptingFrameForwarder source;
2884 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002885 video_stream_encoder_->SetSource(&source,
2886 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002887 timestamp_ms += kFrameIntervalMs;
2888 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002889 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002890 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002891 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2892 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2893 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2894
2895 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002896 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002897 timestamp_ms += kFrameIntervalMs;
2898 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002899 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002900 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2901 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2902 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2903 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2904
2905 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002906 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002907 timestamp_ms += kFrameIntervalMs;
2908 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002909 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002910 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2911 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2912 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2913 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2914
2915 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002916 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002917 timestamp_ms += kFrameIntervalMs;
2918 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002919 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002920 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2921 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2922 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2923 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2924
2925 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002926 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002927 timestamp_ms += kFrameIntervalMs;
2928 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002929 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002930 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2931 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2932 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2933 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2934
2935 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002936 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002937 timestamp_ms += kFrameIntervalMs;
2938 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002939 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002940 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2941 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2942 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2943 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2944
2945 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002946 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002947 timestamp_ms += kFrameIntervalMs;
2948 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002949 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002950 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2951 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2952 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2953 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2954
2955 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002956 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002957 timestamp_ms += kFrameIntervalMs;
2958 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002959 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002960 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2961 rtc::VideoSinkWants last_wants = source.sink_wants();
2962 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2963 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2964 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2965
2966 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002967 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002968 timestamp_ms += kFrameIntervalMs;
2969 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002970 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002971 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2972 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2973 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2974 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2975
2976 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002977 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002978 timestamp_ms += kFrameIntervalMs;
2979 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002980 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002981 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2982 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2983 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2984 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2985
2986 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002987 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002988 timestamp_ms += kFrameIntervalMs;
2989 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002990 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002991 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2992 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2993 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2994 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2995
2996 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002997 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002998 timestamp_ms += kFrameIntervalMs;
2999 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003000 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003001 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
3002 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3003 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3004 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3005
3006 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003007 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003008 timestamp_ms += kFrameIntervalMs;
3009 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003010 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003011 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3012 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3013 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3014 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3015
3016 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003017 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003018 timestamp_ms += kFrameIntervalMs;
3019 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003020 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003021 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
3022 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3023 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3024 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3025
3026 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003027 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003028 timestamp_ms += kFrameIntervalMs;
3029 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003030 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003031 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3032 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3033 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3034 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3035
3036 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003037 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003038 timestamp_ms += kFrameIntervalMs;
3039 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003040 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003041 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02003042 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003043 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3044 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3045 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3046
3047 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003048 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003049 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003050 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3051
mflodmancc3d4422017-08-03 08:27:51 -07003052 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003053}
3054
mflodmancc3d4422017-08-03 08:27:51 -07003055TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07003056 const int kWidth = 1280;
3057 const int kHeight = 720;
3058 const int64_t kFrameIntervalMs = 150;
3059 int64_t timestamp_ms = kFrameIntervalMs;
Erik Språng610c7632019-03-06 15:37:33 +01003060 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3061 DataRate::Zero(), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07003062
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003063 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07003064 AdaptingFrameForwarder source;
3065 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003066 video_stream_encoder_->SetSource(&source,
3067 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07003068 timestamp_ms += kFrameIntervalMs;
3069 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003070 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003071 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003072 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3073 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3074 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3075 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3076 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3077 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3078
3079 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003080 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003081 timestamp_ms += kFrameIntervalMs;
3082 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003083 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003084 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
3085 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3086 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3087 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3088 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3089 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3090 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3091
3092 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003093 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003094 timestamp_ms += kFrameIntervalMs;
3095 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003096 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003097 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
3098 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3099 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3100 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3101 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3102 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3103 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3104
3105 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003106 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003107 timestamp_ms += kFrameIntervalMs;
3108 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003109 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003110 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
3111 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3112 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3113 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3114 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3115 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3116 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3117
3118 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003119 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003120 timestamp_ms += kFrameIntervalMs;
3121 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003122 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003123 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
3124 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3125 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3126 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3127 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3128 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3129 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3130
3131 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003132 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003133 timestamp_ms += kFrameIntervalMs;
3134 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003135 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003136 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3137 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3138 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3139 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3140 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3141 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3142 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3143
3144 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003145 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003146 timestamp_ms += kFrameIntervalMs;
3147 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003148 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003149 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02003150 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003151 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3152 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3153 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3154 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3155 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3156 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3157
3158 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003159 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003160 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003161 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3162 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3163
mflodmancc3d4422017-08-03 08:27:51 -07003164 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003165}
3166
mflodmancc3d4422017-08-03 08:27:51 -07003167TEST_F(VideoStreamEncoderTest,
3168 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07003169 const int kWidth = 640;
3170 const int kHeight = 360;
3171 const int kFpsLimit = 15;
3172 const int64_t kFrameIntervalMs = 150;
3173 int64_t timestamp_ms = kFrameIntervalMs;
Erik Språng610c7632019-03-06 15:37:33 +01003174 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3175 DataRate::Zero(), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07003176
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003177 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07003178 AdaptingFrameForwarder source;
3179 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003180 video_stream_encoder_->SetSource(&source,
3181 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07003182 timestamp_ms += kFrameIntervalMs;
3183 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003184 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003185 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003186 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3187 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3188 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3189 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3190 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3191 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3192
3193 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003194 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003195 timestamp_ms += kFrameIntervalMs;
3196 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003197 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003198 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
3199 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3200 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3201 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3202 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3203 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3204 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3205
3206 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003207 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003208 timestamp_ms += kFrameIntervalMs;
3209 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003210 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003211 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
3212 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3213 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3214 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3215 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3216 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3217 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3218
3219 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003220 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003221 timestamp_ms += kFrameIntervalMs;
3222 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003223 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003224 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3225 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3226 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3227 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3228 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3229 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3230 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3231
3232 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003233 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003234 timestamp_ms += kFrameIntervalMs;
3235 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003236 WaitForEncodedFrame(timestamp_ms);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003237 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003238 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3239 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3240 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3241 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3242 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3243 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3244
3245 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003246 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003247 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003248 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3249 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3250
mflodmancc3d4422017-08-03 08:27:51 -07003251 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003252}
3253
mflodmancc3d4422017-08-03 08:27:51 -07003254TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003255 // Simulates simulcast behavior and makes highest stream resolutions divisible
3256 // by 4.
3257 class CroppingVideoStreamFactory
3258 : public VideoEncoderConfig::VideoStreamFactoryInterface {
3259 public:
3260 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
3261 int framerate)
3262 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
3263 EXPECT_GT(num_temporal_layers, 0u);
3264 EXPECT_GT(framerate, 0);
3265 }
3266
3267 private:
3268 std::vector<VideoStream> CreateEncoderStreams(
3269 int width,
3270 int height,
3271 const VideoEncoderConfig& encoder_config) override {
Yves Gerey665174f2018-06-19 15:03:05 +02003272 std::vector<VideoStream> streams = test::CreateVideoStreams(
3273 width - width % 4, height - height % 4, encoder_config);
ilnik6b826ef2017-06-16 06:53:48 -07003274 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +01003275 stream.num_temporal_layers = num_temporal_layers_;
ilnik6b826ef2017-06-16 06:53:48 -07003276 stream.max_framerate = framerate_;
3277 }
3278 return streams;
3279 }
3280
3281 const size_t num_temporal_layers_;
3282 const int framerate_;
3283 };
3284
3285 const int kFrameWidth = 1920;
3286 const int kFrameHeight = 1080;
3287 // 3/4 of 1920.
3288 const int kAdaptedFrameWidth = 1440;
3289 // 3/4 of 1080 rounded down to multiple of 4.
3290 const int kAdaptedFrameHeight = 808;
3291 const int kFramerate = 24;
3292
Erik Språng610c7632019-03-06 15:37:33 +01003293 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3294 DataRate::Zero(), 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003295 // Trigger reconfigure encoder (without resetting the entire instance).
3296 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02003297 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07003298 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3299 video_encoder_config.number_of_streams = 1;
3300 video_encoder_config.video_stream_factory =
3301 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003302 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02003303 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07003304 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003305
3306 video_source_.set_adaptation_enabled(true);
3307
3308 video_source_.IncomingCapturedFrame(
3309 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003310 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003311
3312 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003313 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003314 video_source_.IncomingCapturedFrame(
3315 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003316 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003317
mflodmancc3d4422017-08-03 08:27:51 -07003318 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003319}
3320
mflodmancc3d4422017-08-03 08:27:51 -07003321TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003322 const int kFrameWidth = 1280;
3323 const int kFrameHeight = 720;
3324 const int kLowFps = 2;
3325 const int kHighFps = 30;
3326
Erik Språng610c7632019-03-06 15:37:33 +01003327 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3328 DataRate::Zero(), 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003329
3330 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3331 max_framerate_ = kLowFps;
3332
3333 // Insert 2 seconds of 2fps video.
3334 for (int i = 0; i < kLowFps * 2; ++i) {
3335 video_source_.IncomingCapturedFrame(
3336 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3337 WaitForEncodedFrame(timestamp_ms);
3338 timestamp_ms += 1000 / kLowFps;
3339 }
3340
3341 // Make sure encoder is updated with new target.
Erik Språng610c7632019-03-06 15:37:33 +01003342 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3343 DataRate::Zero(), 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003344 video_source_.IncomingCapturedFrame(
3345 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3346 WaitForEncodedFrame(timestamp_ms);
3347 timestamp_ms += 1000 / kLowFps;
3348
3349 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3350
3351 // Insert 30fps frames for just a little more than the forced update period.
3352 const int kVcmTimerIntervalFrames =
3353 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3354 const int kFrameIntervalMs = 1000 / kHighFps;
3355 max_framerate_ = kHighFps;
3356 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3357 video_source_.IncomingCapturedFrame(
3358 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3359 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3360 // be dropped if the encoder hans't been updated with the new higher target
3361 // framerate yet, causing it to overshoot the target bitrate and then
3362 // suffering the wrath of the media optimizer.
3363 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3364 timestamp_ms += kFrameIntervalMs;
3365 }
3366
3367 // Don expect correct measurement just yet, but it should be higher than
3368 // before.
3369 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3370
mflodmancc3d4422017-08-03 08:27:51 -07003371 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003372}
3373
mflodmancc3d4422017-08-03 08:27:51 -07003374TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003375 const int kFrameWidth = 1280;
3376 const int kFrameHeight = 720;
3377 const int kTargetBitrateBps = 1000000;
3378
3379 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02003380 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
Erik Språng610c7632019-03-06 15:37:33 +01003381 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3382 DataRate::Zero(), 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -07003383 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003384
3385 // Insert a first video frame, causes another bitrate update.
3386 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3387 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3388 video_source_.IncomingCapturedFrame(
3389 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3390 WaitForEncodedFrame(timestamp_ms);
3391
3392 // Next, simulate video suspension due to pacer queue overrun.
Erik Språng610c7632019-03-06 15:37:33 +01003393 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(0), DataRate::Zero(), 0,
3394 1);
sprang4847ae62017-06-27 07:06:52 -07003395
3396 // Skip ahead until a new periodic parameter update should have occured.
3397 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3398 fake_clock_.AdvanceTimeMicros(
3399 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3400 rtc::kNumMicrosecsPerMillisec);
3401
3402 // Bitrate observer should not be called.
3403 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3404 video_source_.IncomingCapturedFrame(
3405 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3406 ExpectDroppedFrame();
3407
mflodmancc3d4422017-08-03 08:27:51 -07003408 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003409}
ilnik6b826ef2017-06-16 06:53:48 -07003410
Niels Möller4db138e2018-04-19 09:04:13 +02003411TEST_F(VideoStreamEncoderTest,
3412 DefaultCpuAdaptationThresholdsForSoftwareEncoder) {
3413 const int kFrameWidth = 1280;
3414 const int kFrameHeight = 720;
3415 const CpuOveruseOptions default_options;
Erik Språng610c7632019-03-06 15:37:33 +01003416 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3417 DataRate::Zero(), 0, 0);
Niels Möller4db138e2018-04-19 09:04:13 +02003418 video_source_.IncomingCapturedFrame(
3419 CreateFrame(1, kFrameWidth, kFrameHeight));
3420 WaitForEncodedFrame(1);
3421 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3422 .low_encode_usage_threshold_percent,
3423 default_options.low_encode_usage_threshold_percent);
3424 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3425 .high_encode_usage_threshold_percent,
3426 default_options.high_encode_usage_threshold_percent);
3427 video_stream_encoder_->Stop();
3428}
3429
3430TEST_F(VideoStreamEncoderTest,
3431 HigherCpuAdaptationThresholdsForHardwareEncoder) {
3432 const int kFrameWidth = 1280;
3433 const int kFrameHeight = 720;
3434 CpuOveruseOptions hardware_options;
3435 hardware_options.low_encode_usage_threshold_percent = 150;
3436 hardware_options.high_encode_usage_threshold_percent = 200;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +01003437 fake_encoder_.SetIsHardwareAccelerated(true);
Niels Möller4db138e2018-04-19 09:04:13 +02003438
Erik Språng610c7632019-03-06 15:37:33 +01003439 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3440 DataRate::Zero(), 0, 0);
Niels Möller4db138e2018-04-19 09:04:13 +02003441 video_source_.IncomingCapturedFrame(
3442 CreateFrame(1, kFrameWidth, kFrameHeight));
3443 WaitForEncodedFrame(1);
3444 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3445 .low_encode_usage_threshold_percent,
3446 hardware_options.low_encode_usage_threshold_percent);
3447 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3448 .high_encode_usage_threshold_percent,
3449 hardware_options.high_encode_usage_threshold_percent);
3450 video_stream_encoder_->Stop();
3451}
3452
Niels Möller6bb5ab92019-01-11 11:11:10 +01003453TEST_F(VideoStreamEncoderTest, DropsFramesWhenEncoderOvershoots) {
3454 const int kFrameWidth = 320;
3455 const int kFrameHeight = 240;
3456 const int kFps = 30;
3457 const int kTargetBitrateBps = 120000;
3458 const int kNumFramesInRun = kFps * 5; // Runs of five seconds.
3459
Erik Språng610c7632019-03-06 15:37:33 +01003460 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3461 DataRate::Zero(), 0, 0);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003462
3463 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3464 max_framerate_ = kFps;
3465
3466 // Insert 3 seconds of video, verify number of drops with normal bitrate.
3467 fake_encoder_.SimulateOvershoot(1.0);
3468 int num_dropped = 0;
3469 for (int i = 0; i < kNumFramesInRun; ++i) {
3470 video_source_.IncomingCapturedFrame(
3471 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3472 // Wait up to two frame durations for a frame to arrive.
3473 if (!TimedWaitForEncodedFrame(timestamp_ms, 2 * 1000 / kFps)) {
3474 ++num_dropped;
3475 }
3476 timestamp_ms += 1000 / kFps;
3477 }
3478
Erik Språnga8d48ab2019-02-08 14:17:40 +01003479 // Framerate should be measured to be near the expected target rate.
3480 EXPECT_NEAR(fake_encoder_.GetLastFramerate(), kFps, 1);
3481
3482 // Frame drops should be within 5% of expected 0%.
3483 EXPECT_NEAR(num_dropped, 0, 5 * kNumFramesInRun / 100);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003484
3485 // Make encoder produce frames at double the expected bitrate during 3 seconds
3486 // of video, verify number of drops. Rate needs to be slightly changed in
3487 // order to force the rate to be reconfigured.
Erik Språng7ca375c2019-02-06 16:20:17 +01003488 double overshoot_factor = 2.0;
3489 if (RateControlSettings::ParseFromFieldTrials().UseEncoderBitrateAdjuster()) {
3490 // With bitrate adjuster, when need to overshoot even more to trigger
3491 // frame dropping.
3492 overshoot_factor *= 2;
3493 }
3494 fake_encoder_.SimulateOvershoot(overshoot_factor);
Erik Språng610c7632019-03-06 15:37:33 +01003495 video_stream_encoder_->OnBitrateUpdated(
3496 DataRate::bps(kTargetBitrateBps + 1000), DataRate::Zero(), 0, 0);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003497 num_dropped = 0;
3498 for (int i = 0; i < kNumFramesInRun; ++i) {
3499 video_source_.IncomingCapturedFrame(
3500 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3501 // Wait up to two frame durations for a frame to arrive.
3502 if (!TimedWaitForEncodedFrame(timestamp_ms, 2 * 1000 / kFps)) {
3503 ++num_dropped;
3504 }
3505 timestamp_ms += 1000 / kFps;
3506 }
3507
Erik Språng610c7632019-03-06 15:37:33 +01003508 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3509 DataRate::Zero(), 0, 0);
Erik Språnga8d48ab2019-02-08 14:17:40 +01003510
3511 // Target framerate should be still be near the expected target, despite
3512 // the frame drops.
3513 EXPECT_NEAR(fake_encoder_.GetLastFramerate(), kFps, 1);
3514
3515 // Frame drops should be within 5% of expected 50%.
3516 EXPECT_NEAR(num_dropped, kNumFramesInRun / 2, 5 * kNumFramesInRun / 100);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003517
3518 video_stream_encoder_->Stop();
3519}
3520
3521TEST_F(VideoStreamEncoderTest, ConfiguresCorrectFrameRate) {
3522 const int kFrameWidth = 320;
3523 const int kFrameHeight = 240;
3524 const int kActualInputFps = 24;
3525 const int kTargetBitrateBps = 120000;
3526
3527 ASSERT_GT(max_framerate_, kActualInputFps);
3528
3529 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3530 max_framerate_ = kActualInputFps;
Erik Språng610c7632019-03-06 15:37:33 +01003531 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3532 DataRate::Zero(), 0, 0);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003533
3534 // Insert 3 seconds of video, with an input fps lower than configured max.
3535 for (int i = 0; i < kActualInputFps * 3; ++i) {
3536 video_source_.IncomingCapturedFrame(
3537 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3538 // Wait up to two frame durations for a frame to arrive.
3539 WaitForEncodedFrame(timestamp_ms);
3540 timestamp_ms += 1000 / kActualInputFps;
3541 }
3542
3543 EXPECT_NEAR(kActualInputFps, fake_encoder_.GetLastFramerate(), 1);
3544
3545 video_stream_encoder_->Stop();
3546}
3547
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01003548TEST_F(VideoStreamEncoderTest, AccumulatesUpdateRectOnDroppedFrames) {
3549 VideoFrame::UpdateRect rect;
Erik Språng610c7632019-03-06 15:37:33 +01003550 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3551 DataRate::Zero(), 0, 0);
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01003552
3553 fake_encoder_.BlockNextEncode();
3554 video_source_.IncomingCapturedFrame(
3555 CreateFrameWithUpdatedPixel(1, nullptr, 0));
3556 WaitForEncodedFrame(1);
3557 // On the very first frame full update should be forced.
3558 rect = fake_encoder_.GetLastUpdateRect();
3559 EXPECT_EQ(rect.offset_x, 0);
3560 EXPECT_EQ(rect.offset_y, 0);
3561 EXPECT_EQ(rect.height, codec_height_);
3562 EXPECT_EQ(rect.width, codec_width_);
3563 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
3564 // call to ContinueEncode.
3565 video_source_.IncomingCapturedFrame(
3566 CreateFrameWithUpdatedPixel(2, nullptr, 1));
3567 ExpectDroppedFrame();
3568 video_source_.IncomingCapturedFrame(
3569 CreateFrameWithUpdatedPixel(3, nullptr, 10));
3570 ExpectDroppedFrame();
3571 fake_encoder_.ContinueEncode();
3572 WaitForEncodedFrame(3);
3573 // Updates to pixels 1 and 10 should be accumulated to one 10x1 rect.
3574 rect = fake_encoder_.GetLastUpdateRect();
3575 EXPECT_EQ(rect.offset_x, 1);
3576 EXPECT_EQ(rect.offset_y, 0);
3577 EXPECT_EQ(rect.width, 10);
3578 EXPECT_EQ(rect.height, 1);
3579
3580 video_source_.IncomingCapturedFrame(
3581 CreateFrameWithUpdatedPixel(4, nullptr, 0));
3582 WaitForEncodedFrame(4);
3583 // Previous frame was encoded, so no accumulation should happen.
3584 rect = fake_encoder_.GetLastUpdateRect();
3585 EXPECT_EQ(rect.offset_x, 0);
3586 EXPECT_EQ(rect.offset_y, 0);
3587 EXPECT_EQ(rect.width, 1);
3588 EXPECT_EQ(rect.height, 1);
3589
3590 video_stream_encoder_->Stop();
3591}
3592
Erik Språngd7329ca2019-02-21 21:19:53 +01003593TEST_F(VideoStreamEncoderTest, SetsFrameTypes) {
Erik Språng610c7632019-03-06 15:37:33 +01003594 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3595 DataRate::Zero(), 0, 0);
Erik Språngd7329ca2019-02-21 21:19:53 +01003596
3597 // First frame is always keyframe.
3598 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
3599 WaitForEncodedFrame(1);
3600 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
Niels Möller87e2d782019-03-07 10:18:23 +01003601 testing::ElementsAre(VideoFrameType{kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003602
3603 // Insert delta frame.
3604 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
3605 WaitForEncodedFrame(2);
3606 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
Niels Möller87e2d782019-03-07 10:18:23 +01003607 testing::ElementsAre(VideoFrameType{kVideoFrameDelta}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003608
3609 // Request next frame be a key-frame.
3610 video_stream_encoder_->SendKeyFrame();
3611 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
3612 WaitForEncodedFrame(3);
3613 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
Niels Möller87e2d782019-03-07 10:18:23 +01003614 testing::ElementsAre(VideoFrameType{kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003615
3616 video_stream_encoder_->Stop();
3617}
3618
3619TEST_F(VideoStreamEncoderTest, SetsFrameTypesSimulcast) {
3620 // Setup simulcast with three streams.
3621 ResetEncoder("VP8", 3, 1, 1, false);
Erik Språng610c7632019-03-06 15:37:33 +01003622 video_stream_encoder_->OnBitrateUpdated(
3623 DataRate::bps(kSimulcastTargetBitrateBps), DataRate::Zero(), 0, 0);
Erik Språngd7329ca2019-02-21 21:19:53 +01003624 // Wait for all three layers before triggering event.
3625 sink_.SetNumExpectedLayers(3);
3626
3627 // First frame is always keyframe.
3628 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
3629 WaitForEncodedFrame(1);
3630 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
3631 testing::ElementsAreArray(
3632 {kVideoFrameKey, kVideoFrameKey, kVideoFrameKey}));
3633
3634 // Insert delta frame.
3635 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
3636 WaitForEncodedFrame(2);
3637 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
3638 testing::ElementsAreArray(
3639 {kVideoFrameDelta, kVideoFrameDelta, kVideoFrameDelta}));
3640
3641 // Request next frame be a key-frame.
3642 // Only first stream is configured to produce key-frame.
3643 video_stream_encoder_->SendKeyFrame();
3644 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
3645 WaitForEncodedFrame(3);
3646 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
3647 testing::ElementsAreArray(
3648 {kVideoFrameKey, kVideoFrameDelta, kVideoFrameDelta}));
3649
3650 video_stream_encoder_->Stop();
3651}
3652
3653TEST_F(VideoStreamEncoderTest, RequestKeyframeInternalSource) {
3654 // Configure internal source factory and setup test again.
3655 encoder_factory_.SetHasInternalSource(true);
3656 ResetEncoder("VP8", 1, 1, 1, false);
Erik Språng610c7632019-03-06 15:37:33 +01003657 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3658 DataRate::Zero(), 0, 0);
Erik Språngd7329ca2019-02-21 21:19:53 +01003659
3660 // Call encoder directly, simulating internal source where encoded frame
3661 // callback in VideoStreamEncoder is called despite no OnFrame().
3662 fake_encoder_.InjectFrame(CreateFrame(1, nullptr), true);
3663 EXPECT_TRUE(WaitForFrame(kDefaultTimeoutMs));
3664 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
Niels Möller87e2d782019-03-07 10:18:23 +01003665 testing::ElementsAre(VideoFrameType{kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003666
Niels Möller87e2d782019-03-07 10:18:23 +01003667 const std::vector<VideoFrameType> kDeltaFrame = {kVideoFrameDelta};
Erik Språngd7329ca2019-02-21 21:19:53 +01003668 // Need to set timestamp manually since manually for injected frame.
3669 VideoFrame frame = CreateFrame(101, nullptr);
3670 frame.set_timestamp(101);
3671 fake_encoder_.InjectFrame(frame, false);
3672 EXPECT_TRUE(WaitForFrame(kDefaultTimeoutMs));
3673 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
Niels Möller87e2d782019-03-07 10:18:23 +01003674 testing::ElementsAre(VideoFrameType{kVideoFrameDelta}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003675
3676 // Request key-frame. The forces a dummy frame down into the encoder.
3677 fake_encoder_.ExpectNullFrame();
3678 video_stream_encoder_->SendKeyFrame();
3679 EXPECT_TRUE(WaitForFrame(kDefaultTimeoutMs));
3680 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
Niels Möller87e2d782019-03-07 10:18:23 +01003681 testing::ElementsAre(VideoFrameType{kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003682
3683 video_stream_encoder_->Stop();
3684}
Erik Språngb7cb7b52019-02-26 15:52:33 +01003685
3686TEST_F(VideoStreamEncoderTest, AdjustsTimestampInternalSource) {
3687 // Configure internal source factory and setup test again.
3688 encoder_factory_.SetHasInternalSource(true);
3689 ResetEncoder("VP8", 1, 1, 1, false);
Erik Språng610c7632019-03-06 15:37:33 +01003690 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3691 DataRate::Zero(), 0, 0);
Erik Språngb7cb7b52019-02-26 15:52:33 +01003692
3693 int64_t timestamp = 1;
3694 EncodedImage image;
3695 image.Allocate(kTargetBitrateBps / kDefaultFramerate / 8);
3696 image.capture_time_ms_ = ++timestamp;
3697 image.SetTimestamp(static_cast<uint32_t>(timestamp * 90));
3698 const int64_t kEncodeFinishDelayMs = 10;
3699 image.timing_.encode_start_ms = timestamp;
3700 image.timing_.encode_finish_ms = timestamp + kEncodeFinishDelayMs;
3701 fake_encoder_.InjectEncodedImage(image);
3702 // Wait for frame without incrementing clock.
3703 EXPECT_TRUE(sink_.WaitForFrame(kDefaultTimeoutMs));
3704 // Frame is captured kEncodeFinishDelayMs before it's encoded, so restored
3705 // capture timestamp should be kEncodeFinishDelayMs in the past.
3706 EXPECT_EQ(sink_.GetLastCaptureTimeMs(),
3707 fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec -
3708 kEncodeFinishDelayMs);
3709
3710 video_stream_encoder_->Stop();
3711}
perkj26091b12016-09-01 01:17:40 -07003712} // namespace webrtc