blob: e2453a42a63b9b9dc291f34d39ed540fd60bf41a [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/create_vp8_temporal_layers.h"
22#include "api/video_codecs/vp8_temporal_layers.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.
681 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
sprangfe627f32017-03-29 08:24:59 -0700682 for (int i = 0; i < num_streams; ++i) {
683 allocated_temporal_layers_.emplace_back(
Erik Språng4529fbc2018-10-12 10:30:31 +0200684 CreateVp8TemporalLayers(Vp8TemporalLayersType::kFixedPattern,
685 config->VP8().numberOfTemporalLayers));
sprangfe627f32017-03-29 08:24:59 -0700686 }
687 }
Erik Språngb7cb7b52019-02-26 15:52:33 +0100688 if (force_init_encode_failed_) {
689 initialized_ = EncoderState::kInitializationFailed;
sprangfe627f32017-03-29 08:24:59 -0700690 return -1;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100691 }
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100692
Erik Språngb7cb7b52019-02-26 15:52:33 +0100693 initialized_ = EncoderState::kInitialized;
sprangfe627f32017-03-29 08:24:59 -0700694 return res;
695 }
696
Erik Språngb7cb7b52019-02-26 15:52:33 +0100697 int32_t Release() override {
698 rtc::CritScope lock(&local_crit_sect_);
699 EXPECT_NE(initialized_, EncoderState::kUninitialized);
700 initialized_ = EncoderState::kUninitialized;
701 return FakeEncoder::Release();
702 }
703
Niels Möller6bb5ab92019-01-11 11:11:10 +0100704 int32_t SetRateAllocation(const VideoBitrateAllocation& rate_allocation,
705 uint32_t framerate) {
706 rtc::CritScope lock(&local_crit_sect_);
707 VideoBitrateAllocation adjusted_rate_allocation;
708 for (size_t si = 0; si < kMaxSpatialLayers; ++si) {
709 for (size_t ti = 0; ti < kMaxTemporalStreams; ++ti) {
710 if (rate_allocation.HasBitrate(si, ti)) {
711 adjusted_rate_allocation.SetBitrate(
712 si, ti,
713 static_cast<uint32_t>(rate_allocation.GetBitrate(si, ti) *
714 rate_factor_));
715 }
716 }
717 }
718 last_framerate_ = framerate;
Erik Språngd7329ca2019-02-21 21:19:53 +0100719 last_bitrate_allocation_ = rate_allocation;
Niels Möller6bb5ab92019-01-11 11:11:10 +0100720 return FakeEncoder::SetRateAllocation(adjusted_rate_allocation,
721 framerate);
722 }
723
brandtre78d2662017-01-16 05:57:16 -0800724 rtc::CriticalSection local_crit_sect_;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100725 enum class EncoderState {
726 kUninitialized,
727 kInitializationFailed,
728 kInitialized
729 } initialized_ RTC_GUARDED_BY(local_crit_sect_) =
730 EncoderState::kUninitialized;
danilchapa37de392017-09-09 04:17:22 -0700731 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700732 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700733 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
734 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
735 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
736 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
737 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100738 bool is_hardware_accelerated_ RTC_GUARDED_BY(local_crit_sect_) = false;
Erik Språng4529fbc2018-10-12 10:30:31 +0200739 std::vector<std::unique_ptr<Vp8TemporalLayers>> allocated_temporal_layers_
danilchapa37de392017-09-09 04:17:22 -0700740 RTC_GUARDED_BY(local_crit_sect_);
741 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
Niels Möller6bb5ab92019-01-11 11:11:10 +0100742 double rate_factor_ RTC_GUARDED_BY(local_crit_sect_) = 1.0;
743 uint32_t last_framerate_ RTC_GUARDED_BY(local_crit_sect_) = 0;
Erik Språngd7329ca2019-02-21 21:19:53 +0100744 absl::optional<VideoBitrateAllocation> last_bitrate_allocation_;
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100745 VideoFrame::UpdateRect last_update_rect_
746 RTC_GUARDED_BY(local_crit_sect_) = {0, 0, 0, 0};
Niels Möller87e2d782019-03-07 10:18:23 +0100747 std::vector<VideoFrameType> last_frame_types_;
Erik Språngd7329ca2019-02-21 21:19:53 +0100748 bool expect_null_frame_ = false;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100749 EncodedImageCallback* encoded_image_callback_
750 RTC_GUARDED_BY(local_crit_sect_) = nullptr;
perkj26091b12016-09-01 01:17:40 -0700751 };
752
mflodmancc3d4422017-08-03 08:27:51 -0700753 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700754 public:
755 explicit TestSink(TestEncoder* test_encoder)
Niels Möllerc572ff32018-11-07 08:43:50 +0100756 : test_encoder_(test_encoder) {}
perkj26091b12016-09-01 01:17:40 -0700757
perkj26091b12016-09-01 01:17:40 -0700758 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700759 EXPECT_TRUE(
760 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
761 }
762
763 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
764 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700765 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700766 if (!encoded_frame_event_.Wait(timeout_ms))
767 return false;
perkj26091b12016-09-01 01:17:40 -0700768 {
769 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800770 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700771 }
772 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700773 return true;
perkj26091b12016-09-01 01:17:40 -0700774 }
775
sprangb1ca0732017-02-01 08:38:12 -0800776 void WaitForEncodedFrame(uint32_t expected_width,
777 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700778 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100779 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700780 }
781
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100782 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700783 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800784 uint32_t width = 0;
785 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800786 {
787 rtc::CritScope lock(&crit_);
788 width = last_width_;
789 height = last_height_;
790 }
791 EXPECT_EQ(expected_height, height);
792 EXPECT_EQ(expected_width, width);
793 }
794
kthelgason2fc52542017-03-03 00:24:41 -0800795 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800796
sprangc5d62e22017-04-02 23:53:04 -0700797 bool WaitForFrame(int64_t timeout_ms) {
798 return encoded_frame_event_.Wait(timeout_ms);
799 }
800
perkj26091b12016-09-01 01:17:40 -0700801 void SetExpectNoFrames() {
802 rtc::CritScope lock(&crit_);
803 expect_frames_ = false;
804 }
805
asaperssonfab67072017-04-04 05:51:49 -0700806 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200807 rtc::CritScope lock(&crit_);
808 return number_of_reconfigurations_;
809 }
810
asaperssonfab67072017-04-04 05:51:49 -0700811 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200812 rtc::CritScope lock(&crit_);
813 return min_transmit_bitrate_bps_;
814 }
815
Erik Språngd7329ca2019-02-21 21:19:53 +0100816 void SetNumExpectedLayers(size_t num_layers) {
817 rtc::CritScope lock(&crit_);
818 num_expected_layers_ = num_layers;
819 }
820
Erik Språngb7cb7b52019-02-26 15:52:33 +0100821 int64_t GetLastCaptureTimeMs() const {
822 rtc::CritScope lock(&crit_);
823 return last_capture_time_ms_;
824 }
825
perkj26091b12016-09-01 01:17:40 -0700826 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700827 Result OnEncodedImage(
828 const EncodedImage& encoded_image,
829 const CodecSpecificInfo* codec_specific_info,
830 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200831 rtc::CritScope lock(&crit_);
832 EXPECT_TRUE(expect_frames_);
Erik Språngd7329ca2019-02-21 21:19:53 +0100833 uint32_t timestamp = encoded_image.Timestamp();
834 if (last_timestamp_ != timestamp) {
835 num_received_layers_ = 1;
836 } else {
837 ++num_received_layers_;
838 }
839 last_timestamp_ = timestamp;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100840 last_capture_time_ms_ = encoded_image.capture_time_ms_;
sprangb1ca0732017-02-01 08:38:12 -0800841 last_width_ = encoded_image._encodedWidth;
842 last_height_ = encoded_image._encodedHeight;
Erik Språngd7329ca2019-02-21 21:19:53 +0100843 if (num_received_layers_ == num_expected_layers_) {
844 encoded_frame_event_.Set();
845 }
sprangb1ca0732017-02-01 08:38:12 -0800846 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200847 }
848
Rasmus Brandtc402dbe2019-02-04 11:09:46 +0100849 void OnEncoderConfigurationChanged(
850 std::vector<VideoStream> streams,
851 VideoEncoderConfig::ContentType content_type,
852 int min_transmit_bitrate_bps) override {
Per512ecb32016-09-23 15:52:06 +0200853 rtc::CriticalSection crit_;
854 ++number_of_reconfigurations_;
855 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
856 }
857
perkj26091b12016-09-01 01:17:40 -0700858 rtc::CriticalSection crit_;
859 TestEncoder* test_encoder_;
860 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800861 uint32_t last_timestamp_ = 0;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100862 int64_t last_capture_time_ms_ = 0;
sprangb1ca0732017-02-01 08:38:12 -0800863 uint32_t last_height_ = 0;
864 uint32_t last_width_ = 0;
Erik Språngd7329ca2019-02-21 21:19:53 +0100865 size_t num_expected_layers_ = 1;
866 size_t num_received_layers_ = 0;
perkj26091b12016-09-01 01:17:40 -0700867 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200868 int number_of_reconfigurations_ = 0;
869 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700870 };
871
872 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100873 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200874 int codec_width_;
875 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700876 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700877 TestEncoder fake_encoder_;
Niels Möllercbcbc222018-09-28 09:07:24 +0200878 test::VideoEncoderProxyFactory encoder_factory_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800879 std::unique_ptr<VideoBitrateAllocatorFactory> bitrate_allocator_factory_;
sprangc5d62e22017-04-02 23:53:04 -0700880 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700881 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800882 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700883 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700884 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700885};
886
mflodmancc3d4422017-08-03 08:27:51 -0700887TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
Erik Språng610c7632019-03-06 15:37:33 +0100888 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
889 DataRate::Zero(), 0, 0);
Niels Möllerc572ff32018-11-07 08:43:50 +0100890 rtc::Event frame_destroyed_event;
perkja49cbd32016-09-16 07:53:41 -0700891 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700892 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700893 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700894 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700895}
896
mflodmancc3d4422017-08-03 08:27:51 -0700897TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700898 // Dropped since no target bitrate has been set.
Niels Möllerc572ff32018-11-07 08:43:50 +0100899 rtc::Event frame_destroyed_event;
Sebastian Janssona3177052018-04-10 13:05:49 +0200900 // The encoder will cache up to one frame for a short duration. Adding two
901 // frames means that the first frame will be dropped and the second frame will
902 // be sent when the encoder is enabled.
perkja49cbd32016-09-16 07:53:41 -0700903 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
Sebastian Janssona3177052018-04-10 13:05:49 +0200904 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkja49cbd32016-09-16 07:53:41 -0700905 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700906
Erik Språng610c7632019-03-06 15:37:33 +0100907 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
908 DataRate::Zero(), 0, 0);
perkj26091b12016-09-01 01:17:40 -0700909
Sebastian Janssona3177052018-04-10 13:05:49 +0200910 // The pending frame should be received.
sprang4847ae62017-06-27 07:06:52 -0700911 WaitForEncodedFrame(2);
Sebastian Janssona3177052018-04-10 13:05:49 +0200912 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
913
914 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700915 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700916}
917
mflodmancc3d4422017-08-03 08:27:51 -0700918TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
Erik Språng610c7632019-03-06 15:37:33 +0100919 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
920 DataRate::Zero(), 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700921 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700922 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700923
Erik Språng610c7632019-03-06 15:37:33 +0100924 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(0), DataRate::Zero(), 0,
925 0);
Sebastian Janssona3177052018-04-10 13:05:49 +0200926 // The encoder will cache up to one frame for a short duration. Adding two
927 // frames means that the first frame will be dropped and the second frame will
928 // be sent when the encoder is resumed.
perkja49cbd32016-09-16 07:53:41 -0700929 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Sebastian Janssona3177052018-04-10 13:05:49 +0200930 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700931
Erik Språng610c7632019-03-06 15:37:33 +0100932 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
933 DataRate::Zero(), 0, 0);
sprang4847ae62017-06-27 07:06:52 -0700934 WaitForEncodedFrame(3);
Sebastian Janssona3177052018-04-10 13:05:49 +0200935 video_source_.IncomingCapturedFrame(CreateFrame(4, nullptr));
936 WaitForEncodedFrame(4);
mflodmancc3d4422017-08-03 08:27:51 -0700937 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700938}
939
mflodmancc3d4422017-08-03 08:27:51 -0700940TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
Erik Språng610c7632019-03-06 15:37:33 +0100941 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
942 DataRate::Zero(), 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700943 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700944 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700945
946 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700947 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700948
perkja49cbd32016-09-16 07:53:41 -0700949 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700950 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700951 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700952}
953
mflodmancc3d4422017-08-03 08:27:51 -0700954TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
Erik Språng610c7632019-03-06 15:37:33 +0100955 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
956 DataRate::Zero(), 0, 0);
perkj26091b12016-09-01 01:17:40 -0700957
perkja49cbd32016-09-16 07:53:41 -0700958 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700959 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700960
mflodmancc3d4422017-08-03 08:27:51 -0700961 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700962 sink_.SetExpectNoFrames();
Niels Möllerc572ff32018-11-07 08:43:50 +0100963 rtc::Event frame_destroyed_event;
perkja49cbd32016-09-16 07:53:41 -0700964 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
965 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700966}
967
mflodmancc3d4422017-08-03 08:27:51 -0700968TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
Erik Språng610c7632019-03-06 15:37:33 +0100969 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
970 DataRate::Zero(), 0, 0);
perkj26091b12016-09-01 01:17:40 -0700971
972 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700973 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700974 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700975 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
976 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700977 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
978 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700979 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700980 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700981
mflodmancc3d4422017-08-03 08:27:51 -0700982 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700983}
984
mflodmancc3d4422017-08-03 08:27:51 -0700985TEST_F(VideoStreamEncoderTest,
986 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
Erik Språng610c7632019-03-06 15:37:33 +0100987 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
988 DataRate::Zero(), 0, 0);
Per21d45d22016-10-30 21:37:57 +0100989 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200990
991 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200992 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700993 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100994 // The encoder will have been configured once when the first frame is
995 // received.
996 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200997
998 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200999 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +02001000 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -07001001 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001002 kMaxPayloadLength);
Per512ecb32016-09-23 15:52:06 +02001003
1004 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +02001005 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001006 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +01001007 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -07001008 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -07001009
mflodmancc3d4422017-08-03 08:27:51 -07001010 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -07001011}
1012
mflodmancc3d4422017-08-03 08:27:51 -07001013TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
Erik Språng610c7632019-03-06 15:37:33 +01001014 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1015 DataRate::Zero(), 0, 0);
perkjfa10b552016-10-02 23:45:26 -07001016
1017 // Capture a frame and wait for it to synchronize with the encoder thread.
1018 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001019 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +01001020 // The encoder will have been configured once.
1021 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -07001022 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
1023 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
1024
1025 codec_width_ *= 2;
1026 codec_height_ *= 2;
1027 // Capture a frame with a higher resolution and wait for it to synchronize
1028 // with the encoder thread.
1029 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001030 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -07001031 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
1032 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +01001033 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -07001034
mflodmancc3d4422017-08-03 08:27:51 -07001035 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -07001036}
1037
mflodmancc3d4422017-08-03 08:27:51 -07001038TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -07001039 EXPECT_TRUE(video_source_.has_sinks());
1040 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001041 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001042 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001043 EXPECT_FALSE(video_source_.has_sinks());
1044 EXPECT_TRUE(new_video_source.has_sinks());
1045
mflodmancc3d4422017-08-03 08:27:51 -07001046 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001047}
1048
mflodmancc3d4422017-08-03 08:27:51 -07001049TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -07001050 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -07001051 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -07001052 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -07001053 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001054}
1055
Jonathan Yubc771b72017-12-08 17:04:29 -08001056TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
1057 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -07001058 const int kWidth = 1280;
1059 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -08001060
1061 // We rely on the automatic resolution adaptation, but we handle framerate
1062 // adaptation manually by mocking the stats proxy.
1063 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -07001064
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001065 // Enable BALANCED preference, no initial limitation.
Erik Språng610c7632019-03-06 15:37:33 +01001066 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1067 DataRate::Zero(), 0, 0);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001068 video_stream_encoder_->SetSource(&video_source_,
1069 webrtc::DegradationPreference::BALANCED);
Jonathan Yubc771b72017-12-08 17:04:29 -08001070 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001071 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001072 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -07001073 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1074
Jonathan Yubc771b72017-12-08 17:04:29 -08001075 // Adapt down as far as possible.
1076 rtc::VideoSinkWants last_wants;
1077 int64_t t = 1;
1078 int loop_count = 0;
1079 do {
1080 ++loop_count;
1081 last_wants = video_source_.sink_wants();
1082
1083 // Simulate the framerate we've been asked to adapt to.
1084 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
1085 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
1086 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1087 mock_stats.input_frame_rate = fps;
1088 stats_proxy_->SetMockStats(mock_stats);
1089
1090 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1091 sink_.WaitForEncodedFrame(t);
1092 t += frame_interval_ms;
1093
mflodmancc3d4422017-08-03 08:27:51 -07001094 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08001095 VerifyBalancedModeFpsRange(
1096 video_source_.sink_wants(),
1097 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1098 } while (video_source_.sink_wants().max_pixel_count <
1099 last_wants.max_pixel_count ||
1100 video_source_.sink_wants().max_framerate_fps <
1101 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001102
Jonathan Yubc771b72017-12-08 17:04:29 -08001103 // Verify that we've adapted all the way down.
1104 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001105 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001106 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
1107 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -07001108 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -08001109 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
1110 *video_source_.last_sent_height());
1111 EXPECT_EQ(kMinBalancedFramerateFps,
1112 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001113
Jonathan Yubc771b72017-12-08 17:04:29 -08001114 // Adapt back up the same number of times we adapted down.
1115 for (int i = 0; i < loop_count - 1; ++i) {
1116 last_wants = video_source_.sink_wants();
1117
1118 // Simulate the framerate we've been asked to adapt to.
1119 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
1120 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
1121 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1122 mock_stats.input_frame_rate = fps;
1123 stats_proxy_->SetMockStats(mock_stats);
1124
1125 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1126 sink_.WaitForEncodedFrame(t);
1127 t += frame_interval_ms;
1128
mflodmancc3d4422017-08-03 08:27:51 -07001129 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -08001130 VerifyBalancedModeFpsRange(
1131 video_source_.sink_wants(),
1132 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1133 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
1134 last_wants.max_pixel_count ||
1135 video_source_.sink_wants().max_framerate_fps >
1136 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001137 }
1138
Åsa Persson8c1bf952018-09-13 10:42:19 +02001139 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001140 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001141 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001142 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1143 EXPECT_EQ((loop_count - 1) * 2,
1144 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -07001145
mflodmancc3d4422017-08-03 08:27:51 -07001146 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001147}
mflodmancc3d4422017-08-03 08:27:51 -07001148TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
Erik Språng610c7632019-03-06 15:37:33 +01001149 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1150 DataRate::Zero(), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001151 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001152
sprangc5d62e22017-04-02 23:53:04 -07001153 const int kFrameWidth = 1280;
1154 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07001155
Åsa Persson8c1bf952018-09-13 10:42:19 +02001156 int64_t frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -07001157
kthelgason5e13d412016-12-01 03:59:51 -08001158 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001159 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001160 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001161 frame_timestamp += kFrameIntervalMs;
1162
perkj803d97f2016-11-01 11:45:46 -07001163 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001164 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001165 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001166 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001167 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001168 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -07001169
asapersson0944a802017-04-07 00:57:58 -07001170 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -07001171 // wanted resolution.
1172 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
1173 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
1174 kFrameWidth * kFrameHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001175 EXPECT_EQ(kDefaultFramerate, video_source_.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001176
1177 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -07001178 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001179 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001180 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001181
sprangc5d62e22017-04-02 23:53:04 -07001182 // Initially no degradation registered.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001183 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001184
sprangc5d62e22017-04-02 23:53:04 -07001185 // Force an input frame rate to be available, or the adaptation call won't
1186 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -07001187 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -07001188 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -07001189 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -07001190 stats_proxy_->SetMockStats(stats);
1191
mflodmancc3d4422017-08-03 08:27:51 -07001192 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001193 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001194 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001195 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001196 frame_timestamp += kFrameIntervalMs;
1197
1198 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001199 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001200 EXPECT_EQ(std::numeric_limits<int>::max(),
1201 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001202 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001203
asapersson02465b82017-04-10 01:12:52 -07001204 // Turn off degradation completely.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001205 video_stream_encoder_->SetSource(&new_video_source,
1206 webrtc::DegradationPreference::DISABLED);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001207 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001208
mflodmancc3d4422017-08-03 08:27:51 -07001209 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001210 new_video_source.IncomingCapturedFrame(
1211 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001212 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001213 frame_timestamp += kFrameIntervalMs;
1214
1215 // Still no degradation.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001216 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001217
1218 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001219 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001220 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
sprangc5d62e22017-04-02 23:53:04 -07001221 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1222 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001223 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001224 EXPECT_EQ(kDefaultFramerate, new_video_source.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001225
1226 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001227 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001228 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001229 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1230 EXPECT_EQ(std::numeric_limits<int>::max(),
1231 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001232 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001233
mflodmancc3d4422017-08-03 08:27:51 -07001234 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001235}
1236
mflodmancc3d4422017-08-03 08:27:51 -07001237TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
Erik Språng610c7632019-03-06 15:37:33 +01001238 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1239 DataRate::Zero(), 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001240
asaperssonfab67072017-04-04 05:51:49 -07001241 const int kWidth = 1280;
1242 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001243 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001244 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001245 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1246 EXPECT_FALSE(stats.bw_limited_resolution);
1247 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1248
1249 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001250 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001251 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001252 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001253
1254 stats = stats_proxy_->GetStats();
1255 EXPECT_TRUE(stats.bw_limited_resolution);
1256 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1257
1258 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001259 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001260 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001261 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001262
1263 stats = stats_proxy_->GetStats();
1264 EXPECT_FALSE(stats.bw_limited_resolution);
1265 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1266 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1267
mflodmancc3d4422017-08-03 08:27:51 -07001268 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001269}
1270
mflodmancc3d4422017-08-03 08:27:51 -07001271TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
Erik Språng610c7632019-03-06 15:37:33 +01001272 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1273 DataRate::Zero(), 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001274
1275 const int kWidth = 1280;
1276 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001277 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001278 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001279 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1280 EXPECT_FALSE(stats.cpu_limited_resolution);
1281 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1282
1283 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001284 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001285 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001286 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001287
1288 stats = stats_proxy_->GetStats();
1289 EXPECT_TRUE(stats.cpu_limited_resolution);
1290 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1291
1292 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001293 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001294 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001295 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001296
1297 stats = stats_proxy_->GetStats();
1298 EXPECT_FALSE(stats.cpu_limited_resolution);
1299 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001300 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001301
mflodmancc3d4422017-08-03 08:27:51 -07001302 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001303}
1304
mflodmancc3d4422017-08-03 08:27:51 -07001305TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
Erik Språng610c7632019-03-06 15:37:33 +01001306 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1307 DataRate::Zero(), 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001308
asaperssonfab67072017-04-04 05:51:49 -07001309 const int kWidth = 1280;
1310 const int kHeight = 720;
1311 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001312 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001313 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001314 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001315 EXPECT_FALSE(stats.cpu_limited_resolution);
1316 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1317
asaperssonfab67072017-04-04 05:51:49 -07001318 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001319 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001320 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001321 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001322 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001323 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001324 EXPECT_TRUE(stats.cpu_limited_resolution);
1325 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1326
1327 // Set new source with adaptation still enabled.
1328 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001329 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001330 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001331
asaperssonfab67072017-04-04 05:51:49 -07001332 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001333 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001334 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001335 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001336 EXPECT_TRUE(stats.cpu_limited_resolution);
1337 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1338
1339 // Set adaptation disabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001340 video_stream_encoder_->SetSource(&new_video_source,
1341 webrtc::DegradationPreference::DISABLED);
kthelgason876222f2016-11-29 01:44:11 -08001342
asaperssonfab67072017-04-04 05:51:49 -07001343 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001344 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001345 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001346 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001347 EXPECT_FALSE(stats.cpu_limited_resolution);
1348 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1349
1350 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001351 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001352 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001353
asaperssonfab67072017-04-04 05:51:49 -07001354 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001355 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001356 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001357 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001358 EXPECT_TRUE(stats.cpu_limited_resolution);
1359 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1360
asaperssonfab67072017-04-04 05:51:49 -07001361 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001362 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001363 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001364 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001365 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001366 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001367 EXPECT_FALSE(stats.cpu_limited_resolution);
1368 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001369 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001370
mflodmancc3d4422017-08-03 08:27:51 -07001371 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001372}
1373
mflodmancc3d4422017-08-03 08:27:51 -07001374TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
Erik Språng610c7632019-03-06 15:37:33 +01001375 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1376 DataRate::Zero(), 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001377
asaperssonfab67072017-04-04 05:51:49 -07001378 const int kWidth = 1280;
1379 const int kHeight = 720;
1380 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001381 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001382 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001383 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001384 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001385 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001386
1387 // Set new source with adaptation still enabled.
1388 test::FrameForwarder new_video_source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001389 video_stream_encoder_->SetSource(&new_video_source,
1390 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001391
asaperssonfab67072017-04-04 05:51:49 -07001392 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001393 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001394 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001395 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001396 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001397 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001398
asaperssonfab67072017-04-04 05:51:49 -07001399 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001400 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001401 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001402 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001403 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001404 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001405 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001406 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001407
asaperssonfab67072017-04-04 05:51:49 -07001408 // Set new source with adaptation still enabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001409 video_stream_encoder_->SetSource(&new_video_source,
1410 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001411
asaperssonfab67072017-04-04 05:51:49 -07001412 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001413 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001414 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001415 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001416 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001417 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001418
asapersson02465b82017-04-10 01:12:52 -07001419 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001420 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001421 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001422
asaperssonfab67072017-04-04 05:51:49 -07001423 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001424 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001425 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001426 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001427 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001428 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1429 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001430
mflodmancc3d4422017-08-03 08:27:51 -07001431 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001432}
1433
mflodmancc3d4422017-08-03 08:27:51 -07001434TEST_F(VideoStreamEncoderTest,
1435 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
Erik Språng610c7632019-03-06 15:37:33 +01001436 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1437 DataRate::Zero(), 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001438
1439 const int kWidth = 1280;
1440 const int kHeight = 720;
Åsa Persson8c1bf952018-09-13 10:42:19 +02001441 int64_t timestamp_ms = kFrameIntervalMs;
asapersson36e9eb42017-03-31 05:29:12 -07001442 video_source_.set_adaptation_enabled(true);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001443 video_source_.IncomingCapturedFrame(
1444 CreateFrame(timestamp_ms, kWidth, kHeight));
1445 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001446 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1447 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1448 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1449
1450 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001451 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001452 timestamp_ms += kFrameIntervalMs;
1453 video_source_.IncomingCapturedFrame(
1454 CreateFrame(timestamp_ms, kWidth, kHeight));
1455 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001456 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1457 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1458 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1459
1460 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001461 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001462 timestamp_ms += kFrameIntervalMs;
1463 video_source_.IncomingCapturedFrame(
1464 CreateFrame(timestamp_ms, kWidth, kHeight));
1465 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001466 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1467 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1468 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1469
Niels Möller4db138e2018-04-19 09:04:13 +02001470 // Leave source unchanged, but disable quality scaler.
asapersson36e9eb42017-03-31 05:29:12 -07001471 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02001472
1473 VideoEncoderConfig video_encoder_config;
1474 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
1475 // Make format different, to force recreation of encoder.
1476 video_encoder_config.video_format.parameters["foo"] = "foo";
1477 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001478 kMaxPayloadLength);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001479 timestamp_ms += kFrameIntervalMs;
1480 video_source_.IncomingCapturedFrame(
1481 CreateFrame(timestamp_ms, kWidth, kHeight));
1482 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001483 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1484 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1485 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1486
mflodmancc3d4422017-08-03 08:27:51 -07001487 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001488}
1489
mflodmancc3d4422017-08-03 08:27:51 -07001490TEST_F(VideoStreamEncoderTest,
1491 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
Erik Språng610c7632019-03-06 15:37:33 +01001492 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1493 DataRate::Zero(), 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001494
asapersson0944a802017-04-07 00:57:58 -07001495 const int kWidth = 1280;
1496 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001497 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001498
asaperssonfab67072017-04-04 05:51:49 -07001499 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001500 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001501 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001502 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001503 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001504 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1505
asapersson02465b82017-04-10 01:12:52 -07001506 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001507 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001508 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001509 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001510 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001511 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001512 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001513 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1514
1515 // Set new source with adaptation still enabled.
1516 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001517 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001518 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001519
1520 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001521 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001522 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001523 stats = stats_proxy_->GetStats();
1524 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001525 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001526 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1527
sprangc5d62e22017-04-02 23:53:04 -07001528 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001529 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001530 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001531 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001532 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001533 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001534 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001535 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001536 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001537 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001538 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1539
sprangc5d62e22017-04-02 23:53:04 -07001540 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001541 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001542 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1543 mock_stats.input_frame_rate = 30;
1544 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001545 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001546 stats_proxy_->ResetMockStats();
1547
1548 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001549 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001550 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001551
1552 // Framerate now adapted.
1553 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001554 EXPECT_FALSE(stats.cpu_limited_resolution);
1555 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001556 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1557
1558 // Disable CPU adaptation.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001559 video_stream_encoder_->SetSource(&new_video_source,
1560 webrtc::DegradationPreference::DISABLED);
sprangc5d62e22017-04-02 23:53:04 -07001561 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001562 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001563 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001564
1565 stats = stats_proxy_->GetStats();
1566 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001567 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001568 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1569
1570 // Try to trigger overuse. Should not succeed.
1571 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001572 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001573 stats_proxy_->ResetMockStats();
1574
1575 stats = stats_proxy_->GetStats();
1576 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001577 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001578 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1579
1580 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001581 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001582 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssonfab67072017-04-04 05:51:49 -07001583 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001584 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001585 stats = stats_proxy_->GetStats();
1586 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001587 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001588 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001589
1590 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001591 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001592 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001593 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001594 stats = stats_proxy_->GetStats();
1595 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001596 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001597 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1598
1599 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001600 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001601 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001602 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001603 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001604 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001605 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001606 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001607 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001608 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001609 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1610
1611 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001612 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001613 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001614 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001615 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001616 stats = stats_proxy_->GetStats();
1617 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001618 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001619 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001620 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001621
mflodmancc3d4422017-08-03 08:27:51 -07001622 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001623}
1624
mflodmancc3d4422017-08-03 08:27:51 -07001625TEST_F(VideoStreamEncoderTest,
1626 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001627 const int kWidth = 1280;
1628 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001629 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1630 DataRate::Zero(), 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001631
asaperssonfab67072017-04-04 05:51:49 -07001632 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001633 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001634
asaperssonfab67072017-04-04 05:51:49 -07001635 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001636 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001637
asaperssonfab67072017-04-04 05:51:49 -07001638 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001639 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001640
asaperssonfab67072017-04-04 05:51:49 -07001641 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001642 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001643
kthelgason876222f2016-11-29 01:44:11 -08001644 // Expect a scale down.
1645 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001646 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001647
asapersson02465b82017-04-10 01:12:52 -07001648 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001649 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001650 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001651 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001652
asaperssonfab67072017-04-04 05:51:49 -07001653 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001654 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001655 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001656 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001657
asaperssonfab67072017-04-04 05:51:49 -07001658 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001659 EXPECT_EQ(std::numeric_limits<int>::max(),
1660 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001661
asaperssonfab67072017-04-04 05:51:49 -07001662 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001663 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001664 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001665 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001666
asapersson02465b82017-04-10 01:12:52 -07001667 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001668 EXPECT_EQ(std::numeric_limits<int>::max(),
1669 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001670
mflodmancc3d4422017-08-03 08:27:51 -07001671 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001672}
1673
mflodmancc3d4422017-08-03 08:27:51 -07001674TEST_F(VideoStreamEncoderTest,
1675 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001676 const int kWidth = 1280;
1677 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001678 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1679 DataRate::Zero(), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001680
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001681 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001682 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001683 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001684 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001685
1686 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001687 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001688 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001689 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1690 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1691
1692 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001693 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001694 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001695 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1696 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1697 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1698
1699 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001700 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001701 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1702 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1703 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1704
mflodmancc3d4422017-08-03 08:27:51 -07001705 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001706}
1707
mflodmancc3d4422017-08-03 08:27:51 -07001708TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001709 const int kWidth = 1280;
1710 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001711 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1712 DataRate::Zero(), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001713
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001714 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001715 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001716 video_stream_encoder_->SetSource(&source,
1717 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001718 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1719 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001720 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001721
1722 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001723 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001724 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1725 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1726 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1727 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1728
1729 // Trigger adapt down for same input resolution, expect no change.
1730 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1731 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001732 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001733 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1734 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1735 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1736
1737 // Trigger adapt down for larger input resolution, expect no change.
1738 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1739 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001740 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001741 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1742 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1743 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1744
mflodmancc3d4422017-08-03 08:27:51 -07001745 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001746}
1747
mflodmancc3d4422017-08-03 08:27:51 -07001748TEST_F(VideoStreamEncoderTest,
1749 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001750 const int kWidth = 1280;
1751 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001752 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1753 DataRate::Zero(), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001754
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001755 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001756 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001757 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001758 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001759
1760 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001761 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001762 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001763 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1764 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1765
1766 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001767 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001768 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001769 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1770 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1771
mflodmancc3d4422017-08-03 08:27:51 -07001772 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001773}
1774
mflodmancc3d4422017-08-03 08:27:51 -07001775TEST_F(VideoStreamEncoderTest,
1776 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001777 const int kWidth = 1280;
1778 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001779 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1780 DataRate::Zero(), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001781
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001782 // Enable MAINTAIN_RESOLUTION preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001783 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001784 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001785 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
asapersson02465b82017-04-10 01:12:52 -07001786
1787 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001788 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001789 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001790 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001791 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1792
1793 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001794 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001795 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001796 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001797 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1798
mflodmancc3d4422017-08-03 08:27:51 -07001799 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001800}
1801
mflodmancc3d4422017-08-03 08:27:51 -07001802TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001803 const int kWidth = 1280;
1804 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001805 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1806 DataRate::Zero(), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001807
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001808 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001809 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001810 video_stream_encoder_->SetSource(&source,
1811 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001812
1813 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1814 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001815 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001816 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1817 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1818 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1819
1820 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001821 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001822 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001823 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1824 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1825 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1826
mflodmancc3d4422017-08-03 08:27:51 -07001827 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001828}
1829
mflodmancc3d4422017-08-03 08:27:51 -07001830TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001831 const int kWidth = 1280;
1832 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001833 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1834 DataRate::Zero(), 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001835
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001836 // Enable DISABLED preference, no initial limitation.
asapersson09f05612017-05-15 23:40:18 -07001837 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001838 video_stream_encoder_->SetSource(&source,
1839 webrtc::DegradationPreference::DISABLED);
asapersson09f05612017-05-15 23:40:18 -07001840
1841 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1842 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001843 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001844 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1845 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1846 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1847
1848 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001849 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001850 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001851 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1852 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1853 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1854
mflodmancc3d4422017-08-03 08:27:51 -07001855 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001856}
1857
mflodmancc3d4422017-08-03 08:27:51 -07001858TEST_F(VideoStreamEncoderTest,
1859 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001860 const int kWidth = 1280;
1861 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001862 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1863 DataRate::Zero(), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001864
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001865 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001866 AdaptingFrameForwarder source;
1867 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001868 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001869 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001870
1871 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001872 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001873 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001874 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1875 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1876
1877 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001878 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001879 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001880 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001881 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001882 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1883 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1884
1885 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001886 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001887 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001888 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1889 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1890 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1891
mflodmancc3d4422017-08-03 08:27:51 -07001892 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001893}
1894
mflodmancc3d4422017-08-03 08:27:51 -07001895TEST_F(VideoStreamEncoderTest,
1896 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001897 const int kWidth = 1280;
1898 const int kHeight = 720;
1899 const int kInputFps = 30;
Erik Språng610c7632019-03-06 15:37:33 +01001900 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1901 DataRate::Zero(), 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001902
1903 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1904 stats.input_frame_rate = kInputFps;
1905 stats_proxy_->SetMockStats(stats);
1906
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001907 // Expect no scaling to begin with (preference: MAINTAIN_FRAMERATE).
asapersson09f05612017-05-15 23:40:18 -07001908 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1909 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001910 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001911
1912 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001913 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001914 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1915 sink_.WaitForEncodedFrame(2);
1916 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1917
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001918 // Enable MAINTAIN_RESOLUTION preference.
asapersson09f05612017-05-15 23:40:18 -07001919 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001920 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001921 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001922 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001923
1924 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001925 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001926 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1927 sink_.WaitForEncodedFrame(3);
1928 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1929
1930 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001931 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001932 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001933
mflodmancc3d4422017-08-03 08:27:51 -07001934 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001935}
1936
mflodmancc3d4422017-08-03 08:27:51 -07001937TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001938 const int kWidth = 1280;
1939 const int kHeight = 720;
1940 const size_t kNumFrames = 10;
1941
Erik Språng610c7632019-03-06 15:37:33 +01001942 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1943 DataRate::Zero(), 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001944
asaperssond0de2952017-04-21 01:47:31 -07001945 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001946 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001947 video_source_.set_adaptation_enabled(true);
1948
1949 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1950 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1951
1952 int downscales = 0;
1953 for (size_t i = 1; i <= kNumFrames; i++) {
Åsa Persson8c1bf952018-09-13 10:42:19 +02001954 video_source_.IncomingCapturedFrame(
1955 CreateFrame(i * kFrameIntervalMs, kWidth, kHeight));
1956 WaitForEncodedFrame(i * kFrameIntervalMs);
asaperssond0de2952017-04-21 01:47:31 -07001957
asaperssonfab67072017-04-04 05:51:49 -07001958 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001959 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001960 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001961 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001962
1963 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1964 ++downscales;
1965
1966 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1967 EXPECT_EQ(downscales,
1968 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1969 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001970 }
mflodmancc3d4422017-08-03 08:27:51 -07001971 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001972}
1973
mflodmancc3d4422017-08-03 08:27:51 -07001974TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001975 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1976 const int kWidth = 1280;
1977 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001978 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1979 DataRate::Zero(), 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001980
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001981 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001982 AdaptingFrameForwarder source;
1983 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001984 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001985 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001986
Åsa Persson8c1bf952018-09-13 10:42:19 +02001987 int64_t timestamp_ms = kFrameIntervalMs;
1988 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001989 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001990 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001991 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1992 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1993
1994 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001995 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001996 timestamp_ms += kFrameIntervalMs;
1997 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
1998 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07001999 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002000 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2001 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2002
2003 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002004 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002005 timestamp_ms += kFrameIntervalMs;
2006 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002007 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002008 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002009 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2010 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2011
2012 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002013 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002014 timestamp_ms += kFrameIntervalMs;
2015 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2016 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002017 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002018 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2019 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2020
2021 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002022 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002023 timestamp_ms += kFrameIntervalMs;
2024 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asapersson09f05612017-05-15 23:40:18 -07002025 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002026 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002027 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2028 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2029
mflodmancc3d4422017-08-03 08:27:51 -07002030 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002031}
2032
mflodmancc3d4422017-08-03 08:27:51 -07002033TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07002034 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
2035 const int kWidth = 1280;
2036 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01002037 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2038 DataRate::Zero(), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002039
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002040 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002041 AdaptingFrameForwarder source;
2042 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002043 video_stream_encoder_->SetSource(&source,
2044 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002045
Åsa Persson8c1bf952018-09-13 10:42:19 +02002046 int64_t timestamp_ms = kFrameIntervalMs;
2047 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07002048 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002049 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002050 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2051 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2052
2053 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002054 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002055 timestamp_ms += kFrameIntervalMs;
2056 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2057 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002058 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2059 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2060 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2061
2062 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002063 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002064 timestamp_ms += kFrameIntervalMs;
2065 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07002066 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002067 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002068 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2069 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2070
2071 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002072 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002073 timestamp_ms += kFrameIntervalMs;
2074 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2075 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002076 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2077 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2078 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2079
2080 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002081 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002082 timestamp_ms += kFrameIntervalMs;
2083 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07002084 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002085 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002086 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2087 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2088
mflodmancc3d4422017-08-03 08:27:51 -07002089 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002090}
2091
mflodmancc3d4422017-08-03 08:27:51 -07002092TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002093 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
2094 const int kWidth = 1280;
2095 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01002096 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2097 DataRate::Zero(), 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002098
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002099 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002100 AdaptingFrameForwarder source;
2101 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002102 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002103 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002104
Åsa Persson8c1bf952018-09-13 10:42:19 +02002105 int64_t timestamp_ms = kFrameIntervalMs;
2106 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002107 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002108 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002109 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2110 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2111 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2112 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2113
2114 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002115 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002116 timestamp_ms += kFrameIntervalMs;
2117 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2118 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002119 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002120 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2121 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2122 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2123 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2124
2125 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07002126 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002127 timestamp_ms += kFrameIntervalMs;
2128 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2129 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002130 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002131 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2132 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2133 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2134 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2135
Jonathan Yubc771b72017-12-08 17:04:29 -08002136 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002137 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002138 timestamp_ms += kFrameIntervalMs;
2139 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2140 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002141 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002142 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2143 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002144 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002145 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2146
Jonathan Yubc771b72017-12-08 17:04:29 -08002147 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07002148 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002149 timestamp_ms += kFrameIntervalMs;
2150 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2151 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002152 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002153 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07002154 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2155 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2156 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2157 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2158
Jonathan Yubc771b72017-12-08 17:04:29 -08002159 // Trigger quality adapt down, expect no change (min resolution reached).
2160 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002161 timestamp_ms += kFrameIntervalMs;
2162 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2163 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002164 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
2165 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2166 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2167 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2168 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2169
2170 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002171 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002172 timestamp_ms += kFrameIntervalMs;
2173 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2174 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002175 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002176 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2177 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2178 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2179 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2180
2181 // Trigger cpu adapt up, expect upscaled resolution (640x360).
2182 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002183 timestamp_ms += kFrameIntervalMs;
2184 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2185 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002186 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2187 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2188 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2189 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2190 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2191
2192 // Trigger cpu adapt up, expect upscaled resolution (960x540).
2193 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002194 timestamp_ms += kFrameIntervalMs;
2195 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2196 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002197 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002198 last_wants = source.sink_wants();
2199 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2200 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002201 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002202 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2203
2204 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002205 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002206 timestamp_ms += kFrameIntervalMs;
2207 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2208 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002209 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002210 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2211 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002212 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002213 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2214
2215 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002216 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002217 timestamp_ms += kFrameIntervalMs;
2218 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002219 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002220 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002221 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002222 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2223 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002224 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002225 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002226
mflodmancc3d4422017-08-03 08:27:51 -07002227 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002228}
2229
mflodmancc3d4422017-08-03 08:27:51 -07002230TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002231 const int kWidth = 640;
2232 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002233
Erik Språng610c7632019-03-06 15:37:33 +01002234 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2235 DataRate::Zero(), 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002236
perkj803d97f2016-11-01 11:45:46 -07002237 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002238 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002239 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002240 }
2241
mflodmancc3d4422017-08-03 08:27:51 -07002242 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002243 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002244 video_source_.IncomingCapturedFrame(CreateFrame(
2245 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002246 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002247 }
2248
mflodmancc3d4422017-08-03 08:27:51 -07002249 video_stream_encoder_->Stop();
2250 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002251 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002252
perkj803d97f2016-11-01 11:45:46 -07002253 EXPECT_EQ(1,
2254 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2255 EXPECT_EQ(
2256 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2257}
2258
mflodmancc3d4422017-08-03 08:27:51 -07002259TEST_F(VideoStreamEncoderTest,
2260 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
Erik Språng610c7632019-03-06 15:37:33 +01002261 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2262 DataRate::Zero(), 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002263 const int kWidth = 640;
2264 const int kHeight = 360;
2265
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002266 video_stream_encoder_->SetSource(&video_source_,
2267 webrtc::DegradationPreference::DISABLED);
asaperssonf4e44af2017-04-19 02:01:06 -07002268
2269 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2270 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002271 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002272 }
2273
mflodmancc3d4422017-08-03 08:27:51 -07002274 video_stream_encoder_->Stop();
2275 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002276 stats_proxy_.reset();
2277
2278 EXPECT_EQ(0,
2279 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2280}
2281
mflodmancc3d4422017-08-03 08:27:51 -07002282TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002283 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02002284 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002285
2286 const int kDefaultFps = 30;
Erik Språng566124a2018-04-23 12:32:22 +02002287 const VideoBitrateAllocation expected_bitrate =
sprang57c2fff2017-01-16 06:24:02 -08002288 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002289 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002290
sprang57c2fff2017-01-16 06:24:02 -08002291 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
Niels Möller6bb5ab92019-01-11 11:11:10 +01002292 .Times(1);
Erik Språng610c7632019-03-06 15:37:33 +01002293 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kLowTargetBitrateBps),
2294 DataRate::Zero(), 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002295
sprang57c2fff2017-01-16 06:24:02 -08002296 video_source_.IncomingCapturedFrame(
Erik Språngd7329ca2019-02-21 21:19:53 +01002297 CreateFrame(rtc::TimeMillis(), codec_width_, codec_height_));
2298 WaitForEncodedFrame(rtc::TimeMillis());
2299 absl::optional<VideoBitrateAllocation> bitrate_allocation =
2300 fake_encoder_.GetAndResetLastBitrateAllocation();
2301 // Check that encoder has been updated too, not just allocation observer.
2302 EXPECT_EQ(bitrate_allocation->get_sum_bps(), kLowTargetBitrateBps);
2303 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec / kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002304
2305 // Not called on second frame.
2306 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2307 .Times(0);
2308 video_source_.IncomingCapturedFrame(
Erik Språngd7329ca2019-02-21 21:19:53 +01002309 CreateFrame(rtc::TimeMillis(), codec_width_, codec_height_));
2310 WaitForEncodedFrame(rtc::TimeMillis());
2311 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec / kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002312
2313 // Called after a process interval.
2314 const int64_t kProcessIntervalMs =
2315 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang57c2fff2017-01-16 06:24:02 -08002316 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2317 .Times(1);
Erik Språngd7329ca2019-02-21 21:19:53 +01002318 const int64_t start_time_ms = rtc::TimeMillis();
2319 while (rtc::TimeMillis() - start_time_ms < kProcessIntervalMs) {
2320 video_source_.IncomingCapturedFrame(
2321 CreateFrame(rtc::TimeMillis(), codec_width_, codec_height_));
2322 WaitForEncodedFrame(rtc::TimeMillis());
2323 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec / kDefaultFps);
2324 }
2325
2326 // Since rates are unchanged, encoder should not be reconfigured.
2327 EXPECT_FALSE(fake_encoder_.GetAndResetLastBitrateAllocation().has_value());
sprang57c2fff2017-01-16 06:24:02 -08002328
mflodmancc3d4422017-08-03 08:27:51 -07002329 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002330}
2331
Niels Möller7dc26b72017-12-06 10:27:48 +01002332TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2333 const int kFrameWidth = 1280;
2334 const int kFrameHeight = 720;
2335 const int kFramerate = 24;
2336
Erik Språng610c7632019-03-06 15:37:33 +01002337 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2338 DataRate::Zero(), 0, 0);
Niels Möller7dc26b72017-12-06 10:27:48 +01002339 test::FrameForwarder source;
2340 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002341 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002342
2343 // Insert a single frame, triggering initial configuration.
2344 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2345 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2346
2347 EXPECT_EQ(
2348 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2349 kDefaultFramerate);
2350
2351 // Trigger reconfigure encoder (without resetting the entire instance).
2352 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002353 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002354 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2355 video_encoder_config.number_of_streams = 1;
2356 video_encoder_config.video_stream_factory =
2357 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2358 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002359 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002360 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2361
2362 // Detector should be updated with fps limit from codec config.
2363 EXPECT_EQ(
2364 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2365 kFramerate);
2366
2367 // Trigger overuse, max framerate should be reduced.
2368 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2369 stats.input_frame_rate = kFramerate;
2370 stats_proxy_->SetMockStats(stats);
2371 video_stream_encoder_->TriggerCpuOveruse();
2372 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2373 int adapted_framerate =
2374 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2375 EXPECT_LT(adapted_framerate, kFramerate);
2376
2377 // Trigger underuse, max framerate should go back to codec configured fps.
2378 // Set extra low fps, to make sure it's actually reset, not just incremented.
2379 stats = stats_proxy_->GetStats();
2380 stats.input_frame_rate = adapted_framerate / 2;
2381 stats_proxy_->SetMockStats(stats);
2382 video_stream_encoder_->TriggerCpuNormalUsage();
2383 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2384 EXPECT_EQ(
2385 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2386 kFramerate);
2387
2388 video_stream_encoder_->Stop();
2389}
2390
2391TEST_F(VideoStreamEncoderTest,
2392 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2393 const int kFrameWidth = 1280;
2394 const int kFrameHeight = 720;
2395 const int kLowFramerate = 15;
2396 const int kHighFramerate = 25;
2397
Erik Språng610c7632019-03-06 15:37:33 +01002398 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2399 DataRate::Zero(), 0, 0);
Niels Möller7dc26b72017-12-06 10:27:48 +01002400 test::FrameForwarder source;
2401 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002402 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002403
2404 // Trigger initial configuration.
2405 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002406 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002407 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2408 video_encoder_config.number_of_streams = 1;
2409 video_encoder_config.video_stream_factory =
2410 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2411 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2412 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002413 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002414 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2415
2416 EXPECT_EQ(
2417 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2418 kLowFramerate);
2419
2420 // Trigger overuse, max framerate should be reduced.
2421 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2422 stats.input_frame_rate = kLowFramerate;
2423 stats_proxy_->SetMockStats(stats);
2424 video_stream_encoder_->TriggerCpuOveruse();
2425 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2426 int adapted_framerate =
2427 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2428 EXPECT_LT(adapted_framerate, kLowFramerate);
2429
2430 // Reconfigure the encoder with a new (higher max framerate), max fps should
2431 // still respect the adaptation.
2432 video_encoder_config.video_stream_factory =
2433 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2434 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2435 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002436 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002437 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2438
2439 EXPECT_EQ(
2440 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2441 adapted_framerate);
2442
2443 // Trigger underuse, max framerate should go back to codec configured fps.
2444 stats = stats_proxy_->GetStats();
2445 stats.input_frame_rate = adapted_framerate;
2446 stats_proxy_->SetMockStats(stats);
2447 video_stream_encoder_->TriggerCpuNormalUsage();
2448 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2449 EXPECT_EQ(
2450 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2451 kHighFramerate);
2452
2453 video_stream_encoder_->Stop();
2454}
2455
mflodmancc3d4422017-08-03 08:27:51 -07002456TEST_F(VideoStreamEncoderTest,
2457 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002458 const int kFrameWidth = 1280;
2459 const int kFrameHeight = 720;
2460 const int kFramerate = 24;
2461
Erik Språng610c7632019-03-06 15:37:33 +01002462 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2463 DataRate::Zero(), 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002464 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002465 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002466 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangfda496a2017-06-15 04:21:07 -07002467
2468 // Trigger initial configuration.
2469 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002470 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002471 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2472 video_encoder_config.number_of_streams = 1;
2473 video_encoder_config.video_stream_factory =
2474 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2475 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002476 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002477 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002478 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002479
Niels Möller7dc26b72017-12-06 10:27:48 +01002480 EXPECT_EQ(
2481 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2482 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002483
2484 // Trigger overuse, max framerate should be reduced.
2485 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2486 stats.input_frame_rate = kFramerate;
2487 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002488 video_stream_encoder_->TriggerCpuOveruse();
2489 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002490 int adapted_framerate =
2491 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002492 EXPECT_LT(adapted_framerate, kFramerate);
2493
2494 // Change degradation preference to not enable framerate scaling. Target
2495 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002496 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002497 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -07002498 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002499 EXPECT_EQ(
2500 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2501 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002502
mflodmancc3d4422017-08-03 08:27:51 -07002503 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002504}
2505
mflodmancc3d4422017-08-03 08:27:51 -07002506TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002507 const int kTooLowBitrateForFrameSizeBps = 10000;
Erik Språng610c7632019-03-06 15:37:33 +01002508 video_stream_encoder_->OnBitrateUpdated(
2509 DataRate::bps(kTooLowBitrateForFrameSizeBps), DataRate::Zero(), 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002510 const int kWidth = 640;
2511 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002512
asaperssonfab67072017-04-04 05:51:49 -07002513 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002514
2515 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002516 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002517
2518 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002519 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002520
sprangc5d62e22017-04-02 23:53:04 -07002521 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002522
asaperssonfab67072017-04-04 05:51:49 -07002523 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002524 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002525 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002526
2527 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002528 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002529
sprangc5d62e22017-04-02 23:53:04 -07002530 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002531
mflodmancc3d4422017-08-03 08:27:51 -07002532 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002533}
2534
mflodmancc3d4422017-08-03 08:27:51 -07002535TEST_F(VideoStreamEncoderTest,
2536 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002537 const int kTooLowBitrateForFrameSizeBps = 10000;
Erik Språng610c7632019-03-06 15:37:33 +01002538 video_stream_encoder_->OnBitrateUpdated(
2539 DataRate::bps(kTooLowBitrateForFrameSizeBps), DataRate::Zero(), 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002540 const int kWidth = 640;
2541 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002542
2543 // We expect the n initial frames to get dropped.
2544 int i;
2545 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002546 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002547 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002548 }
2549 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002550 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002551 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002552
2553 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002554 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002555
mflodmancc3d4422017-08-03 08:27:51 -07002556 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002557}
2558
mflodmancc3d4422017-08-03 08:27:51 -07002559TEST_F(VideoStreamEncoderTest,
2560 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002561 const int kWidth = 640;
2562 const int kHeight = 360;
Erik Språng610c7632019-03-06 15:37:33 +01002563 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kLowTargetBitrateBps),
2564 DataRate::Zero(), 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002565
2566 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002567 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002568 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason2bc68642017-02-07 07:02:22 -08002569
asaperssonfab67072017-04-04 05:51:49 -07002570 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002571 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002572 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002573
mflodmancc3d4422017-08-03 08:27:51 -07002574 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002575}
2576
mflodmancc3d4422017-08-03 08:27:51 -07002577TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002578 const int kWidth = 640;
2579 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002580 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02002581
2582 VideoEncoderConfig video_encoder_config;
2583 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
2584 // Make format different, to force recreation of encoder.
2585 video_encoder_config.video_format.parameters["foo"] = "foo";
2586 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002587 kMaxPayloadLength);
Erik Språng610c7632019-03-06 15:37:33 +01002588 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kLowTargetBitrateBps),
2589 DataRate::Zero(), 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002590
kthelgasonb83797b2017-02-14 11:57:25 -08002591 // Force quality scaler reconfiguration by resetting the source.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002592 video_stream_encoder_->SetSource(&video_source_,
2593 webrtc::DegradationPreference::BALANCED);
kthelgasonad9010c2017-02-14 00:46:51 -08002594
asaperssonfab67072017-04-04 05:51:49 -07002595 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002596 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002597 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002598
mflodmancc3d4422017-08-03 08:27:51 -07002599 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002600 fake_encoder_.SetQualityScaling(true);
2601}
2602
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002603TEST_F(VideoStreamEncoderTest, InitialFrameDropActivatesWhenBWEstimateReady) {
2604 webrtc::test::ScopedFieldTrials field_trials(
2605 "WebRTC-InitialFramedrop/Enabled/");
2606 // Reset encoder for field trials to take effect.
2607 ConfigureEncoder(video_encoder_config_.Copy());
2608 const int kTooLowBitrateForFrameSizeBps = 10000;
2609 const int kWidth = 640;
2610 const int kHeight = 360;
2611
Erik Språng610c7632019-03-06 15:37:33 +01002612 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2613 DataRate::Zero(), 0, 0);
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002614 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2615 // Frame should not be dropped.
2616 WaitForEncodedFrame(1);
2617
Erik Språng610c7632019-03-06 15:37:33 +01002618 video_stream_encoder_->OnBitrateUpdated(
2619 DataRate::bps(kTooLowBitrateForFrameSizeBps), DataRate::Zero(), 0, 0);
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002620 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
2621 // Expect to drop this frame, the wait should time out.
2622 ExpectDroppedFrame();
2623
2624 // Expect the sink_wants to specify a scaled frame.
2625 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
2626 video_stream_encoder_->Stop();
2627}
2628
mflodmancc3d4422017-08-03 08:27:51 -07002629TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002630 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2631 const int kTooSmallWidth = 10;
2632 const int kTooSmallHeight = 10;
Erik Språng610c7632019-03-06 15:37:33 +01002633 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2634 DataRate::Zero(), 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002635
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002636 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002637 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002638 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002639 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002640 VerifyNoLimitation(source.sink_wants());
2641 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2642
2643 // Trigger adapt down, too small frame, expect no change.
2644 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002645 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002646 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002647 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002648 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2649 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2650
mflodmancc3d4422017-08-03 08:27:51 -07002651 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002652}
2653
mflodmancc3d4422017-08-03 08:27:51 -07002654TEST_F(VideoStreamEncoderTest,
2655 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002656 const int kTooSmallWidth = 10;
2657 const int kTooSmallHeight = 10;
2658 const int kFpsLimit = 7;
Erik Språng610c7632019-03-06 15:37:33 +01002659 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2660 DataRate::Zero(), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002661
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002662 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002663 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002664 video_stream_encoder_->SetSource(&source,
2665 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002666 VerifyNoLimitation(source.sink_wants());
2667 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2668 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2669
2670 // Trigger adapt down, expect limited framerate.
2671 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002672 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002673 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002674 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2675 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2676 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2677 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2678
2679 // Trigger adapt down, too small frame, expect no change.
2680 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002681 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002682 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002683 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2684 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2685 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2686 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2687
mflodmancc3d4422017-08-03 08:27:51 -07002688 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002689}
2690
mflodmancc3d4422017-08-03 08:27:51 -07002691TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002692 fake_encoder_.ForceInitEncodeFailure(true);
Erik Språng610c7632019-03-06 15:37:33 +01002693 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2694 DataRate::Zero(), 0, 0);
Niels Möllerf1338562018-04-26 09:51:47 +02002695 ResetEncoder("VP8", 2, 1, 1, false);
asapersson02465b82017-04-10 01:12:52 -07002696 const int kFrameWidth = 1280;
2697 const int kFrameHeight = 720;
2698 video_source_.IncomingCapturedFrame(
2699 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002700 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002701 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002702}
2703
sprangb1ca0732017-02-01 08:38:12 -08002704// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002705TEST_F(VideoStreamEncoderTest,
2706 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
Erik Språng610c7632019-03-06 15:37:33 +01002707 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2708 DataRate::Zero(), 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002709
2710 const int kFrameWidth = 1280;
2711 const int kFrameHeight = 720;
2712 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002713 // requested by
2714 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002715 video_source_.set_adaptation_enabled(true);
2716
2717 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002718 CreateFrame(1 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002719 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002720
2721 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002722 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002723 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002724 CreateFrame(2 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002725 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002726
asaperssonfab67072017-04-04 05:51:49 -07002727 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002728 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002729 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002730 CreateFrame(3 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002731 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002732
mflodmancc3d4422017-08-03 08:27:51 -07002733 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002734}
sprangfe627f32017-03-29 08:24:59 -07002735
mflodmancc3d4422017-08-03 08:27:51 -07002736TEST_F(VideoStreamEncoderTest,
2737 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002738 const int kFrameWidth = 1280;
2739 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07002740
Erik Språng610c7632019-03-06 15:37:33 +01002741 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2742 DataRate::Zero(), 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -07002743 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002744 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002745 video_source_.set_adaptation_enabled(true);
2746
sprang4847ae62017-06-27 07:06:52 -07002747 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002748
2749 video_source_.IncomingCapturedFrame(
2750 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002751 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002752
2753 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002754 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002755
2756 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002757 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002758 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002759 video_source_.IncomingCapturedFrame(
2760 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002761 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002762 }
2763
2764 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002765 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002766 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002767 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002768 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002769 video_source_.IncomingCapturedFrame(
2770 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002771 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002772 ++num_frames_dropped;
2773 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002774 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002775 }
2776 }
2777
sprang4847ae62017-06-27 07:06:52 -07002778 // Add some slack to account for frames dropped by the frame dropper.
2779 const int kErrorMargin = 1;
2780 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002781 kErrorMargin);
2782
2783 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002784 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002785 num_frames_dropped = 0;
Åsa Persson8c1bf952018-09-13 10:42:19 +02002786 for (int i = 0; i <= max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002787 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002788 video_source_.IncomingCapturedFrame(
2789 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002790 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002791 ++num_frames_dropped;
2792 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002793 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002794 }
2795 }
sprang4847ae62017-06-27 07:06:52 -07002796 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002797 kErrorMargin);
2798
2799 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002800 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002801 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002802 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002803 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002804 video_source_.IncomingCapturedFrame(
2805 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002806 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002807 ++num_frames_dropped;
2808 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002809 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002810 }
2811 }
sprang4847ae62017-06-27 07:06:52 -07002812 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002813 kErrorMargin);
2814
2815 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002816 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002817 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002818 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002819 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002820 video_source_.IncomingCapturedFrame(
2821 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002822 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002823 ++num_frames_dropped;
2824 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002825 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002826 }
2827 }
2828 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2829
mflodmancc3d4422017-08-03 08:27:51 -07002830 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002831}
2832
mflodmancc3d4422017-08-03 08:27:51 -07002833TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002834 const int kFramerateFps = 5;
2835 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002836 const int kFrameWidth = 1280;
2837 const int kFrameHeight = 720;
2838
sprang4847ae62017-06-27 07:06:52 -07002839 // Reconfigure encoder with two temporal layers and screensharing, which will
2840 // disable frame dropping and make testing easier.
Niels Möllerf1338562018-04-26 09:51:47 +02002841 ResetEncoder("VP8", 1, 2, 1, true);
sprang4847ae62017-06-27 07:06:52 -07002842
Erik Språng610c7632019-03-06 15:37:33 +01002843 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2844 DataRate::Zero(), 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -07002845 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002846 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002847 video_source_.set_adaptation_enabled(true);
2848
sprang4847ae62017-06-27 07:06:52 -07002849 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002850
2851 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08002852 rtc::VideoSinkWants last_wants;
2853 do {
2854 last_wants = video_source_.sink_wants();
2855
sprangc5d62e22017-04-02 23:53:04 -07002856 // Insert frames to get a new fps estimate...
2857 for (int j = 0; j < kFramerateFps; ++j) {
2858 video_source_.IncomingCapturedFrame(
2859 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08002860 if (video_source_.last_sent_width()) {
2861 sink_.WaitForEncodedFrame(timestamp_ms);
2862 }
sprangc5d62e22017-04-02 23:53:04 -07002863 timestamp_ms += kFrameIntervalMs;
Yves Gerey665174f2018-06-19 15:03:05 +02002864 fake_clock_.AdvanceTimeMicros(kFrameIntervalMs *
2865 rtc::kNumMicrosecsPerMillisec);
sprangc5d62e22017-04-02 23:53:04 -07002866 }
2867 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002868 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08002869 } while (video_source_.sink_wants().max_framerate_fps <
2870 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07002871
Jonathan Yubc771b72017-12-08 17:04:29 -08002872 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07002873
mflodmancc3d4422017-08-03 08:27:51 -07002874 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002875}
asaperssonf7e294d2017-06-13 23:25:22 -07002876
mflodmancc3d4422017-08-03 08:27:51 -07002877TEST_F(VideoStreamEncoderTest,
2878 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002879 const int kWidth = 1280;
2880 const int kHeight = 720;
2881 const int64_t kFrameIntervalMs = 150;
2882 int64_t timestamp_ms = kFrameIntervalMs;
Erik Språng610c7632019-03-06 15:37:33 +01002883 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2884 DataRate::Zero(), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002885
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002886 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002887 AdaptingFrameForwarder source;
2888 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002889 video_stream_encoder_->SetSource(&source,
2890 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002891 timestamp_ms += kFrameIntervalMs;
2892 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002893 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002894 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002895 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2896 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2897 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2898
2899 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002900 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002901 timestamp_ms += kFrameIntervalMs;
2902 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002903 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002904 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2905 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2906 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2907 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2908
2909 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002910 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002911 timestamp_ms += kFrameIntervalMs;
2912 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002913 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002914 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2915 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2916 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2917 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2918
2919 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002920 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002921 timestamp_ms += kFrameIntervalMs;
2922 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002923 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002924 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2925 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2926 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2927 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2928
2929 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002930 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002931 timestamp_ms += kFrameIntervalMs;
2932 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002933 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002934 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2935 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2936 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2937 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2938
2939 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002940 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002941 timestamp_ms += kFrameIntervalMs;
2942 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002943 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002944 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2945 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2946 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2947 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2948
2949 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002950 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002951 timestamp_ms += kFrameIntervalMs;
2952 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002953 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002954 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2955 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2956 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2957 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2958
2959 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002960 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002961 timestamp_ms += kFrameIntervalMs;
2962 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002963 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002964 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2965 rtc::VideoSinkWants last_wants = source.sink_wants();
2966 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2967 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2968 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2969
2970 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002971 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002972 timestamp_ms += kFrameIntervalMs;
2973 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002974 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002975 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2976 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2977 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2978 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2979
2980 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002981 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002982 timestamp_ms += kFrameIntervalMs;
2983 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002984 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002985 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2986 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2987 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2988 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2989
2990 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002991 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002992 timestamp_ms += kFrameIntervalMs;
2993 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002994 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002995 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2996 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2997 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2998 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2999
3000 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003001 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003002 timestamp_ms += kFrameIntervalMs;
3003 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003004 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003005 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
3006 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3007 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3008 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3009
3010 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003011 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003012 timestamp_ms += kFrameIntervalMs;
3013 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003014 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003015 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3016 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3017 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3018 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3019
3020 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003021 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003022 timestamp_ms += kFrameIntervalMs;
3023 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003024 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003025 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
3026 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3027 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3028 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3029
3030 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003031 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003032 timestamp_ms += kFrameIntervalMs;
3033 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003034 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003035 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3036 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3037 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3038 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3039
3040 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003041 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003042 timestamp_ms += kFrameIntervalMs;
3043 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003044 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003045 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02003046 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003047 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3048 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3049 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3050
3051 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003052 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003053 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003054 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3055
mflodmancc3d4422017-08-03 08:27:51 -07003056 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003057}
3058
mflodmancc3d4422017-08-03 08:27:51 -07003059TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07003060 const int kWidth = 1280;
3061 const int kHeight = 720;
3062 const int64_t kFrameIntervalMs = 150;
3063 int64_t timestamp_ms = kFrameIntervalMs;
Erik Språng610c7632019-03-06 15:37:33 +01003064 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3065 DataRate::Zero(), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07003066
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003067 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07003068 AdaptingFrameForwarder source;
3069 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003070 video_stream_encoder_->SetSource(&source,
3071 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07003072 timestamp_ms += kFrameIntervalMs;
3073 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003074 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003075 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003076 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3077 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3078 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3079 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3080 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3081 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3082
3083 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003084 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003085 timestamp_ms += kFrameIntervalMs;
3086 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003087 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003088 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
3089 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3090 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3091 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3092 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3093 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3094 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3095
3096 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003097 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003098 timestamp_ms += kFrameIntervalMs;
3099 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003100 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003101 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
3102 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3103 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3104 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3105 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3106 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3107 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3108
3109 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003110 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003111 timestamp_ms += kFrameIntervalMs;
3112 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003113 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003114 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
3115 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3116 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3117 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3118 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3119 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3120 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3121
3122 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003123 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003124 timestamp_ms += kFrameIntervalMs;
3125 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003126 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003127 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
3128 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3129 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3130 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3131 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3132 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3133 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3134
3135 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003136 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003137 timestamp_ms += kFrameIntervalMs;
3138 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003139 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003140 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3141 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3142 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3143 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3144 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3145 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3146 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3147
3148 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003149 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003150 timestamp_ms += kFrameIntervalMs;
3151 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003152 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003153 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02003154 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003155 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3156 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3157 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3158 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3159 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3160 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3161
3162 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003163 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003164 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003165 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3166 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3167
mflodmancc3d4422017-08-03 08:27:51 -07003168 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003169}
3170
mflodmancc3d4422017-08-03 08:27:51 -07003171TEST_F(VideoStreamEncoderTest,
3172 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07003173 const int kWidth = 640;
3174 const int kHeight = 360;
3175 const int kFpsLimit = 15;
3176 const int64_t kFrameIntervalMs = 150;
3177 int64_t timestamp_ms = kFrameIntervalMs;
Erik Språng610c7632019-03-06 15:37:33 +01003178 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3179 DataRate::Zero(), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07003180
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003181 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07003182 AdaptingFrameForwarder source;
3183 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003184 video_stream_encoder_->SetSource(&source,
3185 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07003186 timestamp_ms += kFrameIntervalMs;
3187 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003188 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003189 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003190 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3191 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3192 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3193 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3194 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3195 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3196
3197 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003198 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003199 timestamp_ms += kFrameIntervalMs;
3200 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003201 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003202 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
3203 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3204 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3205 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3206 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3207 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3208 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3209
3210 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003211 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003212 timestamp_ms += kFrameIntervalMs;
3213 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003214 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003215 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
3216 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3217 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3218 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3219 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3220 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3221 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3222
3223 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003224 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003225 timestamp_ms += kFrameIntervalMs;
3226 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003227 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003228 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3229 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3230 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3231 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3232 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3233 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3234 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3235
3236 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003237 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003238 timestamp_ms += kFrameIntervalMs;
3239 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003240 WaitForEncodedFrame(timestamp_ms);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003241 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003242 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3243 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3244 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3245 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3246 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3247 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3248
3249 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003250 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003251 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003252 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3253 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3254
mflodmancc3d4422017-08-03 08:27:51 -07003255 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003256}
3257
mflodmancc3d4422017-08-03 08:27:51 -07003258TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003259 // Simulates simulcast behavior and makes highest stream resolutions divisible
3260 // by 4.
3261 class CroppingVideoStreamFactory
3262 : public VideoEncoderConfig::VideoStreamFactoryInterface {
3263 public:
3264 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
3265 int framerate)
3266 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
3267 EXPECT_GT(num_temporal_layers, 0u);
3268 EXPECT_GT(framerate, 0);
3269 }
3270
3271 private:
3272 std::vector<VideoStream> CreateEncoderStreams(
3273 int width,
3274 int height,
3275 const VideoEncoderConfig& encoder_config) override {
Yves Gerey665174f2018-06-19 15:03:05 +02003276 std::vector<VideoStream> streams = test::CreateVideoStreams(
3277 width - width % 4, height - height % 4, encoder_config);
ilnik6b826ef2017-06-16 06:53:48 -07003278 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +01003279 stream.num_temporal_layers = num_temporal_layers_;
ilnik6b826ef2017-06-16 06:53:48 -07003280 stream.max_framerate = framerate_;
3281 }
3282 return streams;
3283 }
3284
3285 const size_t num_temporal_layers_;
3286 const int framerate_;
3287 };
3288
3289 const int kFrameWidth = 1920;
3290 const int kFrameHeight = 1080;
3291 // 3/4 of 1920.
3292 const int kAdaptedFrameWidth = 1440;
3293 // 3/4 of 1080 rounded down to multiple of 4.
3294 const int kAdaptedFrameHeight = 808;
3295 const int kFramerate = 24;
3296
Erik Språng610c7632019-03-06 15:37:33 +01003297 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3298 DataRate::Zero(), 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003299 // Trigger reconfigure encoder (without resetting the entire instance).
3300 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02003301 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07003302 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3303 video_encoder_config.number_of_streams = 1;
3304 video_encoder_config.video_stream_factory =
3305 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003306 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02003307 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07003308 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003309
3310 video_source_.set_adaptation_enabled(true);
3311
3312 video_source_.IncomingCapturedFrame(
3313 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003314 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003315
3316 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003317 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003318 video_source_.IncomingCapturedFrame(
3319 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003320 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003321
mflodmancc3d4422017-08-03 08:27:51 -07003322 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003323}
3324
mflodmancc3d4422017-08-03 08:27:51 -07003325TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003326 const int kFrameWidth = 1280;
3327 const int kFrameHeight = 720;
3328 const int kLowFps = 2;
3329 const int kHighFps = 30;
3330
Erik Språng610c7632019-03-06 15:37:33 +01003331 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3332 DataRate::Zero(), 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003333
3334 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3335 max_framerate_ = kLowFps;
3336
3337 // Insert 2 seconds of 2fps video.
3338 for (int i = 0; i < kLowFps * 2; ++i) {
3339 video_source_.IncomingCapturedFrame(
3340 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3341 WaitForEncodedFrame(timestamp_ms);
3342 timestamp_ms += 1000 / kLowFps;
3343 }
3344
3345 // Make sure encoder is updated with new target.
Erik Språng610c7632019-03-06 15:37:33 +01003346 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3347 DataRate::Zero(), 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003348 video_source_.IncomingCapturedFrame(
3349 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3350 WaitForEncodedFrame(timestamp_ms);
3351 timestamp_ms += 1000 / kLowFps;
3352
3353 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3354
3355 // Insert 30fps frames for just a little more than the forced update period.
3356 const int kVcmTimerIntervalFrames =
3357 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3358 const int kFrameIntervalMs = 1000 / kHighFps;
3359 max_framerate_ = kHighFps;
3360 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3361 video_source_.IncomingCapturedFrame(
3362 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3363 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3364 // be dropped if the encoder hans't been updated with the new higher target
3365 // framerate yet, causing it to overshoot the target bitrate and then
3366 // suffering the wrath of the media optimizer.
3367 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3368 timestamp_ms += kFrameIntervalMs;
3369 }
3370
3371 // Don expect correct measurement just yet, but it should be higher than
3372 // before.
3373 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3374
mflodmancc3d4422017-08-03 08:27:51 -07003375 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003376}
3377
mflodmancc3d4422017-08-03 08:27:51 -07003378TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003379 const int kFrameWidth = 1280;
3380 const int kFrameHeight = 720;
3381 const int kTargetBitrateBps = 1000000;
3382
3383 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02003384 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
Erik Språng610c7632019-03-06 15:37:33 +01003385 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3386 DataRate::Zero(), 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -07003387 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003388
3389 // Insert a first video frame, causes another bitrate update.
3390 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3391 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3392 video_source_.IncomingCapturedFrame(
3393 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3394 WaitForEncodedFrame(timestamp_ms);
3395
3396 // Next, simulate video suspension due to pacer queue overrun.
Erik Språng610c7632019-03-06 15:37:33 +01003397 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(0), DataRate::Zero(), 0,
3398 1);
sprang4847ae62017-06-27 07:06:52 -07003399
3400 // Skip ahead until a new periodic parameter update should have occured.
3401 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3402 fake_clock_.AdvanceTimeMicros(
3403 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3404 rtc::kNumMicrosecsPerMillisec);
3405
3406 // Bitrate observer should not be called.
3407 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3408 video_source_.IncomingCapturedFrame(
3409 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3410 ExpectDroppedFrame();
3411
mflodmancc3d4422017-08-03 08:27:51 -07003412 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003413}
ilnik6b826ef2017-06-16 06:53:48 -07003414
Niels Möller4db138e2018-04-19 09:04:13 +02003415TEST_F(VideoStreamEncoderTest,
3416 DefaultCpuAdaptationThresholdsForSoftwareEncoder) {
3417 const int kFrameWidth = 1280;
3418 const int kFrameHeight = 720;
3419 const CpuOveruseOptions default_options;
Erik Språng610c7632019-03-06 15:37:33 +01003420 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3421 DataRate::Zero(), 0, 0);
Niels Möller4db138e2018-04-19 09:04:13 +02003422 video_source_.IncomingCapturedFrame(
3423 CreateFrame(1, kFrameWidth, kFrameHeight));
3424 WaitForEncodedFrame(1);
3425 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3426 .low_encode_usage_threshold_percent,
3427 default_options.low_encode_usage_threshold_percent);
3428 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3429 .high_encode_usage_threshold_percent,
3430 default_options.high_encode_usage_threshold_percent);
3431 video_stream_encoder_->Stop();
3432}
3433
3434TEST_F(VideoStreamEncoderTest,
3435 HigherCpuAdaptationThresholdsForHardwareEncoder) {
3436 const int kFrameWidth = 1280;
3437 const int kFrameHeight = 720;
3438 CpuOveruseOptions hardware_options;
3439 hardware_options.low_encode_usage_threshold_percent = 150;
3440 hardware_options.high_encode_usage_threshold_percent = 200;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +01003441 fake_encoder_.SetIsHardwareAccelerated(true);
Niels Möller4db138e2018-04-19 09:04:13 +02003442
Erik Språng610c7632019-03-06 15:37:33 +01003443 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3444 DataRate::Zero(), 0, 0);
Niels Möller4db138e2018-04-19 09:04:13 +02003445 video_source_.IncomingCapturedFrame(
3446 CreateFrame(1, kFrameWidth, kFrameHeight));
3447 WaitForEncodedFrame(1);
3448 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3449 .low_encode_usage_threshold_percent,
3450 hardware_options.low_encode_usage_threshold_percent);
3451 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3452 .high_encode_usage_threshold_percent,
3453 hardware_options.high_encode_usage_threshold_percent);
3454 video_stream_encoder_->Stop();
3455}
3456
Niels Möller6bb5ab92019-01-11 11:11:10 +01003457TEST_F(VideoStreamEncoderTest, DropsFramesWhenEncoderOvershoots) {
3458 const int kFrameWidth = 320;
3459 const int kFrameHeight = 240;
3460 const int kFps = 30;
3461 const int kTargetBitrateBps = 120000;
3462 const int kNumFramesInRun = kFps * 5; // Runs of five seconds.
3463
Erik Språng610c7632019-03-06 15:37:33 +01003464 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3465 DataRate::Zero(), 0, 0);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003466
3467 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3468 max_framerate_ = kFps;
3469
3470 // Insert 3 seconds of video, verify number of drops with normal bitrate.
3471 fake_encoder_.SimulateOvershoot(1.0);
3472 int num_dropped = 0;
3473 for (int i = 0; i < kNumFramesInRun; ++i) {
3474 video_source_.IncomingCapturedFrame(
3475 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3476 // Wait up to two frame durations for a frame to arrive.
3477 if (!TimedWaitForEncodedFrame(timestamp_ms, 2 * 1000 / kFps)) {
3478 ++num_dropped;
3479 }
3480 timestamp_ms += 1000 / kFps;
3481 }
3482
Erik Språnga8d48ab2019-02-08 14:17:40 +01003483 // Framerate should be measured to be near the expected target rate.
3484 EXPECT_NEAR(fake_encoder_.GetLastFramerate(), kFps, 1);
3485
3486 // Frame drops should be within 5% of expected 0%.
3487 EXPECT_NEAR(num_dropped, 0, 5 * kNumFramesInRun / 100);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003488
3489 // Make encoder produce frames at double the expected bitrate during 3 seconds
3490 // of video, verify number of drops. Rate needs to be slightly changed in
3491 // order to force the rate to be reconfigured.
Erik Språng7ca375c2019-02-06 16:20:17 +01003492 double overshoot_factor = 2.0;
3493 if (RateControlSettings::ParseFromFieldTrials().UseEncoderBitrateAdjuster()) {
3494 // With bitrate adjuster, when need to overshoot even more to trigger
3495 // frame dropping.
3496 overshoot_factor *= 2;
3497 }
3498 fake_encoder_.SimulateOvershoot(overshoot_factor);
Erik Språng610c7632019-03-06 15:37:33 +01003499 video_stream_encoder_->OnBitrateUpdated(
3500 DataRate::bps(kTargetBitrateBps + 1000), DataRate::Zero(), 0, 0);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003501 num_dropped = 0;
3502 for (int i = 0; i < kNumFramesInRun; ++i) {
3503 video_source_.IncomingCapturedFrame(
3504 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3505 // Wait up to two frame durations for a frame to arrive.
3506 if (!TimedWaitForEncodedFrame(timestamp_ms, 2 * 1000 / kFps)) {
3507 ++num_dropped;
3508 }
3509 timestamp_ms += 1000 / kFps;
3510 }
3511
Erik Språng610c7632019-03-06 15:37:33 +01003512 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3513 DataRate::Zero(), 0, 0);
Erik Språnga8d48ab2019-02-08 14:17:40 +01003514
3515 // Target framerate should be still be near the expected target, despite
3516 // the frame drops.
3517 EXPECT_NEAR(fake_encoder_.GetLastFramerate(), kFps, 1);
3518
3519 // Frame drops should be within 5% of expected 50%.
3520 EXPECT_NEAR(num_dropped, kNumFramesInRun / 2, 5 * kNumFramesInRun / 100);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003521
3522 video_stream_encoder_->Stop();
3523}
3524
3525TEST_F(VideoStreamEncoderTest, ConfiguresCorrectFrameRate) {
3526 const int kFrameWidth = 320;
3527 const int kFrameHeight = 240;
3528 const int kActualInputFps = 24;
3529 const int kTargetBitrateBps = 120000;
3530
3531 ASSERT_GT(max_framerate_, kActualInputFps);
3532
3533 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3534 max_framerate_ = kActualInputFps;
Erik Språng610c7632019-03-06 15:37:33 +01003535 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3536 DataRate::Zero(), 0, 0);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003537
3538 // Insert 3 seconds of video, with an input fps lower than configured max.
3539 for (int i = 0; i < kActualInputFps * 3; ++i) {
3540 video_source_.IncomingCapturedFrame(
3541 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3542 // Wait up to two frame durations for a frame to arrive.
3543 WaitForEncodedFrame(timestamp_ms);
3544 timestamp_ms += 1000 / kActualInputFps;
3545 }
3546
3547 EXPECT_NEAR(kActualInputFps, fake_encoder_.GetLastFramerate(), 1);
3548
3549 video_stream_encoder_->Stop();
3550}
3551
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01003552TEST_F(VideoStreamEncoderTest, AccumulatesUpdateRectOnDroppedFrames) {
3553 VideoFrame::UpdateRect rect;
Erik Språng610c7632019-03-06 15:37:33 +01003554 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3555 DataRate::Zero(), 0, 0);
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01003556
3557 fake_encoder_.BlockNextEncode();
3558 video_source_.IncomingCapturedFrame(
3559 CreateFrameWithUpdatedPixel(1, nullptr, 0));
3560 WaitForEncodedFrame(1);
3561 // On the very first frame full update should be forced.
3562 rect = fake_encoder_.GetLastUpdateRect();
3563 EXPECT_EQ(rect.offset_x, 0);
3564 EXPECT_EQ(rect.offset_y, 0);
3565 EXPECT_EQ(rect.height, codec_height_);
3566 EXPECT_EQ(rect.width, codec_width_);
3567 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
3568 // call to ContinueEncode.
3569 video_source_.IncomingCapturedFrame(
3570 CreateFrameWithUpdatedPixel(2, nullptr, 1));
3571 ExpectDroppedFrame();
3572 video_source_.IncomingCapturedFrame(
3573 CreateFrameWithUpdatedPixel(3, nullptr, 10));
3574 ExpectDroppedFrame();
3575 fake_encoder_.ContinueEncode();
3576 WaitForEncodedFrame(3);
3577 // Updates to pixels 1 and 10 should be accumulated to one 10x1 rect.
3578 rect = fake_encoder_.GetLastUpdateRect();
3579 EXPECT_EQ(rect.offset_x, 1);
3580 EXPECT_EQ(rect.offset_y, 0);
3581 EXPECT_EQ(rect.width, 10);
3582 EXPECT_EQ(rect.height, 1);
3583
3584 video_source_.IncomingCapturedFrame(
3585 CreateFrameWithUpdatedPixel(4, nullptr, 0));
3586 WaitForEncodedFrame(4);
3587 // Previous frame was encoded, so no accumulation should happen.
3588 rect = fake_encoder_.GetLastUpdateRect();
3589 EXPECT_EQ(rect.offset_x, 0);
3590 EXPECT_EQ(rect.offset_y, 0);
3591 EXPECT_EQ(rect.width, 1);
3592 EXPECT_EQ(rect.height, 1);
3593
3594 video_stream_encoder_->Stop();
3595}
3596
Erik Språngd7329ca2019-02-21 21:19:53 +01003597TEST_F(VideoStreamEncoderTest, SetsFrameTypes) {
Erik Språng610c7632019-03-06 15:37:33 +01003598 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3599 DataRate::Zero(), 0, 0);
Erik Språngd7329ca2019-02-21 21:19:53 +01003600
3601 // First frame is always keyframe.
3602 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
3603 WaitForEncodedFrame(1);
3604 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
Niels Möller87e2d782019-03-07 10:18:23 +01003605 testing::ElementsAre(VideoFrameType{kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003606
3607 // Insert delta frame.
3608 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
3609 WaitForEncodedFrame(2);
3610 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
Niels Möller87e2d782019-03-07 10:18:23 +01003611 testing::ElementsAre(VideoFrameType{kVideoFrameDelta}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003612
3613 // Request next frame be a key-frame.
3614 video_stream_encoder_->SendKeyFrame();
3615 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
3616 WaitForEncodedFrame(3);
3617 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
Niels Möller87e2d782019-03-07 10:18:23 +01003618 testing::ElementsAre(VideoFrameType{kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003619
3620 video_stream_encoder_->Stop();
3621}
3622
3623TEST_F(VideoStreamEncoderTest, SetsFrameTypesSimulcast) {
3624 // Setup simulcast with three streams.
3625 ResetEncoder("VP8", 3, 1, 1, false);
Erik Språng610c7632019-03-06 15:37:33 +01003626 video_stream_encoder_->OnBitrateUpdated(
3627 DataRate::bps(kSimulcastTargetBitrateBps), DataRate::Zero(), 0, 0);
Erik Språngd7329ca2019-02-21 21:19:53 +01003628 // Wait for all three layers before triggering event.
3629 sink_.SetNumExpectedLayers(3);
3630
3631 // First frame is always keyframe.
3632 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
3633 WaitForEncodedFrame(1);
3634 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
3635 testing::ElementsAreArray(
3636 {kVideoFrameKey, kVideoFrameKey, kVideoFrameKey}));
3637
3638 // Insert delta frame.
3639 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
3640 WaitForEncodedFrame(2);
3641 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
3642 testing::ElementsAreArray(
3643 {kVideoFrameDelta, kVideoFrameDelta, kVideoFrameDelta}));
3644
3645 // Request next frame be a key-frame.
3646 // Only first stream is configured to produce key-frame.
3647 video_stream_encoder_->SendKeyFrame();
3648 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
3649 WaitForEncodedFrame(3);
3650 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
3651 testing::ElementsAreArray(
3652 {kVideoFrameKey, kVideoFrameDelta, kVideoFrameDelta}));
3653
3654 video_stream_encoder_->Stop();
3655}
3656
3657TEST_F(VideoStreamEncoderTest, RequestKeyframeInternalSource) {
3658 // Configure internal source factory and setup test again.
3659 encoder_factory_.SetHasInternalSource(true);
3660 ResetEncoder("VP8", 1, 1, 1, false);
Erik Språng610c7632019-03-06 15:37:33 +01003661 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3662 DataRate::Zero(), 0, 0);
Erik Språngd7329ca2019-02-21 21:19:53 +01003663
3664 // Call encoder directly, simulating internal source where encoded frame
3665 // callback in VideoStreamEncoder is called despite no OnFrame().
3666 fake_encoder_.InjectFrame(CreateFrame(1, nullptr), true);
3667 EXPECT_TRUE(WaitForFrame(kDefaultTimeoutMs));
3668 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
Niels Möller87e2d782019-03-07 10:18:23 +01003669 testing::ElementsAre(VideoFrameType{kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003670
Niels Möller87e2d782019-03-07 10:18:23 +01003671 const std::vector<VideoFrameType> kDeltaFrame = {kVideoFrameDelta};
Erik Språngd7329ca2019-02-21 21:19:53 +01003672 // Need to set timestamp manually since manually for injected frame.
3673 VideoFrame frame = CreateFrame(101, nullptr);
3674 frame.set_timestamp(101);
3675 fake_encoder_.InjectFrame(frame, false);
3676 EXPECT_TRUE(WaitForFrame(kDefaultTimeoutMs));
3677 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
Niels Möller87e2d782019-03-07 10:18:23 +01003678 testing::ElementsAre(VideoFrameType{kVideoFrameDelta}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003679
3680 // Request key-frame. The forces a dummy frame down into the encoder.
3681 fake_encoder_.ExpectNullFrame();
3682 video_stream_encoder_->SendKeyFrame();
3683 EXPECT_TRUE(WaitForFrame(kDefaultTimeoutMs));
3684 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
Niels Möller87e2d782019-03-07 10:18:23 +01003685 testing::ElementsAre(VideoFrameType{kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003686
3687 video_stream_encoder_->Stop();
3688}
Erik Språngb7cb7b52019-02-26 15:52:33 +01003689
3690TEST_F(VideoStreamEncoderTest, AdjustsTimestampInternalSource) {
3691 // Configure internal source factory and setup test again.
3692 encoder_factory_.SetHasInternalSource(true);
3693 ResetEncoder("VP8", 1, 1, 1, false);
Erik Språng610c7632019-03-06 15:37:33 +01003694 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3695 DataRate::Zero(), 0, 0);
Erik Språngb7cb7b52019-02-26 15:52:33 +01003696
3697 int64_t timestamp = 1;
3698 EncodedImage image;
3699 image.Allocate(kTargetBitrateBps / kDefaultFramerate / 8);
3700 image.capture_time_ms_ = ++timestamp;
3701 image.SetTimestamp(static_cast<uint32_t>(timestamp * 90));
3702 const int64_t kEncodeFinishDelayMs = 10;
3703 image.timing_.encode_start_ms = timestamp;
3704 image.timing_.encode_finish_ms = timestamp + kEncodeFinishDelayMs;
3705 fake_encoder_.InjectEncodedImage(image);
3706 // Wait for frame without incrementing clock.
3707 EXPECT_TRUE(sink_.WaitForFrame(kDefaultTimeoutMs));
3708 // Frame is captured kEncodeFinishDelayMs before it's encoded, so restored
3709 // capture timestamp should be kEncodeFinishDelayMs in the past.
3710 EXPECT_EQ(sink_.GetLastCaptureTimeMs(),
3711 fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec -
3712 kEncodeFinishDelayMs);
3713
3714 video_stream_encoder_->Stop();
3715}
perkj26091b12016-09-01 01:17:40 -07003716} // namespace webrtc