blob: ad4200b4439f8b82d38f9f67f05aa59c020b6d7a [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::_;
45using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080046
perkj803d97f2016-11-01 11:45:46 -070047namespace {
Åsa Persson8c1bf952018-09-13 10:42:19 +020048const int kMinPixelsPerFrame = 320 * 180;
49const int kMinFramerateFps = 2;
50const int kMinBalancedFramerateFps = 7;
51const int64_t kFrameTimeoutMs = 100;
asapersson5f7226f2016-11-25 04:37:00 -080052const size_t kMaxPayloadLength = 1440;
Erik Språngd7329ca2019-02-21 21:19:53 +010053const uint32_t kTargetBitrateBps = 1000000;
54const uint32_t kSimulcastTargetBitrateBps = 3150000;
55const uint32_t kLowTargetBitrateBps = kTargetBitrateBps / 10;
kthelgason2bc68642017-02-07 07:02:22 -080056const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070057const int kDefaultFramerate = 30;
Åsa Persson8c1bf952018-09-13 10:42:19 +020058const int64_t kFrameIntervalMs = rtc::kNumMillisecsPerSec / kDefaultFramerate;
asapersson5f7226f2016-11-25 04:37:00 -080059
perkj803d97f2016-11-01 11:45:46 -070060class TestBuffer : public webrtc::I420Buffer {
61 public:
62 TestBuffer(rtc::Event* event, int width, int height)
63 : I420Buffer(width, height), event_(event) {}
64
65 private:
66 friend class rtc::RefCountedObject<TestBuffer>;
67 ~TestBuffer() override {
68 if (event_)
69 event_->Set();
70 }
71 rtc::Event* const event_;
72};
73
Niels Möller7dc26b72017-12-06 10:27:48 +010074class CpuOveruseDetectorProxy : public OveruseFrameDetector {
75 public:
Niels Möllerd1f7eb62018-03-28 16:40:58 +020076 explicit CpuOveruseDetectorProxy(CpuOveruseMetricsObserver* metrics_observer)
77 : OveruseFrameDetector(metrics_observer),
Niels Möller7dc26b72017-12-06 10:27:48 +010078 last_target_framerate_fps_(-1) {}
79 virtual ~CpuOveruseDetectorProxy() {}
80
81 void OnTargetFramerateUpdated(int framerate_fps) override {
82 rtc::CritScope cs(&lock_);
83 last_target_framerate_fps_ = framerate_fps;
84 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
85 }
86
87 int GetLastTargetFramerate() {
88 rtc::CritScope cs(&lock_);
89 return last_target_framerate_fps_;
90 }
91
Niels Möller4db138e2018-04-19 09:04:13 +020092 CpuOveruseOptions GetOptions() { return options_; }
93
Niels Möller7dc26b72017-12-06 10:27:48 +010094 private:
95 rtc::CriticalSection lock_;
96 int last_target_framerate_fps_ RTC_GUARDED_BY(lock_);
97};
98
mflodmancc3d4422017-08-03 08:27:51 -070099class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -0700100 public:
Niels Möller213618e2018-07-24 09:29:58 +0200101 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
102 const VideoStreamEncoderSettings& settings)
Sebastian Jansson572c60f2019-03-04 18:30:41 +0100103 : VideoStreamEncoder(Clock::GetRealTimeClock(),
104 1 /* number_of_cores */,
Yves Gerey665174f2018-06-19 15:03:05 +0200105 stats_proxy,
106 settings,
Yves Gerey665174f2018-06-19 15:03:05 +0200107 std::unique_ptr<OveruseFrameDetector>(
108 overuse_detector_proxy_ =
Sebastian Jansson74682c12019-03-01 11:50:20 +0100109 new CpuOveruseDetectorProxy(stats_proxy)),
110 &GlobalTaskQueueFactory()) {}
perkj803d97f2016-11-01 11:45:46 -0700111
sprangb1ca0732017-02-01 08:38:12 -0800112 void PostTaskAndWait(bool down, AdaptReason reason) {
Niels Möllerc572ff32018-11-07 08:43:50 +0100113 rtc::Event event;
kthelgason876222f2016-11-29 01:44:11 -0800114 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800115 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700116 event.Set();
117 });
perkj070ba852017-02-16 15:46:27 -0800118 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700119 }
120
kthelgason2fc52542017-03-03 00:24:41 -0800121 // This is used as a synchronisation mechanism, to make sure that the
122 // encoder queue is not blocked before we start sending it frames.
123 void WaitUntilTaskQueueIsIdle() {
Niels Möllerc572ff32018-11-07 08:43:50 +0100124 rtc::Event event;
Yves Gerey665174f2018-06-19 15:03:05 +0200125 encoder_queue()->PostTask([&event] { event.Set(); });
kthelgason2fc52542017-03-03 00:24:41 -0800126 ASSERT_TRUE(event.Wait(5000));
127 }
128
sprangb1ca0732017-02-01 08:38:12 -0800129 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800130
sprangb1ca0732017-02-01 08:38:12 -0800131 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800132
sprangb1ca0732017-02-01 08:38:12 -0800133 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800134
sprangb1ca0732017-02-01 08:38:12 -0800135 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700136
Niels Möller7dc26b72017-12-06 10:27:48 +0100137 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700138};
139
asapersson5f7226f2016-11-25 04:37:00 -0800140class VideoStreamFactory
141 : public VideoEncoderConfig::VideoStreamFactoryInterface {
142 public:
sprangfda496a2017-06-15 04:21:07 -0700143 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
144 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800145 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700146 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800147 }
148
149 private:
150 std::vector<VideoStream> CreateEncoderStreams(
151 int width,
152 int height,
153 const VideoEncoderConfig& encoder_config) override {
154 std::vector<VideoStream> streams =
155 test::CreateVideoStreams(width, height, encoder_config);
156 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +0100157 stream.num_temporal_layers = num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700158 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800159 }
160 return streams;
161 }
sprangfda496a2017-06-15 04:21:07 -0700162
asapersson5f7226f2016-11-25 04:37:00 -0800163 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700164 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800165};
166
sprangb1ca0732017-02-01 08:38:12 -0800167class AdaptingFrameForwarder : public test::FrameForwarder {
168 public:
169 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700170 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800171
172 void set_adaptation_enabled(bool enabled) {
173 rtc::CritScope cs(&crit_);
174 adaptation_enabled_ = enabled;
175 }
176
asaperssonfab67072017-04-04 05:51:49 -0700177 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800178 rtc::CritScope cs(&crit_);
179 return adaptation_enabled_;
180 }
181
asapersson09f05612017-05-15 23:40:18 -0700182 rtc::VideoSinkWants last_wants() const {
183 rtc::CritScope cs(&crit_);
184 return last_wants_;
185 }
186
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200187 absl::optional<int> last_sent_width() const { return last_width_; }
188 absl::optional<int> last_sent_height() const { return last_height_; }
Jonathan Yubc771b72017-12-08 17:04:29 -0800189
sprangb1ca0732017-02-01 08:38:12 -0800190 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
191 int cropped_width = 0;
192 int cropped_height = 0;
193 int out_width = 0;
194 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700195 if (adaption_enabled()) {
196 if (adapter_.AdaptFrameResolution(
197 video_frame.width(), video_frame.height(),
198 video_frame.timestamp_us() * 1000, &cropped_width,
199 &cropped_height, &out_width, &out_height)) {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100200 VideoFrame adapted_frame =
201 VideoFrame::Builder()
202 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
203 nullptr, out_width, out_height))
204 .set_timestamp_rtp(99)
205 .set_timestamp_ms(99)
206 .set_rotation(kVideoRotation_0)
207 .build();
sprangc5d62e22017-04-02 23:53:04 -0700208 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
209 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800210 last_width_.emplace(adapted_frame.width());
211 last_height_.emplace(adapted_frame.height());
212 } else {
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200213 last_width_ = absl::nullopt;
214 last_height_ = absl::nullopt;
sprangc5d62e22017-04-02 23:53:04 -0700215 }
sprangb1ca0732017-02-01 08:38:12 -0800216 } else {
217 test::FrameForwarder::IncomingCapturedFrame(video_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800218 last_width_.emplace(video_frame.width());
219 last_height_.emplace(video_frame.height());
sprangb1ca0732017-02-01 08:38:12 -0800220 }
221 }
222
223 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
224 const rtc::VideoSinkWants& wants) override {
225 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700226 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700227 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
228 wants.max_pixel_count,
229 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800230 test::FrameForwarder::AddOrUpdateSink(sink, wants);
231 }
sprangb1ca0732017-02-01 08:38:12 -0800232 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700233 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
234 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200235 absl::optional<int> last_width_;
236 absl::optional<int> last_height_;
sprangb1ca0732017-02-01 08:38:12 -0800237};
sprangc5d62e22017-04-02 23:53:04 -0700238
Niels Möller213618e2018-07-24 09:29:58 +0200239// TODO(nisse): Mock only VideoStreamEncoderObserver.
sprangc5d62e22017-04-02 23:53:04 -0700240class MockableSendStatisticsProxy : public SendStatisticsProxy {
241 public:
242 MockableSendStatisticsProxy(Clock* clock,
243 const VideoSendStream::Config& config,
244 VideoEncoderConfig::ContentType content_type)
245 : SendStatisticsProxy(clock, config, content_type) {}
246
247 VideoSendStream::Stats GetStats() override {
248 rtc::CritScope cs(&lock_);
249 if (mock_stats_)
250 return *mock_stats_;
251 return SendStatisticsProxy::GetStats();
252 }
253
Niels Möller213618e2018-07-24 09:29:58 +0200254 int GetInputFrameRate() const override {
255 rtc::CritScope cs(&lock_);
256 if (mock_stats_)
257 return mock_stats_->input_frame_rate;
258 return SendStatisticsProxy::GetInputFrameRate();
259 }
sprangc5d62e22017-04-02 23:53:04 -0700260 void SetMockStats(const VideoSendStream::Stats& stats) {
261 rtc::CritScope cs(&lock_);
262 mock_stats_.emplace(stats);
263 }
264
265 void ResetMockStats() {
266 rtc::CritScope cs(&lock_);
267 mock_stats_.reset();
268 }
269
270 private:
271 rtc::CriticalSection lock_;
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200272 absl::optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700273};
274
sprang4847ae62017-06-27 07:06:52 -0700275class MockBitrateObserver : public VideoBitrateAllocationObserver {
276 public:
Erik Språng566124a2018-04-23 12:32:22 +0200277 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const VideoBitrateAllocation&));
sprang4847ae62017-06-27 07:06:52 -0700278};
279
perkj803d97f2016-11-01 11:45:46 -0700280} // namespace
281
mflodmancc3d4422017-08-03 08:27:51 -0700282class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700283 public:
284 static const int kDefaultTimeoutMs = 30 * 1000;
285
mflodmancc3d4422017-08-03 08:27:51 -0700286 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700287 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700288 codec_width_(320),
289 codec_height_(240),
Åsa Persson8c1bf952018-09-13 10:42:19 +0200290 max_framerate_(kDefaultFramerate),
perkj26091b12016-09-01 01:17:40 -0700291 fake_encoder_(),
Niels Möller4db138e2018-04-19 09:04:13 +0200292 encoder_factory_(&fake_encoder_),
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800293 bitrate_allocator_factory_(CreateBuiltinVideoBitrateAllocatorFactory()),
sprangc5d62e22017-04-02 23:53:04 -0700294 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700295 Clock::GetRealTimeClock(),
296 video_send_config_,
297 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700298 sink_(&fake_encoder_) {}
299
300 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700301 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700302 video_send_config_ = VideoSendStream::Config(nullptr);
Niels Möller4db138e2018-04-19 09:04:13 +0200303 video_send_config_.encoder_settings.encoder_factory = &encoder_factory_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800304 video_send_config_.encoder_settings.bitrate_allocator_factory =
305 bitrate_allocator_factory_.get();
Niels Möller259a4972018-04-05 15:36:51 +0200306 video_send_config_.rtp.payload_name = "FAKE";
307 video_send_config_.rtp.payload_type = 125;
perkj26091b12016-09-01 01:17:40 -0700308
Per512ecb32016-09-23 15:52:06 +0200309 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200310 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700311 video_encoder_config.video_stream_factory =
312 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100313 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700314
315 // Framerate limit is specified by the VideoStreamFactory.
316 std::vector<VideoStream> streams =
317 video_encoder_config.video_stream_factory->CreateEncoderStreams(
318 codec_width_, codec_height_, video_encoder_config);
319 max_framerate_ = streams[0].max_framerate;
320 fake_clock_.SetTimeMicros(1234);
321
Niels Möllerf1338562018-04-26 09:51:47 +0200322 ConfigureEncoder(std::move(video_encoder_config));
asapersson5f7226f2016-11-25 04:37:00 -0800323 }
324
Niels Möllerf1338562018-04-26 09:51:47 +0200325 void ConfigureEncoder(VideoEncoderConfig video_encoder_config) {
mflodmancc3d4422017-08-03 08:27:51 -0700326 if (video_stream_encoder_)
327 video_stream_encoder_->Stop();
328 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700329 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700330 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
331 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700332 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -0700333 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
334 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200335 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -0700336 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800337 }
338
339 void ResetEncoder(const std::string& payload_name,
340 size_t num_streams,
341 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700342 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700343 bool screenshare) {
Niels Möller259a4972018-04-05 15:36:51 +0200344 video_send_config_.rtp.payload_name = payload_name;
asapersson5f7226f2016-11-25 04:37:00 -0800345
346 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200347 video_encoder_config.codec_type = PayloadStringToCodecType(payload_name);
asapersson5f7226f2016-11-25 04:37:00 -0800348 video_encoder_config.number_of_streams = num_streams;
Erik Språngd7329ca2019-02-21 21:19:53 +0100349 video_encoder_config.max_bitrate_bps =
350 num_streams == 1 ? kTargetBitrateBps : kSimulcastTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800351 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700352 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
353 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700354 video_encoder_config.content_type =
355 screenshare ? VideoEncoderConfig::ContentType::kScreen
356 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700357 if (payload_name == "VP9") {
358 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
359 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
360 video_encoder_config.encoder_specific_settings =
361 new rtc::RefCountedObject<
362 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
363 }
Niels Möllerf1338562018-04-26 09:51:47 +0200364 ConfigureEncoder(std::move(video_encoder_config));
perkj26091b12016-09-01 01:17:40 -0700365 }
366
sprang57c2fff2017-01-16 06:24:02 -0800367 VideoFrame CreateFrame(int64_t ntp_time_ms,
368 rtc::Event* destruction_event) const {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100369 VideoFrame frame =
370 VideoFrame::Builder()
371 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
372 destruction_event, codec_width_, codec_height_))
373 .set_timestamp_rtp(99)
374 .set_timestamp_ms(99)
375 .set_rotation(kVideoRotation_0)
376 .build();
sprang57c2fff2017-01-16 06:24:02 -0800377 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700378 return frame;
379 }
380
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100381 VideoFrame CreateFrameWithUpdatedPixel(int64_t ntp_time_ms,
382 rtc::Event* destruction_event,
383 int offset_x) const {
384 VideoFrame frame =
385 VideoFrame::Builder()
386 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
387 destruction_event, codec_width_, codec_height_))
388 .set_timestamp_rtp(99)
389 .set_timestamp_ms(99)
390 .set_rotation(kVideoRotation_0)
391 .set_update_rect({offset_x, 0, 1, 1})
392 .build();
393 frame.set_ntp_time_ms(ntp_time_ms);
394 return frame;
395 }
396
sprang57c2fff2017-01-16 06:24:02 -0800397 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100398 VideoFrame frame =
399 VideoFrame::Builder()
400 .set_video_frame_buffer(
401 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height))
402 .set_timestamp_rtp(99)
403 .set_timestamp_ms(99)
404 .set_rotation(kVideoRotation_0)
405 .build();
sprang57c2fff2017-01-16 06:24:02 -0800406 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700407 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700408 return frame;
409 }
410
asapersson02465b82017-04-10 01:12:52 -0700411 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700412 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700413 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
414 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700415 }
416
asapersson09f05612017-05-15 23:40:18 -0700417 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
418 const rtc::VideoSinkWants& wants2) {
419 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
420 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
421 }
422
Åsa Persson8c1bf952018-09-13 10:42:19 +0200423 void VerifyFpsMaxResolutionMax(const rtc::VideoSinkWants& wants) {
424 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
425 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
426 EXPECT_FALSE(wants.target_pixel_count);
427 }
428
asapersson09f05612017-05-15 23:40:18 -0700429 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
430 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200431 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700432 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
433 EXPECT_GT(wants1.max_pixel_count, 0);
434 }
435
436 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
437 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200438 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700439 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
440 }
441
asaperssonf7e294d2017-06-13 23:25:22 -0700442 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
443 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200444 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700445 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
446 }
447
448 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
449 const rtc::VideoSinkWants& wants2) {
450 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
451 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
452 }
453
454 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
455 const rtc::VideoSinkWants& wants2) {
456 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
457 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
458 }
459
460 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
461 const rtc::VideoSinkWants& wants2) {
462 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
463 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
464 EXPECT_GT(wants1.max_pixel_count, 0);
465 }
466
467 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
468 const rtc::VideoSinkWants& wants2) {
469 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
470 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
471 }
472
asapersson09f05612017-05-15 23:40:18 -0700473 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
474 int pixel_count) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200475 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700476 EXPECT_LT(wants.max_pixel_count, pixel_count);
477 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700478 }
479
480 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
481 EXPECT_LT(wants.max_framerate_fps, fps);
482 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
483 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700484 }
485
asaperssonf7e294d2017-06-13 23:25:22 -0700486 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
487 int expected_fps) {
488 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
489 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
490 EXPECT_FALSE(wants.target_pixel_count);
491 }
492
Jonathan Yubc771b72017-12-08 17:04:29 -0800493 void VerifyBalancedModeFpsRange(const rtc::VideoSinkWants& wants,
494 int last_frame_pixels) {
495 // Balanced mode should always scale FPS to the desired range before
496 // attempting to scale resolution.
497 int fps_limit = wants.max_framerate_fps;
498 if (last_frame_pixels <= 320 * 240) {
499 EXPECT_TRUE(7 <= fps_limit && fps_limit <= 10);
500 } else if (last_frame_pixels <= 480 * 270) {
501 EXPECT_TRUE(10 <= fps_limit && fps_limit <= 15);
502 } else if (last_frame_pixels <= 640 * 480) {
503 EXPECT_LE(15, fps_limit);
504 } else {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200505 EXPECT_EQ(kDefaultFramerate, fps_limit);
Jonathan Yubc771b72017-12-08 17:04:29 -0800506 }
507 }
508
sprang4847ae62017-06-27 07:06:52 -0700509 void WaitForEncodedFrame(int64_t expected_ntp_time) {
510 sink_.WaitForEncodedFrame(expected_ntp_time);
511 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
512 }
513
514 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
515 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
516 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
517 return ok;
518 }
519
520 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
521 sink_.WaitForEncodedFrame(expected_width, expected_height);
522 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
523 }
524
525 void ExpectDroppedFrame() {
526 sink_.ExpectDroppedFrame();
527 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
528 }
529
530 bool WaitForFrame(int64_t timeout_ms) {
531 bool ok = sink_.WaitForFrame(timeout_ms);
532 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
533 return ok;
534 }
535
perkj26091b12016-09-01 01:17:40 -0700536 class TestEncoder : public test::FakeEncoder {
537 public:
Niels Möllerc572ff32018-11-07 08:43:50 +0100538 TestEncoder() : FakeEncoder(Clock::GetRealTimeClock()) {}
perkj26091b12016-09-01 01:17:40 -0700539
asaperssonfab67072017-04-04 05:51:49 -0700540 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800541 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700542 return config_;
543 }
544
545 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800546 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700547 block_next_encode_ = true;
548 }
549
Erik Språngaed30702018-11-05 12:57:17 +0100550 VideoEncoder::EncoderInfo GetEncoderInfo() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800551 rtc::CritScope lock(&local_crit_sect_);
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100552 EncoderInfo info;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100553 if (initialized_ == EncoderState::kInitialized) {
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100554 if (quality_scaling_) {
555 info.scaling_settings =
556 VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
557 }
558 info.is_hardware_accelerated = is_hardware_accelerated_;
Erik Språngaed30702018-11-05 12:57:17 +0100559 }
560 return info;
kthelgason876222f2016-11-29 01:44:11 -0800561 }
562
Erik Språngb7cb7b52019-02-26 15:52:33 +0100563 int32_t RegisterEncodeCompleteCallback(
564 EncodedImageCallback* callback) override {
565 rtc::CritScope lock(&local_crit_sect_);
566 encoded_image_callback_ = callback;
567 return FakeEncoder::RegisterEncodeCompleteCallback(callback);
568 }
569
perkjfa10b552016-10-02 23:45:26 -0700570 void ContinueEncode() { continue_encode_event_.Set(); }
571
572 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
573 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800574 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700575 EXPECT_EQ(timestamp_, timestamp);
576 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
577 }
578
kthelgason2fc52542017-03-03 00:24:41 -0800579 void SetQualityScaling(bool b) {
580 rtc::CritScope lock(&local_crit_sect_);
581 quality_scaling_ = b;
582 }
kthelgasonad9010c2017-02-14 00:46:51 -0800583
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100584 void SetIsHardwareAccelerated(bool is_hardware_accelerated) {
585 rtc::CritScope lock(&local_crit_sect_);
586 is_hardware_accelerated_ = is_hardware_accelerated;
587 }
588
sprangfe627f32017-03-29 08:24:59 -0700589 void ForceInitEncodeFailure(bool force_failure) {
590 rtc::CritScope lock(&local_crit_sect_);
591 force_init_encode_failed_ = force_failure;
592 }
593
Niels Möller6bb5ab92019-01-11 11:11:10 +0100594 void SimulateOvershoot(double rate_factor) {
595 rtc::CritScope lock(&local_crit_sect_);
596 rate_factor_ = rate_factor;
597 }
598
Erik Språngd7329ca2019-02-21 21:19:53 +0100599 uint32_t GetLastFramerate() const {
Niels Möller6bb5ab92019-01-11 11:11:10 +0100600 rtc::CritScope lock(&local_crit_sect_);
601 return last_framerate_;
602 }
603
Erik Språngd7329ca2019-02-21 21:19:53 +0100604 VideoFrame::UpdateRect GetLastUpdateRect() const {
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100605 rtc::CritScope lock(&local_crit_sect_);
606 return last_update_rect_;
607 }
608
Erik Språngd7329ca2019-02-21 21:19:53 +0100609 const std::vector<FrameType>& LastFrameTypes() const {
610 rtc::CritScope lock(&local_crit_sect_);
611 return last_frame_types_;
612 }
613
614 void InjectFrame(const VideoFrame& input_image, bool keyframe) {
615 const std::vector<FrameType> frame_type = {keyframe ? kVideoFrameKey
616 : kVideoFrameDelta};
617 {
618 rtc::CritScope lock(&local_crit_sect_);
619 last_frame_types_ = frame_type;
620 }
621 FakeEncoder::Encode(input_image, nullptr, &frame_type);
622 }
623
Erik Språngb7cb7b52019-02-26 15:52:33 +0100624 void InjectEncodedImage(const EncodedImage& image) {
625 rtc::CritScope lock(&local_crit_sect_);
626 encoded_image_callback_->OnEncodedImage(image, nullptr, nullptr);
627 }
628
Erik Språngd7329ca2019-02-21 21:19:53 +0100629 void ExpectNullFrame() {
630 rtc::CritScope lock(&local_crit_sect_);
631 expect_null_frame_ = true;
632 }
633
634 absl::optional<VideoBitrateAllocation> GetAndResetLastBitrateAllocation() {
635 auto allocation = last_bitrate_allocation_;
636 last_bitrate_allocation_.reset();
637 return allocation;
638 }
639
perkjfa10b552016-10-02 23:45:26 -0700640 private:
perkj26091b12016-09-01 01:17:40 -0700641 int32_t Encode(const VideoFrame& input_image,
642 const CodecSpecificInfo* codec_specific_info,
643 const std::vector<FrameType>* frame_types) override {
644 bool block_encode;
645 {
brandtre78d2662017-01-16 05:57:16 -0800646 rtc::CritScope lock(&local_crit_sect_);
Erik Språngd7329ca2019-02-21 21:19:53 +0100647 if (expect_null_frame_) {
648 EXPECT_EQ(input_image.timestamp(), 0u);
649 EXPECT_EQ(input_image.width(), 1);
650 last_frame_types_ = *frame_types;
651 expect_null_frame_ = false;
652 } else {
653 EXPECT_GT(input_image.timestamp(), timestamp_);
654 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
655 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
656 }
perkj26091b12016-09-01 01:17:40 -0700657
658 timestamp_ = input_image.timestamp();
659 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700660 last_input_width_ = input_image.width();
661 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700662 block_encode = block_next_encode_;
663 block_next_encode_ = false;
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100664 last_update_rect_ = input_image.update_rect();
Erik Språngd7329ca2019-02-21 21:19:53 +0100665 last_frame_types_ = *frame_types;
perkj26091b12016-09-01 01:17:40 -0700666 }
667 int32_t result =
668 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
669 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700670 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700671 return result;
672 }
673
sprangfe627f32017-03-29 08:24:59 -0700674 int32_t InitEncode(const VideoCodec* config,
675 int32_t number_of_cores,
676 size_t max_payload_size) override {
677 int res =
678 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
679 rtc::CritScope lock(&local_crit_sect_);
Erik Språngb7cb7b52019-02-26 15:52:33 +0100680 EXPECT_EQ(initialized_, EncoderState::kUninitialized);
Erik Språng82fad3d2018-03-21 09:57:23 +0100681 if (config->codecType == kVideoCodecVP8) {
sprangfe627f32017-03-29 08:24:59 -0700682 // Simulate setting up temporal layers, in order to validate the life
683 // cycle of these objects.
684 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
sprangfe627f32017-03-29 08:24:59 -0700685 for (int i = 0; i < num_streams; ++i) {
686 allocated_temporal_layers_.emplace_back(
Erik Språng4529fbc2018-10-12 10:30:31 +0200687 CreateVp8TemporalLayers(Vp8TemporalLayersType::kFixedPattern,
688 config->VP8().numberOfTemporalLayers));
sprangfe627f32017-03-29 08:24:59 -0700689 }
690 }
Erik Språngb7cb7b52019-02-26 15:52:33 +0100691 if (force_init_encode_failed_) {
692 initialized_ = EncoderState::kInitializationFailed;
sprangfe627f32017-03-29 08:24:59 -0700693 return -1;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100694 }
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100695
Erik Språngb7cb7b52019-02-26 15:52:33 +0100696 initialized_ = EncoderState::kInitialized;
sprangfe627f32017-03-29 08:24:59 -0700697 return res;
698 }
699
Erik Språngb7cb7b52019-02-26 15:52:33 +0100700 int32_t Release() override {
701 rtc::CritScope lock(&local_crit_sect_);
702 EXPECT_NE(initialized_, EncoderState::kUninitialized);
703 initialized_ = EncoderState::kUninitialized;
704 return FakeEncoder::Release();
705 }
706
Niels Möller6bb5ab92019-01-11 11:11:10 +0100707 int32_t SetRateAllocation(const VideoBitrateAllocation& rate_allocation,
708 uint32_t framerate) {
709 rtc::CritScope lock(&local_crit_sect_);
710 VideoBitrateAllocation adjusted_rate_allocation;
711 for (size_t si = 0; si < kMaxSpatialLayers; ++si) {
712 for (size_t ti = 0; ti < kMaxTemporalStreams; ++ti) {
713 if (rate_allocation.HasBitrate(si, ti)) {
714 adjusted_rate_allocation.SetBitrate(
715 si, ti,
716 static_cast<uint32_t>(rate_allocation.GetBitrate(si, ti) *
717 rate_factor_));
718 }
719 }
720 }
721 last_framerate_ = framerate;
Erik Språngd7329ca2019-02-21 21:19:53 +0100722 last_bitrate_allocation_ = rate_allocation;
Niels Möller6bb5ab92019-01-11 11:11:10 +0100723 return FakeEncoder::SetRateAllocation(adjusted_rate_allocation,
724 framerate);
725 }
726
brandtre78d2662017-01-16 05:57:16 -0800727 rtc::CriticalSection local_crit_sect_;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100728 enum class EncoderState {
729 kUninitialized,
730 kInitializationFailed,
731 kInitialized
732 } initialized_ RTC_GUARDED_BY(local_crit_sect_) =
733 EncoderState::kUninitialized;
danilchapa37de392017-09-09 04:17:22 -0700734 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700735 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700736 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
737 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
738 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
739 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
740 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100741 bool is_hardware_accelerated_ RTC_GUARDED_BY(local_crit_sect_) = false;
Erik Språng4529fbc2018-10-12 10:30:31 +0200742 std::vector<std::unique_ptr<Vp8TemporalLayers>> allocated_temporal_layers_
danilchapa37de392017-09-09 04:17:22 -0700743 RTC_GUARDED_BY(local_crit_sect_);
744 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
Niels Möller6bb5ab92019-01-11 11:11:10 +0100745 double rate_factor_ RTC_GUARDED_BY(local_crit_sect_) = 1.0;
746 uint32_t last_framerate_ RTC_GUARDED_BY(local_crit_sect_) = 0;
Erik Språngd7329ca2019-02-21 21:19:53 +0100747 absl::optional<VideoBitrateAllocation> last_bitrate_allocation_;
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100748 VideoFrame::UpdateRect last_update_rect_
749 RTC_GUARDED_BY(local_crit_sect_) = {0, 0, 0, 0};
Erik Språngd7329ca2019-02-21 21:19:53 +0100750 std::vector<FrameType> last_frame_types_;
751 bool expect_null_frame_ = false;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100752 EncodedImageCallback* encoded_image_callback_
753 RTC_GUARDED_BY(local_crit_sect_) = nullptr;
perkj26091b12016-09-01 01:17:40 -0700754 };
755
mflodmancc3d4422017-08-03 08:27:51 -0700756 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700757 public:
758 explicit TestSink(TestEncoder* test_encoder)
Niels Möllerc572ff32018-11-07 08:43:50 +0100759 : test_encoder_(test_encoder) {}
perkj26091b12016-09-01 01:17:40 -0700760
perkj26091b12016-09-01 01:17:40 -0700761 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700762 EXPECT_TRUE(
763 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
764 }
765
766 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
767 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700768 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700769 if (!encoded_frame_event_.Wait(timeout_ms))
770 return false;
perkj26091b12016-09-01 01:17:40 -0700771 {
772 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800773 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700774 }
775 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700776 return true;
perkj26091b12016-09-01 01:17:40 -0700777 }
778
sprangb1ca0732017-02-01 08:38:12 -0800779 void WaitForEncodedFrame(uint32_t expected_width,
780 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700781 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100782 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700783 }
784
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100785 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700786 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800787 uint32_t width = 0;
788 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800789 {
790 rtc::CritScope lock(&crit_);
791 width = last_width_;
792 height = last_height_;
793 }
794 EXPECT_EQ(expected_height, height);
795 EXPECT_EQ(expected_width, width);
796 }
797
kthelgason2fc52542017-03-03 00:24:41 -0800798 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800799
sprangc5d62e22017-04-02 23:53:04 -0700800 bool WaitForFrame(int64_t timeout_ms) {
801 return encoded_frame_event_.Wait(timeout_ms);
802 }
803
perkj26091b12016-09-01 01:17:40 -0700804 void SetExpectNoFrames() {
805 rtc::CritScope lock(&crit_);
806 expect_frames_ = false;
807 }
808
asaperssonfab67072017-04-04 05:51:49 -0700809 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200810 rtc::CritScope lock(&crit_);
811 return number_of_reconfigurations_;
812 }
813
asaperssonfab67072017-04-04 05:51:49 -0700814 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200815 rtc::CritScope lock(&crit_);
816 return min_transmit_bitrate_bps_;
817 }
818
Erik Språngd7329ca2019-02-21 21:19:53 +0100819 void SetNumExpectedLayers(size_t num_layers) {
820 rtc::CritScope lock(&crit_);
821 num_expected_layers_ = num_layers;
822 }
823
Erik Språngb7cb7b52019-02-26 15:52:33 +0100824 int64_t GetLastCaptureTimeMs() const {
825 rtc::CritScope lock(&crit_);
826 return last_capture_time_ms_;
827 }
828
perkj26091b12016-09-01 01:17:40 -0700829 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700830 Result OnEncodedImage(
831 const EncodedImage& encoded_image,
832 const CodecSpecificInfo* codec_specific_info,
833 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200834 rtc::CritScope lock(&crit_);
835 EXPECT_TRUE(expect_frames_);
Erik Språngd7329ca2019-02-21 21:19:53 +0100836 uint32_t timestamp = encoded_image.Timestamp();
837 if (last_timestamp_ != timestamp) {
838 num_received_layers_ = 1;
839 } else {
840 ++num_received_layers_;
841 }
842 last_timestamp_ = timestamp;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100843 last_capture_time_ms_ = encoded_image.capture_time_ms_;
sprangb1ca0732017-02-01 08:38:12 -0800844 last_width_ = encoded_image._encodedWidth;
845 last_height_ = encoded_image._encodedHeight;
Erik Språngd7329ca2019-02-21 21:19:53 +0100846 if (num_received_layers_ == num_expected_layers_) {
847 encoded_frame_event_.Set();
848 }
sprangb1ca0732017-02-01 08:38:12 -0800849 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200850 }
851
Rasmus Brandtc402dbe2019-02-04 11:09:46 +0100852 void OnEncoderConfigurationChanged(
853 std::vector<VideoStream> streams,
854 VideoEncoderConfig::ContentType content_type,
855 int min_transmit_bitrate_bps) override {
Per512ecb32016-09-23 15:52:06 +0200856 rtc::CriticalSection crit_;
857 ++number_of_reconfigurations_;
858 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
859 }
860
perkj26091b12016-09-01 01:17:40 -0700861 rtc::CriticalSection crit_;
862 TestEncoder* test_encoder_;
863 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800864 uint32_t last_timestamp_ = 0;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100865 int64_t last_capture_time_ms_ = 0;
sprangb1ca0732017-02-01 08:38:12 -0800866 uint32_t last_height_ = 0;
867 uint32_t last_width_ = 0;
Erik Språngd7329ca2019-02-21 21:19:53 +0100868 size_t num_expected_layers_ = 1;
869 size_t num_received_layers_ = 0;
perkj26091b12016-09-01 01:17:40 -0700870 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200871 int number_of_reconfigurations_ = 0;
872 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700873 };
874
875 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100876 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200877 int codec_width_;
878 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700879 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700880 TestEncoder fake_encoder_;
Niels Möllercbcbc222018-09-28 09:07:24 +0200881 test::VideoEncoderProxyFactory encoder_factory_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800882 std::unique_ptr<VideoBitrateAllocatorFactory> bitrate_allocator_factory_;
sprangc5d62e22017-04-02 23:53:04 -0700883 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700884 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800885 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700886 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700887 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700888};
889
mflodmancc3d4422017-08-03 08:27:51 -0700890TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
Erik Språng610c7632019-03-06 15:37:33 +0100891 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
892 DataRate::Zero(), 0, 0);
Niels Möllerc572ff32018-11-07 08:43:50 +0100893 rtc::Event frame_destroyed_event;
perkja49cbd32016-09-16 07:53:41 -0700894 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700895 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700896 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700897 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700898}
899
mflodmancc3d4422017-08-03 08:27:51 -0700900TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700901 // Dropped since no target bitrate has been set.
Niels Möllerc572ff32018-11-07 08:43:50 +0100902 rtc::Event frame_destroyed_event;
Sebastian Janssona3177052018-04-10 13:05:49 +0200903 // The encoder will cache up to one frame for a short duration. Adding two
904 // frames means that the first frame will be dropped and the second frame will
905 // be sent when the encoder is enabled.
perkja49cbd32016-09-16 07:53:41 -0700906 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
Sebastian Janssona3177052018-04-10 13:05:49 +0200907 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkja49cbd32016-09-16 07:53:41 -0700908 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700909
Erik Språng610c7632019-03-06 15:37:33 +0100910 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
911 DataRate::Zero(), 0, 0);
perkj26091b12016-09-01 01:17:40 -0700912
Sebastian Janssona3177052018-04-10 13:05:49 +0200913 // The pending frame should be received.
sprang4847ae62017-06-27 07:06:52 -0700914 WaitForEncodedFrame(2);
Sebastian Janssona3177052018-04-10 13:05:49 +0200915 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
916
917 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700918 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700919}
920
mflodmancc3d4422017-08-03 08:27:51 -0700921TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
Erik Språng610c7632019-03-06 15:37:33 +0100922 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
923 DataRate::Zero(), 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700924 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700925 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700926
Erik Språng610c7632019-03-06 15:37:33 +0100927 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(0), DataRate::Zero(), 0,
928 0);
Sebastian Janssona3177052018-04-10 13:05:49 +0200929 // The encoder will cache up to one frame for a short duration. Adding two
930 // frames means that the first frame will be dropped and the second frame will
931 // be sent when the encoder is resumed.
perkja49cbd32016-09-16 07:53:41 -0700932 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Sebastian Janssona3177052018-04-10 13:05:49 +0200933 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700934
Erik Språng610c7632019-03-06 15:37:33 +0100935 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
936 DataRate::Zero(), 0, 0);
sprang4847ae62017-06-27 07:06:52 -0700937 WaitForEncodedFrame(3);
Sebastian Janssona3177052018-04-10 13:05:49 +0200938 video_source_.IncomingCapturedFrame(CreateFrame(4, nullptr));
939 WaitForEncodedFrame(4);
mflodmancc3d4422017-08-03 08:27:51 -0700940 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700941}
942
mflodmancc3d4422017-08-03 08:27:51 -0700943TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
Erik Språng610c7632019-03-06 15:37:33 +0100944 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
945 DataRate::Zero(), 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700946 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700947 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700948
949 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700950 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700951
perkja49cbd32016-09-16 07:53:41 -0700952 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700953 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700954 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700955}
956
mflodmancc3d4422017-08-03 08:27:51 -0700957TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
Erik Språng610c7632019-03-06 15:37:33 +0100958 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
959 DataRate::Zero(), 0, 0);
perkj26091b12016-09-01 01:17:40 -0700960
perkja49cbd32016-09-16 07:53:41 -0700961 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700962 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700963
mflodmancc3d4422017-08-03 08:27:51 -0700964 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700965 sink_.SetExpectNoFrames();
Niels Möllerc572ff32018-11-07 08:43:50 +0100966 rtc::Event frame_destroyed_event;
perkja49cbd32016-09-16 07:53:41 -0700967 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
968 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700969}
970
mflodmancc3d4422017-08-03 08:27:51 -0700971TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
Erik Språng610c7632019-03-06 15:37:33 +0100972 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
973 DataRate::Zero(), 0, 0);
perkj26091b12016-09-01 01:17:40 -0700974
975 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700976 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700977 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700978 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
979 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700980 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
981 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700982 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700983 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700984
mflodmancc3d4422017-08-03 08:27:51 -0700985 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700986}
987
mflodmancc3d4422017-08-03 08:27:51 -0700988TEST_F(VideoStreamEncoderTest,
989 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
Erik Språng610c7632019-03-06 15:37:33 +0100990 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
991 DataRate::Zero(), 0, 0);
Per21d45d22016-10-30 21:37:57 +0100992 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200993
994 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200995 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700996 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100997 // The encoder will have been configured once when the first frame is
998 // received.
999 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +02001000
1001 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02001002 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +02001003 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -07001004 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001005 kMaxPayloadLength);
Per512ecb32016-09-23 15:52:06 +02001006
1007 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +02001008 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001009 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +01001010 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -07001011 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -07001012
mflodmancc3d4422017-08-03 08:27:51 -07001013 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -07001014}
1015
mflodmancc3d4422017-08-03 08:27:51 -07001016TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
Erik Språng610c7632019-03-06 15:37:33 +01001017 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1018 DataRate::Zero(), 0, 0);
perkjfa10b552016-10-02 23:45:26 -07001019
1020 // Capture a frame and wait for it to synchronize with the encoder thread.
1021 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001022 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +01001023 // The encoder will have been configured once.
1024 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -07001025 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
1026 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
1027
1028 codec_width_ *= 2;
1029 codec_height_ *= 2;
1030 // Capture a frame with a higher resolution and wait for it to synchronize
1031 // with the encoder thread.
1032 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001033 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -07001034 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
1035 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +01001036 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -07001037
mflodmancc3d4422017-08-03 08:27:51 -07001038 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -07001039}
1040
mflodmancc3d4422017-08-03 08:27:51 -07001041TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -07001042 EXPECT_TRUE(video_source_.has_sinks());
1043 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001044 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001045 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001046 EXPECT_FALSE(video_source_.has_sinks());
1047 EXPECT_TRUE(new_video_source.has_sinks());
1048
mflodmancc3d4422017-08-03 08:27:51 -07001049 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001050}
1051
mflodmancc3d4422017-08-03 08:27:51 -07001052TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -07001053 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -07001054 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -07001055 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -07001056 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001057}
1058
Jonathan Yubc771b72017-12-08 17:04:29 -08001059TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
1060 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -07001061 const int kWidth = 1280;
1062 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -08001063
1064 // We rely on the automatic resolution adaptation, but we handle framerate
1065 // adaptation manually by mocking the stats proxy.
1066 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -07001067
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001068 // Enable BALANCED preference, no initial limitation.
Erik Språng610c7632019-03-06 15:37:33 +01001069 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1070 DataRate::Zero(), 0, 0);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001071 video_stream_encoder_->SetSource(&video_source_,
1072 webrtc::DegradationPreference::BALANCED);
Jonathan Yubc771b72017-12-08 17:04:29 -08001073 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001074 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001075 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -07001076 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1077
Jonathan Yubc771b72017-12-08 17:04:29 -08001078 // Adapt down as far as possible.
1079 rtc::VideoSinkWants last_wants;
1080 int64_t t = 1;
1081 int loop_count = 0;
1082 do {
1083 ++loop_count;
1084 last_wants = video_source_.sink_wants();
1085
1086 // Simulate the framerate we've been asked to adapt to.
1087 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
1088 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
1089 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1090 mock_stats.input_frame_rate = fps;
1091 stats_proxy_->SetMockStats(mock_stats);
1092
1093 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1094 sink_.WaitForEncodedFrame(t);
1095 t += frame_interval_ms;
1096
mflodmancc3d4422017-08-03 08:27:51 -07001097 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08001098 VerifyBalancedModeFpsRange(
1099 video_source_.sink_wants(),
1100 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1101 } while (video_source_.sink_wants().max_pixel_count <
1102 last_wants.max_pixel_count ||
1103 video_source_.sink_wants().max_framerate_fps <
1104 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001105
Jonathan Yubc771b72017-12-08 17:04:29 -08001106 // Verify that we've adapted all the way down.
1107 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001108 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001109 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
1110 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -07001111 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -08001112 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
1113 *video_source_.last_sent_height());
1114 EXPECT_EQ(kMinBalancedFramerateFps,
1115 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001116
Jonathan Yubc771b72017-12-08 17:04:29 -08001117 // Adapt back up the same number of times we adapted down.
1118 for (int i = 0; i < loop_count - 1; ++i) {
1119 last_wants = video_source_.sink_wants();
1120
1121 // Simulate the framerate we've been asked to adapt to.
1122 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
1123 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
1124 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1125 mock_stats.input_frame_rate = fps;
1126 stats_proxy_->SetMockStats(mock_stats);
1127
1128 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1129 sink_.WaitForEncodedFrame(t);
1130 t += frame_interval_ms;
1131
mflodmancc3d4422017-08-03 08:27:51 -07001132 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -08001133 VerifyBalancedModeFpsRange(
1134 video_source_.sink_wants(),
1135 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1136 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
1137 last_wants.max_pixel_count ||
1138 video_source_.sink_wants().max_framerate_fps >
1139 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001140 }
1141
Åsa Persson8c1bf952018-09-13 10:42:19 +02001142 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001143 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001144 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001145 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1146 EXPECT_EQ((loop_count - 1) * 2,
1147 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -07001148
mflodmancc3d4422017-08-03 08:27:51 -07001149 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001150}
mflodmancc3d4422017-08-03 08:27:51 -07001151TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
Erik Språng610c7632019-03-06 15:37:33 +01001152 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1153 DataRate::Zero(), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001154 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001155
sprangc5d62e22017-04-02 23:53:04 -07001156 const int kFrameWidth = 1280;
1157 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07001158
Åsa Persson8c1bf952018-09-13 10:42:19 +02001159 int64_t frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -07001160
kthelgason5e13d412016-12-01 03:59:51 -08001161 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001162 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001163 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001164 frame_timestamp += kFrameIntervalMs;
1165
perkj803d97f2016-11-01 11:45:46 -07001166 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001167 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001168 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001169 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001170 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001171 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -07001172
asapersson0944a802017-04-07 00:57:58 -07001173 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -07001174 // wanted resolution.
1175 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
1176 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
1177 kFrameWidth * kFrameHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001178 EXPECT_EQ(kDefaultFramerate, video_source_.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001179
1180 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -07001181 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001182 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001183 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001184
sprangc5d62e22017-04-02 23:53:04 -07001185 // Initially no degradation registered.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001186 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001187
sprangc5d62e22017-04-02 23:53:04 -07001188 // Force an input frame rate to be available, or the adaptation call won't
1189 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -07001190 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -07001191 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -07001192 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -07001193 stats_proxy_->SetMockStats(stats);
1194
mflodmancc3d4422017-08-03 08:27:51 -07001195 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001196 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001197 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001198 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001199 frame_timestamp += kFrameIntervalMs;
1200
1201 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001202 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001203 EXPECT_EQ(std::numeric_limits<int>::max(),
1204 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001205 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001206
asapersson02465b82017-04-10 01:12:52 -07001207 // Turn off degradation completely.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001208 video_stream_encoder_->SetSource(&new_video_source,
1209 webrtc::DegradationPreference::DISABLED);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001210 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001211
mflodmancc3d4422017-08-03 08:27:51 -07001212 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001213 new_video_source.IncomingCapturedFrame(
1214 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001215 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001216 frame_timestamp += kFrameIntervalMs;
1217
1218 // Still no degradation.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001219 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001220
1221 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001222 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001223 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
sprangc5d62e22017-04-02 23:53:04 -07001224 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1225 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001226 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001227 EXPECT_EQ(kDefaultFramerate, new_video_source.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001228
1229 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001230 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001231 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001232 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1233 EXPECT_EQ(std::numeric_limits<int>::max(),
1234 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001235 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001236
mflodmancc3d4422017-08-03 08:27:51 -07001237 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001238}
1239
mflodmancc3d4422017-08-03 08:27:51 -07001240TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
Erik Språng610c7632019-03-06 15:37:33 +01001241 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1242 DataRate::Zero(), 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001243
asaperssonfab67072017-04-04 05:51:49 -07001244 const int kWidth = 1280;
1245 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001246 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001247 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001248 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1249 EXPECT_FALSE(stats.bw_limited_resolution);
1250 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1251
1252 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001253 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001254 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001255 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001256
1257 stats = stats_proxy_->GetStats();
1258 EXPECT_TRUE(stats.bw_limited_resolution);
1259 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1260
1261 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001262 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001263 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001264 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001265
1266 stats = stats_proxy_->GetStats();
1267 EXPECT_FALSE(stats.bw_limited_resolution);
1268 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1269 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1270
mflodmancc3d4422017-08-03 08:27:51 -07001271 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001272}
1273
mflodmancc3d4422017-08-03 08:27:51 -07001274TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
Erik Språng610c7632019-03-06 15:37:33 +01001275 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1276 DataRate::Zero(), 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001277
1278 const int kWidth = 1280;
1279 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001280 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001281 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001282 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1283 EXPECT_FALSE(stats.cpu_limited_resolution);
1284 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1285
1286 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001287 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001288 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001289 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001290
1291 stats = stats_proxy_->GetStats();
1292 EXPECT_TRUE(stats.cpu_limited_resolution);
1293 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1294
1295 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001296 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001297 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001298 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001299
1300 stats = stats_proxy_->GetStats();
1301 EXPECT_FALSE(stats.cpu_limited_resolution);
1302 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001303 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001304
mflodmancc3d4422017-08-03 08:27:51 -07001305 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001306}
1307
mflodmancc3d4422017-08-03 08:27:51 -07001308TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
Erik Språng610c7632019-03-06 15:37:33 +01001309 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1310 DataRate::Zero(), 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001311
asaperssonfab67072017-04-04 05:51:49 -07001312 const int kWidth = 1280;
1313 const int kHeight = 720;
1314 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001315 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001316 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001317 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001318 EXPECT_FALSE(stats.cpu_limited_resolution);
1319 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1320
asaperssonfab67072017-04-04 05:51:49 -07001321 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001322 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001323 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001324 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001325 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001326 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001327 EXPECT_TRUE(stats.cpu_limited_resolution);
1328 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1329
1330 // Set new source with adaptation still enabled.
1331 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001332 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001333 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001334
asaperssonfab67072017-04-04 05:51:49 -07001335 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001336 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001337 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001338 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001339 EXPECT_TRUE(stats.cpu_limited_resolution);
1340 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1341
1342 // Set adaptation disabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001343 video_stream_encoder_->SetSource(&new_video_source,
1344 webrtc::DegradationPreference::DISABLED);
kthelgason876222f2016-11-29 01:44:11 -08001345
asaperssonfab67072017-04-04 05:51:49 -07001346 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001347 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001348 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001349 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001350 EXPECT_FALSE(stats.cpu_limited_resolution);
1351 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1352
1353 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001354 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001355 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001356
asaperssonfab67072017-04-04 05:51:49 -07001357 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001358 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001359 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001360 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001361 EXPECT_TRUE(stats.cpu_limited_resolution);
1362 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1363
asaperssonfab67072017-04-04 05:51:49 -07001364 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001365 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001366 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001367 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001368 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001369 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001370 EXPECT_FALSE(stats.cpu_limited_resolution);
1371 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001372 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001373
mflodmancc3d4422017-08-03 08:27:51 -07001374 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001375}
1376
mflodmancc3d4422017-08-03 08:27:51 -07001377TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
Erik Språng610c7632019-03-06 15:37:33 +01001378 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1379 DataRate::Zero(), 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001380
asaperssonfab67072017-04-04 05:51:49 -07001381 const int kWidth = 1280;
1382 const int kHeight = 720;
1383 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001384 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001385 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001386 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001387 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001388 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001389
1390 // Set new source with adaptation still enabled.
1391 test::FrameForwarder new_video_source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001392 video_stream_encoder_->SetSource(&new_video_source,
1393 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001394
asaperssonfab67072017-04-04 05:51:49 -07001395 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001396 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001397 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001398 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001399 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001400 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001401
asaperssonfab67072017-04-04 05:51:49 -07001402 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001403 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001404 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001405 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001406 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001407 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001408 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001409 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001410
asaperssonfab67072017-04-04 05:51:49 -07001411 // Set new source with adaptation still enabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001412 video_stream_encoder_->SetSource(&new_video_source,
1413 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001414
asaperssonfab67072017-04-04 05:51:49 -07001415 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001416 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001417 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001418 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001419 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001420 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001421
asapersson02465b82017-04-10 01:12:52 -07001422 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001423 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001424 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001425
asaperssonfab67072017-04-04 05:51:49 -07001426 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001427 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001428 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001429 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001430 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001431 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1432 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001433
mflodmancc3d4422017-08-03 08:27:51 -07001434 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001435}
1436
mflodmancc3d4422017-08-03 08:27:51 -07001437TEST_F(VideoStreamEncoderTest,
1438 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
Erik Språng610c7632019-03-06 15:37:33 +01001439 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1440 DataRate::Zero(), 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001441
1442 const int kWidth = 1280;
1443 const int kHeight = 720;
Åsa Persson8c1bf952018-09-13 10:42:19 +02001444 int64_t timestamp_ms = kFrameIntervalMs;
asapersson36e9eb42017-03-31 05:29:12 -07001445 video_source_.set_adaptation_enabled(true);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001446 video_source_.IncomingCapturedFrame(
1447 CreateFrame(timestamp_ms, kWidth, kHeight));
1448 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001449 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1450 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1451 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1452
1453 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001454 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001455 timestamp_ms += kFrameIntervalMs;
1456 video_source_.IncomingCapturedFrame(
1457 CreateFrame(timestamp_ms, kWidth, kHeight));
1458 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001459 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1460 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1461 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1462
1463 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001464 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001465 timestamp_ms += kFrameIntervalMs;
1466 video_source_.IncomingCapturedFrame(
1467 CreateFrame(timestamp_ms, kWidth, kHeight));
1468 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001469 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1470 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1471 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1472
Niels Möller4db138e2018-04-19 09:04:13 +02001473 // Leave source unchanged, but disable quality scaler.
asapersson36e9eb42017-03-31 05:29:12 -07001474 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02001475
1476 VideoEncoderConfig video_encoder_config;
1477 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
1478 // Make format different, to force recreation of encoder.
1479 video_encoder_config.video_format.parameters["foo"] = "foo";
1480 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001481 kMaxPayloadLength);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001482 timestamp_ms += kFrameIntervalMs;
1483 video_source_.IncomingCapturedFrame(
1484 CreateFrame(timestamp_ms, kWidth, kHeight));
1485 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001486 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1487 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1488 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1489
mflodmancc3d4422017-08-03 08:27:51 -07001490 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001491}
1492
mflodmancc3d4422017-08-03 08:27:51 -07001493TEST_F(VideoStreamEncoderTest,
1494 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
Erik Språng610c7632019-03-06 15:37:33 +01001495 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1496 DataRate::Zero(), 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001497
asapersson0944a802017-04-07 00:57:58 -07001498 const int kWidth = 1280;
1499 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001500 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001501
asaperssonfab67072017-04-04 05:51:49 -07001502 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001503 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001504 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001505 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001506 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001507 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1508
asapersson02465b82017-04-10 01:12:52 -07001509 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001510 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001511 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001512 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001513 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001514 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001515 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001516 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1517
1518 // Set new source with adaptation still enabled.
1519 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001520 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001521 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001522
1523 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001524 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001525 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001526 stats = stats_proxy_->GetStats();
1527 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001528 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001529 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1530
sprangc5d62e22017-04-02 23:53:04 -07001531 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001532 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001533 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001534 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001535 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001536 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001537 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001538 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001539 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001540 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001541 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1542
sprangc5d62e22017-04-02 23:53:04 -07001543 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001544 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001545 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1546 mock_stats.input_frame_rate = 30;
1547 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001548 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001549 stats_proxy_->ResetMockStats();
1550
1551 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001552 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001553 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001554
1555 // Framerate now adapted.
1556 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001557 EXPECT_FALSE(stats.cpu_limited_resolution);
1558 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001559 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1560
1561 // Disable CPU adaptation.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001562 video_stream_encoder_->SetSource(&new_video_source,
1563 webrtc::DegradationPreference::DISABLED);
sprangc5d62e22017-04-02 23:53:04 -07001564 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001565 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001566 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001567
1568 stats = stats_proxy_->GetStats();
1569 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001570 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001571 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1572
1573 // Try to trigger overuse. Should not succeed.
1574 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001575 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001576 stats_proxy_->ResetMockStats();
1577
1578 stats = stats_proxy_->GetStats();
1579 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001580 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001581 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1582
1583 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001584 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001585 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssonfab67072017-04-04 05:51:49 -07001586 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001587 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001588 stats = stats_proxy_->GetStats();
1589 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001590 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001591 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001592
1593 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001594 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001595 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001596 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001597 stats = stats_proxy_->GetStats();
1598 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001599 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001600 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1601
1602 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001603 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001604 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001605 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001606 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001607 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001608 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001609 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001610 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001611 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001612 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1613
1614 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001615 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001616 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001617 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001618 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001619 stats = stats_proxy_->GetStats();
1620 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001621 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001622 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001623 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001624
mflodmancc3d4422017-08-03 08:27:51 -07001625 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001626}
1627
mflodmancc3d4422017-08-03 08:27:51 -07001628TEST_F(VideoStreamEncoderTest,
1629 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001630 const int kWidth = 1280;
1631 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001632 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1633 DataRate::Zero(), 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001634
asaperssonfab67072017-04-04 05:51:49 -07001635 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001636 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001637
asaperssonfab67072017-04-04 05:51:49 -07001638 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001639 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001640
asaperssonfab67072017-04-04 05:51:49 -07001641 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001642 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001643
asaperssonfab67072017-04-04 05:51:49 -07001644 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001645 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001646
kthelgason876222f2016-11-29 01:44:11 -08001647 // Expect a scale down.
1648 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001649 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001650
asapersson02465b82017-04-10 01:12:52 -07001651 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001652 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001653 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001654 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001655
asaperssonfab67072017-04-04 05:51:49 -07001656 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001657 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001658 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001659 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001660
asaperssonfab67072017-04-04 05:51:49 -07001661 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001662 EXPECT_EQ(std::numeric_limits<int>::max(),
1663 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001664
asaperssonfab67072017-04-04 05:51:49 -07001665 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001666 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001667 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001668 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001669
asapersson02465b82017-04-10 01:12:52 -07001670 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001671 EXPECT_EQ(std::numeric_limits<int>::max(),
1672 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001673
mflodmancc3d4422017-08-03 08:27:51 -07001674 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001675}
1676
mflodmancc3d4422017-08-03 08:27:51 -07001677TEST_F(VideoStreamEncoderTest,
1678 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001679 const int kWidth = 1280;
1680 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001681 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1682 DataRate::Zero(), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001683
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001684 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001685 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001686 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001687 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001688
1689 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001690 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001691 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001692 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1693 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1694
1695 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001696 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001697 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001698 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1699 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1700 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1701
1702 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001703 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001704 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1705 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1706 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1707
mflodmancc3d4422017-08-03 08:27:51 -07001708 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001709}
1710
mflodmancc3d4422017-08-03 08:27:51 -07001711TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001712 const int kWidth = 1280;
1713 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001714 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1715 DataRate::Zero(), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001716
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001717 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001718 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001719 video_stream_encoder_->SetSource(&source,
1720 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001721 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1722 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001723 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001724
1725 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001726 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001727 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1728 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1729 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1730 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1731
1732 // Trigger adapt down for same input resolution, expect no change.
1733 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1734 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001735 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001736 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1737 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1738 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1739
1740 // Trigger adapt down for larger input resolution, expect no change.
1741 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1742 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001743 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001744 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1745 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1746 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1747
mflodmancc3d4422017-08-03 08:27:51 -07001748 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001749}
1750
mflodmancc3d4422017-08-03 08:27:51 -07001751TEST_F(VideoStreamEncoderTest,
1752 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001753 const int kWidth = 1280;
1754 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001755 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1756 DataRate::Zero(), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001757
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001758 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001759 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001760 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001761 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001762
1763 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001764 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001765 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001766 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1767 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1768
1769 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001770 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001771 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001772 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1773 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1774
mflodmancc3d4422017-08-03 08:27:51 -07001775 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001776}
1777
mflodmancc3d4422017-08-03 08:27:51 -07001778TEST_F(VideoStreamEncoderTest,
1779 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001780 const int kWidth = 1280;
1781 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001782 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1783 DataRate::Zero(), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001784
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001785 // Enable MAINTAIN_RESOLUTION preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001786 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001787 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001788 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
asapersson02465b82017-04-10 01:12:52 -07001789
1790 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001791 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001792 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001793 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001794 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1795
1796 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001797 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001798 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001799 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001800 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1801
mflodmancc3d4422017-08-03 08:27:51 -07001802 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001803}
1804
mflodmancc3d4422017-08-03 08:27:51 -07001805TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001806 const int kWidth = 1280;
1807 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001808 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1809 DataRate::Zero(), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001810
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001811 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001812 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001813 video_stream_encoder_->SetSource(&source,
1814 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001815
1816 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1817 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001818 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001819 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1820 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1821 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1822
1823 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001824 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001825 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001826 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1827 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1828 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1829
mflodmancc3d4422017-08-03 08:27:51 -07001830 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001831}
1832
mflodmancc3d4422017-08-03 08:27:51 -07001833TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001834 const int kWidth = 1280;
1835 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001836 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1837 DataRate::Zero(), 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001838
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001839 // Enable DISABLED preference, no initial limitation.
asapersson09f05612017-05-15 23:40:18 -07001840 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001841 video_stream_encoder_->SetSource(&source,
1842 webrtc::DegradationPreference::DISABLED);
asapersson09f05612017-05-15 23:40:18 -07001843
1844 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1845 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001846 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001847 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1848 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1849 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1850
1851 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001852 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001853 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001854 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1855 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1856 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1857
mflodmancc3d4422017-08-03 08:27:51 -07001858 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001859}
1860
mflodmancc3d4422017-08-03 08:27:51 -07001861TEST_F(VideoStreamEncoderTest,
1862 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001863 const int kWidth = 1280;
1864 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001865 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1866 DataRate::Zero(), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001867
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001868 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001869 AdaptingFrameForwarder source;
1870 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001871 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001872 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001873
1874 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001875 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001876 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001877 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1878 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1879
1880 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001881 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001882 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001883 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001884 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001885 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1886 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1887
1888 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001889 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001890 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001891 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1892 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1893 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1894
mflodmancc3d4422017-08-03 08:27:51 -07001895 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001896}
1897
mflodmancc3d4422017-08-03 08:27:51 -07001898TEST_F(VideoStreamEncoderTest,
1899 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001900 const int kWidth = 1280;
1901 const int kHeight = 720;
1902 const int kInputFps = 30;
Erik Språng610c7632019-03-06 15:37:33 +01001903 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1904 DataRate::Zero(), 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001905
1906 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1907 stats.input_frame_rate = kInputFps;
1908 stats_proxy_->SetMockStats(stats);
1909
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001910 // Expect no scaling to begin with (preference: MAINTAIN_FRAMERATE).
asapersson09f05612017-05-15 23:40:18 -07001911 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1912 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001913 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001914
1915 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001916 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001917 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1918 sink_.WaitForEncodedFrame(2);
1919 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1920
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001921 // Enable MAINTAIN_RESOLUTION preference.
asapersson09f05612017-05-15 23:40:18 -07001922 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001923 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001924 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001925 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001926
1927 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001928 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001929 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1930 sink_.WaitForEncodedFrame(3);
1931 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1932
1933 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001934 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001935 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001936
mflodmancc3d4422017-08-03 08:27:51 -07001937 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001938}
1939
mflodmancc3d4422017-08-03 08:27:51 -07001940TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001941 const int kWidth = 1280;
1942 const int kHeight = 720;
1943 const size_t kNumFrames = 10;
1944
Erik Språng610c7632019-03-06 15:37:33 +01001945 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1946 DataRate::Zero(), 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001947
asaperssond0de2952017-04-21 01:47:31 -07001948 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001949 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001950 video_source_.set_adaptation_enabled(true);
1951
1952 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1953 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1954
1955 int downscales = 0;
1956 for (size_t i = 1; i <= kNumFrames; i++) {
Åsa Persson8c1bf952018-09-13 10:42:19 +02001957 video_source_.IncomingCapturedFrame(
1958 CreateFrame(i * kFrameIntervalMs, kWidth, kHeight));
1959 WaitForEncodedFrame(i * kFrameIntervalMs);
asaperssond0de2952017-04-21 01:47:31 -07001960
asaperssonfab67072017-04-04 05:51:49 -07001961 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001962 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001963 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001964 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001965
1966 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1967 ++downscales;
1968
1969 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1970 EXPECT_EQ(downscales,
1971 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1972 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001973 }
mflodmancc3d4422017-08-03 08:27:51 -07001974 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001975}
1976
mflodmancc3d4422017-08-03 08:27:51 -07001977TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001978 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1979 const int kWidth = 1280;
1980 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01001981 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
1982 DataRate::Zero(), 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001983
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001984 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07001985 AdaptingFrameForwarder source;
1986 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001987 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001988 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07001989
Åsa Persson8c1bf952018-09-13 10:42:19 +02001990 int64_t timestamp_ms = kFrameIntervalMs;
1991 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001992 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001993 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07001994 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1995 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1996
1997 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001998 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001999 timestamp_ms += kFrameIntervalMs;
2000 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2001 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002002 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002003 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2004 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2005
2006 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002007 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002008 timestamp_ms += kFrameIntervalMs;
2009 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002010 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002011 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002012 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2013 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2014
2015 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002016 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002017 timestamp_ms += kFrameIntervalMs;
2018 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2019 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002020 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002021 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2022 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2023
2024 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002025 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002026 timestamp_ms += kFrameIntervalMs;
2027 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asapersson09f05612017-05-15 23:40:18 -07002028 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002029 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002030 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2031 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2032
mflodmancc3d4422017-08-03 08:27:51 -07002033 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002034}
2035
mflodmancc3d4422017-08-03 08:27:51 -07002036TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07002037 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
2038 const int kWidth = 1280;
2039 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01002040 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2041 DataRate::Zero(), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002042
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002043 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002044 AdaptingFrameForwarder source;
2045 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002046 video_stream_encoder_->SetSource(&source,
2047 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002048
Åsa Persson8c1bf952018-09-13 10:42:19 +02002049 int64_t timestamp_ms = kFrameIntervalMs;
2050 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07002051 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002052 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002053 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2054 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2055
2056 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002057 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002058 timestamp_ms += kFrameIntervalMs;
2059 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2060 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002061 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2062 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2063 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2064
2065 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002066 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002067 timestamp_ms += kFrameIntervalMs;
2068 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07002069 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002070 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002071 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2072 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2073
2074 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002075 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002076 timestamp_ms += kFrameIntervalMs;
2077 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2078 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002079 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2080 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2081 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2082
2083 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002084 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002085 timestamp_ms += kFrameIntervalMs;
2086 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07002087 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002088 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002089 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2090 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2091
mflodmancc3d4422017-08-03 08:27:51 -07002092 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002093}
2094
mflodmancc3d4422017-08-03 08:27:51 -07002095TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002096 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
2097 const int kWidth = 1280;
2098 const int kHeight = 720;
Erik Språng610c7632019-03-06 15:37:33 +01002099 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2100 DataRate::Zero(), 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002101
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002102 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002103 AdaptingFrameForwarder source;
2104 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002105 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002106 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002107
Åsa Persson8c1bf952018-09-13 10:42:19 +02002108 int64_t timestamp_ms = kFrameIntervalMs;
2109 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002110 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002111 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002112 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2113 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2114 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2115 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2116
2117 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002118 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002119 timestamp_ms += kFrameIntervalMs;
2120 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2121 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002122 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002123 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2124 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2125 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2126 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2127
2128 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07002129 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002130 timestamp_ms += kFrameIntervalMs;
2131 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2132 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002133 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002134 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2135 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2136 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2137 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2138
Jonathan Yubc771b72017-12-08 17:04:29 -08002139 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002140 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002141 timestamp_ms += kFrameIntervalMs;
2142 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2143 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002144 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002145 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2146 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002147 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002148 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2149
Jonathan Yubc771b72017-12-08 17:04:29 -08002150 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07002151 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002152 timestamp_ms += kFrameIntervalMs;
2153 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2154 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002155 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002156 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07002157 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2158 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2159 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2160 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2161
Jonathan Yubc771b72017-12-08 17:04:29 -08002162 // Trigger quality adapt down, expect no change (min resolution reached).
2163 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002164 timestamp_ms += kFrameIntervalMs;
2165 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2166 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002167 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
2168 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2169 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2170 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2171 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2172
2173 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002174 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002175 timestamp_ms += kFrameIntervalMs;
2176 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2177 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002178 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002179 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2180 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2181 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2182 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2183
2184 // Trigger cpu adapt up, expect upscaled resolution (640x360).
2185 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002186 timestamp_ms += kFrameIntervalMs;
2187 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2188 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002189 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2190 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2191 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2192 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2193 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2194
2195 // Trigger cpu adapt up, expect upscaled resolution (960x540).
2196 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002197 timestamp_ms += kFrameIntervalMs;
2198 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2199 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002200 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002201 last_wants = source.sink_wants();
2202 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2203 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002204 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002205 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2206
2207 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002208 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002209 timestamp_ms += kFrameIntervalMs;
2210 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2211 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002212 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002213 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2214 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002215 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002216 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2217
2218 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002219 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002220 timestamp_ms += kFrameIntervalMs;
2221 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002222 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002223 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002224 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002225 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2226 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002227 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002228 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002229
mflodmancc3d4422017-08-03 08:27:51 -07002230 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002231}
2232
mflodmancc3d4422017-08-03 08:27:51 -07002233TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002234 const int kWidth = 640;
2235 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002236
Erik Språng610c7632019-03-06 15:37:33 +01002237 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2238 DataRate::Zero(), 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002239
perkj803d97f2016-11-01 11:45:46 -07002240 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002241 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002242 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002243 }
2244
mflodmancc3d4422017-08-03 08:27:51 -07002245 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002246 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002247 video_source_.IncomingCapturedFrame(CreateFrame(
2248 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002249 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002250 }
2251
mflodmancc3d4422017-08-03 08:27:51 -07002252 video_stream_encoder_->Stop();
2253 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002254 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002255
perkj803d97f2016-11-01 11:45:46 -07002256 EXPECT_EQ(1,
2257 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2258 EXPECT_EQ(
2259 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2260}
2261
mflodmancc3d4422017-08-03 08:27:51 -07002262TEST_F(VideoStreamEncoderTest,
2263 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
Erik Språng610c7632019-03-06 15:37:33 +01002264 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2265 DataRate::Zero(), 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002266 const int kWidth = 640;
2267 const int kHeight = 360;
2268
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002269 video_stream_encoder_->SetSource(&video_source_,
2270 webrtc::DegradationPreference::DISABLED);
asaperssonf4e44af2017-04-19 02:01:06 -07002271
2272 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2273 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002274 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002275 }
2276
mflodmancc3d4422017-08-03 08:27:51 -07002277 video_stream_encoder_->Stop();
2278 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002279 stats_proxy_.reset();
2280
2281 EXPECT_EQ(0,
2282 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2283}
2284
mflodmancc3d4422017-08-03 08:27:51 -07002285TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002286 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02002287 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002288
2289 const int kDefaultFps = 30;
Erik Språng566124a2018-04-23 12:32:22 +02002290 const VideoBitrateAllocation expected_bitrate =
sprang57c2fff2017-01-16 06:24:02 -08002291 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002292 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002293
sprang57c2fff2017-01-16 06:24:02 -08002294 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
Niels Möller6bb5ab92019-01-11 11:11:10 +01002295 .Times(1);
Erik Språng610c7632019-03-06 15:37:33 +01002296 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kLowTargetBitrateBps),
2297 DataRate::Zero(), 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002298
sprang57c2fff2017-01-16 06:24:02 -08002299 video_source_.IncomingCapturedFrame(
Erik Språngd7329ca2019-02-21 21:19:53 +01002300 CreateFrame(rtc::TimeMillis(), codec_width_, codec_height_));
2301 WaitForEncodedFrame(rtc::TimeMillis());
2302 absl::optional<VideoBitrateAllocation> bitrate_allocation =
2303 fake_encoder_.GetAndResetLastBitrateAllocation();
2304 // Check that encoder has been updated too, not just allocation observer.
2305 EXPECT_EQ(bitrate_allocation->get_sum_bps(), kLowTargetBitrateBps);
2306 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec / kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002307
2308 // Not called on second frame.
2309 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2310 .Times(0);
2311 video_source_.IncomingCapturedFrame(
Erik Språngd7329ca2019-02-21 21:19:53 +01002312 CreateFrame(rtc::TimeMillis(), codec_width_, codec_height_));
2313 WaitForEncodedFrame(rtc::TimeMillis());
2314 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec / kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002315
2316 // Called after a process interval.
2317 const int64_t kProcessIntervalMs =
2318 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang57c2fff2017-01-16 06:24:02 -08002319 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2320 .Times(1);
Erik Språngd7329ca2019-02-21 21:19:53 +01002321 const int64_t start_time_ms = rtc::TimeMillis();
2322 while (rtc::TimeMillis() - start_time_ms < kProcessIntervalMs) {
2323 video_source_.IncomingCapturedFrame(
2324 CreateFrame(rtc::TimeMillis(), codec_width_, codec_height_));
2325 WaitForEncodedFrame(rtc::TimeMillis());
2326 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec / kDefaultFps);
2327 }
2328
2329 // Since rates are unchanged, encoder should not be reconfigured.
2330 EXPECT_FALSE(fake_encoder_.GetAndResetLastBitrateAllocation().has_value());
sprang57c2fff2017-01-16 06:24:02 -08002331
mflodmancc3d4422017-08-03 08:27:51 -07002332 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002333}
2334
Niels Möller7dc26b72017-12-06 10:27:48 +01002335TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2336 const int kFrameWidth = 1280;
2337 const int kFrameHeight = 720;
2338 const int kFramerate = 24;
2339
Erik Språng610c7632019-03-06 15:37:33 +01002340 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2341 DataRate::Zero(), 0, 0);
Niels Möller7dc26b72017-12-06 10:27:48 +01002342 test::FrameForwarder source;
2343 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002344 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002345
2346 // Insert a single frame, triggering initial configuration.
2347 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2348 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2349
2350 EXPECT_EQ(
2351 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2352 kDefaultFramerate);
2353
2354 // Trigger reconfigure encoder (without resetting the entire instance).
2355 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002356 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002357 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2358 video_encoder_config.number_of_streams = 1;
2359 video_encoder_config.video_stream_factory =
2360 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2361 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002362 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002363 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2364
2365 // Detector should be updated with fps limit from codec config.
2366 EXPECT_EQ(
2367 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2368 kFramerate);
2369
2370 // Trigger overuse, max framerate should be reduced.
2371 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2372 stats.input_frame_rate = kFramerate;
2373 stats_proxy_->SetMockStats(stats);
2374 video_stream_encoder_->TriggerCpuOveruse();
2375 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2376 int adapted_framerate =
2377 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2378 EXPECT_LT(adapted_framerate, kFramerate);
2379
2380 // Trigger underuse, max framerate should go back to codec configured fps.
2381 // Set extra low fps, to make sure it's actually reset, not just incremented.
2382 stats = stats_proxy_->GetStats();
2383 stats.input_frame_rate = adapted_framerate / 2;
2384 stats_proxy_->SetMockStats(stats);
2385 video_stream_encoder_->TriggerCpuNormalUsage();
2386 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2387 EXPECT_EQ(
2388 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2389 kFramerate);
2390
2391 video_stream_encoder_->Stop();
2392}
2393
2394TEST_F(VideoStreamEncoderTest,
2395 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2396 const int kFrameWidth = 1280;
2397 const int kFrameHeight = 720;
2398 const int kLowFramerate = 15;
2399 const int kHighFramerate = 25;
2400
Erik Språng610c7632019-03-06 15:37:33 +01002401 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2402 DataRate::Zero(), 0, 0);
Niels Möller7dc26b72017-12-06 10:27:48 +01002403 test::FrameForwarder source;
2404 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002405 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002406
2407 // Trigger initial configuration.
2408 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002409 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002410 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2411 video_encoder_config.number_of_streams = 1;
2412 video_encoder_config.video_stream_factory =
2413 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2414 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2415 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002416 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002417 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2418
2419 EXPECT_EQ(
2420 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2421 kLowFramerate);
2422
2423 // Trigger overuse, max framerate should be reduced.
2424 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2425 stats.input_frame_rate = kLowFramerate;
2426 stats_proxy_->SetMockStats(stats);
2427 video_stream_encoder_->TriggerCpuOveruse();
2428 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2429 int adapted_framerate =
2430 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2431 EXPECT_LT(adapted_framerate, kLowFramerate);
2432
2433 // Reconfigure the encoder with a new (higher max framerate), max fps should
2434 // still respect the adaptation.
2435 video_encoder_config.video_stream_factory =
2436 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2437 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2438 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002439 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002440 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2441
2442 EXPECT_EQ(
2443 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2444 adapted_framerate);
2445
2446 // Trigger underuse, max framerate should go back to codec configured fps.
2447 stats = stats_proxy_->GetStats();
2448 stats.input_frame_rate = adapted_framerate;
2449 stats_proxy_->SetMockStats(stats);
2450 video_stream_encoder_->TriggerCpuNormalUsage();
2451 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2452 EXPECT_EQ(
2453 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2454 kHighFramerate);
2455
2456 video_stream_encoder_->Stop();
2457}
2458
mflodmancc3d4422017-08-03 08:27:51 -07002459TEST_F(VideoStreamEncoderTest,
2460 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002461 const int kFrameWidth = 1280;
2462 const int kFrameHeight = 720;
2463 const int kFramerate = 24;
2464
Erik Språng610c7632019-03-06 15:37:33 +01002465 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2466 DataRate::Zero(), 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002467 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002468 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002469 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangfda496a2017-06-15 04:21:07 -07002470
2471 // Trigger initial configuration.
2472 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002473 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002474 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2475 video_encoder_config.number_of_streams = 1;
2476 video_encoder_config.video_stream_factory =
2477 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2478 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002479 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002480 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002481 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002482
Niels Möller7dc26b72017-12-06 10:27:48 +01002483 EXPECT_EQ(
2484 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2485 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002486
2487 // Trigger overuse, max framerate should be reduced.
2488 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2489 stats.input_frame_rate = kFramerate;
2490 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002491 video_stream_encoder_->TriggerCpuOveruse();
2492 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002493 int adapted_framerate =
2494 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002495 EXPECT_LT(adapted_framerate, kFramerate);
2496
2497 // Change degradation preference to not enable framerate scaling. Target
2498 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002499 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002500 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -07002501 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002502 EXPECT_EQ(
2503 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2504 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002505
mflodmancc3d4422017-08-03 08:27:51 -07002506 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002507}
2508
mflodmancc3d4422017-08-03 08:27:51 -07002509TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002510 const int kTooLowBitrateForFrameSizeBps = 10000;
Erik Språng610c7632019-03-06 15:37:33 +01002511 video_stream_encoder_->OnBitrateUpdated(
2512 DataRate::bps(kTooLowBitrateForFrameSizeBps), DataRate::Zero(), 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002513 const int kWidth = 640;
2514 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002515
asaperssonfab67072017-04-04 05:51:49 -07002516 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002517
2518 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002519 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002520
2521 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002522 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002523
sprangc5d62e22017-04-02 23:53:04 -07002524 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002525
asaperssonfab67072017-04-04 05:51:49 -07002526 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002527 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002528 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002529
2530 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002531 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002532
sprangc5d62e22017-04-02 23:53:04 -07002533 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002534
mflodmancc3d4422017-08-03 08:27:51 -07002535 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002536}
2537
mflodmancc3d4422017-08-03 08:27:51 -07002538TEST_F(VideoStreamEncoderTest,
2539 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002540 const int kTooLowBitrateForFrameSizeBps = 10000;
Erik Språng610c7632019-03-06 15:37:33 +01002541 video_stream_encoder_->OnBitrateUpdated(
2542 DataRate::bps(kTooLowBitrateForFrameSizeBps), DataRate::Zero(), 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002543 const int kWidth = 640;
2544 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002545
2546 // We expect the n initial frames to get dropped.
2547 int i;
2548 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002549 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002550 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002551 }
2552 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002553 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002554 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002555
2556 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002557 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002558
mflodmancc3d4422017-08-03 08:27:51 -07002559 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002560}
2561
mflodmancc3d4422017-08-03 08:27:51 -07002562TEST_F(VideoStreamEncoderTest,
2563 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002564 const int kWidth = 640;
2565 const int kHeight = 360;
Erik Språng610c7632019-03-06 15:37:33 +01002566 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kLowTargetBitrateBps),
2567 DataRate::Zero(), 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002568
2569 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002570 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002571 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason2bc68642017-02-07 07:02:22 -08002572
asaperssonfab67072017-04-04 05:51:49 -07002573 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002574 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002575 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002576
mflodmancc3d4422017-08-03 08:27:51 -07002577 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002578}
2579
mflodmancc3d4422017-08-03 08:27:51 -07002580TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002581 const int kWidth = 640;
2582 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002583 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02002584
2585 VideoEncoderConfig video_encoder_config;
2586 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
2587 // Make format different, to force recreation of encoder.
2588 video_encoder_config.video_format.parameters["foo"] = "foo";
2589 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002590 kMaxPayloadLength);
Erik Språng610c7632019-03-06 15:37:33 +01002591 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kLowTargetBitrateBps),
2592 DataRate::Zero(), 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002593
kthelgasonb83797b2017-02-14 11:57:25 -08002594 // Force quality scaler reconfiguration by resetting the source.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002595 video_stream_encoder_->SetSource(&video_source_,
2596 webrtc::DegradationPreference::BALANCED);
kthelgasonad9010c2017-02-14 00:46:51 -08002597
asaperssonfab67072017-04-04 05:51:49 -07002598 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002599 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002600 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002601
mflodmancc3d4422017-08-03 08:27:51 -07002602 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002603 fake_encoder_.SetQualityScaling(true);
2604}
2605
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002606TEST_F(VideoStreamEncoderTest, InitialFrameDropActivatesWhenBWEstimateReady) {
2607 webrtc::test::ScopedFieldTrials field_trials(
2608 "WebRTC-InitialFramedrop/Enabled/");
2609 // Reset encoder for field trials to take effect.
2610 ConfigureEncoder(video_encoder_config_.Copy());
2611 const int kTooLowBitrateForFrameSizeBps = 10000;
2612 const int kWidth = 640;
2613 const int kHeight = 360;
2614
Erik Språng610c7632019-03-06 15:37:33 +01002615 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2616 DataRate::Zero(), 0, 0);
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002617 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2618 // Frame should not be dropped.
2619 WaitForEncodedFrame(1);
2620
Erik Språng610c7632019-03-06 15:37:33 +01002621 video_stream_encoder_->OnBitrateUpdated(
2622 DataRate::bps(kTooLowBitrateForFrameSizeBps), DataRate::Zero(), 0, 0);
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002623 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
2624 // Expect to drop this frame, the wait should time out.
2625 ExpectDroppedFrame();
2626
2627 // Expect the sink_wants to specify a scaled frame.
2628 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
2629 video_stream_encoder_->Stop();
2630}
2631
mflodmancc3d4422017-08-03 08:27:51 -07002632TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002633 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2634 const int kTooSmallWidth = 10;
2635 const int kTooSmallHeight = 10;
Erik Språng610c7632019-03-06 15:37:33 +01002636 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2637 DataRate::Zero(), 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002638
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002639 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002640 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002641 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002642 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002643 VerifyNoLimitation(source.sink_wants());
2644 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2645
2646 // Trigger adapt down, too small frame, expect no change.
2647 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002648 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002649 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002650 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002651 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2652 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2653
mflodmancc3d4422017-08-03 08:27:51 -07002654 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002655}
2656
mflodmancc3d4422017-08-03 08:27:51 -07002657TEST_F(VideoStreamEncoderTest,
2658 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002659 const int kTooSmallWidth = 10;
2660 const int kTooSmallHeight = 10;
2661 const int kFpsLimit = 7;
Erik Språng610c7632019-03-06 15:37:33 +01002662 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2663 DataRate::Zero(), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002664
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002665 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002666 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002667 video_stream_encoder_->SetSource(&source,
2668 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002669 VerifyNoLimitation(source.sink_wants());
2670 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2671 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2672
2673 // Trigger adapt down, expect limited framerate.
2674 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002675 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002676 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002677 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2678 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2679 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2680 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2681
2682 // Trigger adapt down, too small frame, expect no change.
2683 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002684 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002685 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002686 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2687 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2688 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2689 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2690
mflodmancc3d4422017-08-03 08:27:51 -07002691 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002692}
2693
mflodmancc3d4422017-08-03 08:27:51 -07002694TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002695 fake_encoder_.ForceInitEncodeFailure(true);
Erik Språng610c7632019-03-06 15:37:33 +01002696 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2697 DataRate::Zero(), 0, 0);
Niels Möllerf1338562018-04-26 09:51:47 +02002698 ResetEncoder("VP8", 2, 1, 1, false);
asapersson02465b82017-04-10 01:12:52 -07002699 const int kFrameWidth = 1280;
2700 const int kFrameHeight = 720;
2701 video_source_.IncomingCapturedFrame(
2702 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002703 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002704 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002705}
2706
sprangb1ca0732017-02-01 08:38:12 -08002707// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002708TEST_F(VideoStreamEncoderTest,
2709 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
Erik Språng610c7632019-03-06 15:37:33 +01002710 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2711 DataRate::Zero(), 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002712
2713 const int kFrameWidth = 1280;
2714 const int kFrameHeight = 720;
2715 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002716 // requested by
2717 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002718 video_source_.set_adaptation_enabled(true);
2719
2720 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002721 CreateFrame(1 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002722 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002723
2724 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002725 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002726 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002727 CreateFrame(2 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002728 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002729
asaperssonfab67072017-04-04 05:51:49 -07002730 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002731 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002732 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002733 CreateFrame(3 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002734 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002735
mflodmancc3d4422017-08-03 08:27:51 -07002736 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002737}
sprangfe627f32017-03-29 08:24:59 -07002738
mflodmancc3d4422017-08-03 08:27:51 -07002739TEST_F(VideoStreamEncoderTest,
2740 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002741 const int kFrameWidth = 1280;
2742 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07002743
Erik Språng610c7632019-03-06 15:37:33 +01002744 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2745 DataRate::Zero(), 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -07002746 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002747 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002748 video_source_.set_adaptation_enabled(true);
2749
sprang4847ae62017-06-27 07:06:52 -07002750 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002751
2752 video_source_.IncomingCapturedFrame(
2753 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002754 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002755
2756 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002757 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002758
2759 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002760 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002761 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002762 video_source_.IncomingCapturedFrame(
2763 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002764 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002765 }
2766
2767 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002768 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002769 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002770 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002771 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002772 video_source_.IncomingCapturedFrame(
2773 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002774 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002775 ++num_frames_dropped;
2776 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002777 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002778 }
2779 }
2780
sprang4847ae62017-06-27 07:06:52 -07002781 // Add some slack to account for frames dropped by the frame dropper.
2782 const int kErrorMargin = 1;
2783 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002784 kErrorMargin);
2785
2786 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002787 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002788 num_frames_dropped = 0;
Åsa Persson8c1bf952018-09-13 10:42:19 +02002789 for (int i = 0; i <= max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002790 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002791 video_source_.IncomingCapturedFrame(
2792 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002793 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002794 ++num_frames_dropped;
2795 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002796 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002797 }
2798 }
sprang4847ae62017-06-27 07:06:52 -07002799 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002800 kErrorMargin);
2801
2802 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002803 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002804 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002805 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002806 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002807 video_source_.IncomingCapturedFrame(
2808 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002809 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002810 ++num_frames_dropped;
2811 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002812 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002813 }
2814 }
sprang4847ae62017-06-27 07:06:52 -07002815 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002816 kErrorMargin);
2817
2818 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002819 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002820 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002821 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002822 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002823 video_source_.IncomingCapturedFrame(
2824 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002825 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002826 ++num_frames_dropped;
2827 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01002828 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07002829 }
2830 }
2831 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2832
mflodmancc3d4422017-08-03 08:27:51 -07002833 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002834}
2835
mflodmancc3d4422017-08-03 08:27:51 -07002836TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002837 const int kFramerateFps = 5;
2838 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07002839 const int kFrameWidth = 1280;
2840 const int kFrameHeight = 720;
2841
sprang4847ae62017-06-27 07:06:52 -07002842 // Reconfigure encoder with two temporal layers and screensharing, which will
2843 // disable frame dropping and make testing easier.
Niels Möllerf1338562018-04-26 09:51:47 +02002844 ResetEncoder("VP8", 1, 2, 1, true);
sprang4847ae62017-06-27 07:06:52 -07002845
Erik Språng610c7632019-03-06 15:37:33 +01002846 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2847 DataRate::Zero(), 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -07002848 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002849 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07002850 video_source_.set_adaptation_enabled(true);
2851
sprang4847ae62017-06-27 07:06:52 -07002852 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002853
2854 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08002855 rtc::VideoSinkWants last_wants;
2856 do {
2857 last_wants = video_source_.sink_wants();
2858
sprangc5d62e22017-04-02 23:53:04 -07002859 // Insert frames to get a new fps estimate...
2860 for (int j = 0; j < kFramerateFps; ++j) {
2861 video_source_.IncomingCapturedFrame(
2862 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08002863 if (video_source_.last_sent_width()) {
2864 sink_.WaitForEncodedFrame(timestamp_ms);
2865 }
sprangc5d62e22017-04-02 23:53:04 -07002866 timestamp_ms += kFrameIntervalMs;
Yves Gerey665174f2018-06-19 15:03:05 +02002867 fake_clock_.AdvanceTimeMicros(kFrameIntervalMs *
2868 rtc::kNumMicrosecsPerMillisec);
sprangc5d62e22017-04-02 23:53:04 -07002869 }
2870 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002871 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08002872 } while (video_source_.sink_wants().max_framerate_fps <
2873 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07002874
Jonathan Yubc771b72017-12-08 17:04:29 -08002875 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07002876
mflodmancc3d4422017-08-03 08:27:51 -07002877 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002878}
asaperssonf7e294d2017-06-13 23:25:22 -07002879
mflodmancc3d4422017-08-03 08:27:51 -07002880TEST_F(VideoStreamEncoderTest,
2881 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002882 const int kWidth = 1280;
2883 const int kHeight = 720;
2884 const int64_t kFrameIntervalMs = 150;
2885 int64_t timestamp_ms = kFrameIntervalMs;
Erik Språng610c7632019-03-06 15:37:33 +01002886 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
2887 DataRate::Zero(), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002888
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002889 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002890 AdaptingFrameForwarder source;
2891 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002892 video_stream_encoder_->SetSource(&source,
2893 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002894 timestamp_ms += kFrameIntervalMs;
2895 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002896 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002897 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002898 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2899 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2900 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2901
2902 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002903 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002904 timestamp_ms += kFrameIntervalMs;
2905 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002906 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002907 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2908 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2909 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2910 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2911
2912 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002913 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002914 timestamp_ms += kFrameIntervalMs;
2915 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002916 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002917 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2918 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2919 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2920 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2921
2922 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002923 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002924 timestamp_ms += kFrameIntervalMs;
2925 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002926 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002927 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2928 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2929 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2930 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2931
2932 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002933 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002934 timestamp_ms += kFrameIntervalMs;
2935 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002936 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002937 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2938 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2939 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2940 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2941
2942 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002943 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002944 timestamp_ms += kFrameIntervalMs;
2945 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002946 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002947 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2948 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2949 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2950 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2951
2952 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002953 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002954 timestamp_ms += kFrameIntervalMs;
2955 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002956 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002957 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2958 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2959 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2960 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2961
2962 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002963 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002964 timestamp_ms += kFrameIntervalMs;
2965 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002966 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002967 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2968 rtc::VideoSinkWants last_wants = source.sink_wants();
2969 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2970 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2971 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2972
2973 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002974 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002975 timestamp_ms += kFrameIntervalMs;
2976 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002977 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002978 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2979 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2980 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2981 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2982
2983 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002984 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002985 timestamp_ms += kFrameIntervalMs;
2986 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002987 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002988 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2989 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2990 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2991 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2992
2993 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002994 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002995 timestamp_ms += kFrameIntervalMs;
2996 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002997 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002998 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2999 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3000 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3001 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3002
3003 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003004 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003005 timestamp_ms += kFrameIntervalMs;
3006 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003007 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003008 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
3009 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3010 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3011 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3012
3013 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003014 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003015 timestamp_ms += kFrameIntervalMs;
3016 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003017 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003018 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3019 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3020 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3021 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3022
3023 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003024 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003025 timestamp_ms += kFrameIntervalMs;
3026 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003027 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003028 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
3029 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3030 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3031 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3032
3033 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003034 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003035 timestamp_ms += kFrameIntervalMs;
3036 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003037 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003038 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3039 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3040 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3041 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3042
3043 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003044 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003045 timestamp_ms += kFrameIntervalMs;
3046 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003047 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003048 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02003049 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003050 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3051 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3052 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3053
3054 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003055 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003056 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003057 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3058
mflodmancc3d4422017-08-03 08:27:51 -07003059 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003060}
3061
mflodmancc3d4422017-08-03 08:27:51 -07003062TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07003063 const int kWidth = 1280;
3064 const int kHeight = 720;
3065 const int64_t kFrameIntervalMs = 150;
3066 int64_t timestamp_ms = kFrameIntervalMs;
Erik Språng610c7632019-03-06 15:37:33 +01003067 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3068 DataRate::Zero(), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07003069
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003070 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07003071 AdaptingFrameForwarder source;
3072 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003073 video_stream_encoder_->SetSource(&source,
3074 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07003075 timestamp_ms += kFrameIntervalMs;
3076 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003077 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003078 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003079 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3080 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3081 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3082 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3083 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3084 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3085
3086 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003087 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003088 timestamp_ms += kFrameIntervalMs;
3089 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003090 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003091 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
3092 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3093 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3094 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3095 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3096 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3097 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3098
3099 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003100 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003101 timestamp_ms += kFrameIntervalMs;
3102 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003103 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003104 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
3105 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3106 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3107 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3108 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3109 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3110 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3111
3112 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003113 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003114 timestamp_ms += kFrameIntervalMs;
3115 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003116 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003117 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
3118 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3119 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3120 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3121 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3122 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3123 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3124
3125 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003126 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003127 timestamp_ms += kFrameIntervalMs;
3128 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003129 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003130 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
3131 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3132 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3133 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3134 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3135 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3136 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3137
3138 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003139 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003140 timestamp_ms += kFrameIntervalMs;
3141 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003142 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003143 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3144 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3145 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3146 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3147 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3148 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3149 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3150
3151 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003152 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003153 timestamp_ms += kFrameIntervalMs;
3154 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003155 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003156 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02003157 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003158 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3159 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3160 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3161 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3162 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3163 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3164
3165 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003166 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003167 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003168 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3169 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3170
mflodmancc3d4422017-08-03 08:27:51 -07003171 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003172}
3173
mflodmancc3d4422017-08-03 08:27:51 -07003174TEST_F(VideoStreamEncoderTest,
3175 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07003176 const int kWidth = 640;
3177 const int kHeight = 360;
3178 const int kFpsLimit = 15;
3179 const int64_t kFrameIntervalMs = 150;
3180 int64_t timestamp_ms = kFrameIntervalMs;
Erik Språng610c7632019-03-06 15:37:33 +01003181 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3182 DataRate::Zero(), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07003183
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003184 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07003185 AdaptingFrameForwarder source;
3186 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003187 video_stream_encoder_->SetSource(&source,
3188 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07003189 timestamp_ms += kFrameIntervalMs;
3190 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003191 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003192 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003193 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3194 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3195 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3196 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3197 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3198 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3199
3200 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003201 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003202 timestamp_ms += kFrameIntervalMs;
3203 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003204 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003205 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
3206 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3207 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3208 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3209 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3210 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3211 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3212
3213 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003214 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003215 timestamp_ms += kFrameIntervalMs;
3216 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003217 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003218 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
3219 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3220 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3221 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3222 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3223 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3224 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3225
3226 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003227 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003228 timestamp_ms += kFrameIntervalMs;
3229 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003230 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003231 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3232 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3233 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3234 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3235 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3236 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3237 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3238
3239 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003240 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003241 timestamp_ms += kFrameIntervalMs;
3242 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003243 WaitForEncodedFrame(timestamp_ms);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003244 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003245 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3246 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3247 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3248 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3249 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3250 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3251
3252 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003253 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003254 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003255 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3256 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3257
mflodmancc3d4422017-08-03 08:27:51 -07003258 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003259}
3260
mflodmancc3d4422017-08-03 08:27:51 -07003261TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003262 // Simulates simulcast behavior and makes highest stream resolutions divisible
3263 // by 4.
3264 class CroppingVideoStreamFactory
3265 : public VideoEncoderConfig::VideoStreamFactoryInterface {
3266 public:
3267 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
3268 int framerate)
3269 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
3270 EXPECT_GT(num_temporal_layers, 0u);
3271 EXPECT_GT(framerate, 0);
3272 }
3273
3274 private:
3275 std::vector<VideoStream> CreateEncoderStreams(
3276 int width,
3277 int height,
3278 const VideoEncoderConfig& encoder_config) override {
Yves Gerey665174f2018-06-19 15:03:05 +02003279 std::vector<VideoStream> streams = test::CreateVideoStreams(
3280 width - width % 4, height - height % 4, encoder_config);
ilnik6b826ef2017-06-16 06:53:48 -07003281 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +01003282 stream.num_temporal_layers = num_temporal_layers_;
ilnik6b826ef2017-06-16 06:53:48 -07003283 stream.max_framerate = framerate_;
3284 }
3285 return streams;
3286 }
3287
3288 const size_t num_temporal_layers_;
3289 const int framerate_;
3290 };
3291
3292 const int kFrameWidth = 1920;
3293 const int kFrameHeight = 1080;
3294 // 3/4 of 1920.
3295 const int kAdaptedFrameWidth = 1440;
3296 // 3/4 of 1080 rounded down to multiple of 4.
3297 const int kAdaptedFrameHeight = 808;
3298 const int kFramerate = 24;
3299
Erik Språng610c7632019-03-06 15:37:33 +01003300 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3301 DataRate::Zero(), 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003302 // Trigger reconfigure encoder (without resetting the entire instance).
3303 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02003304 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07003305 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3306 video_encoder_config.number_of_streams = 1;
3307 video_encoder_config.video_stream_factory =
3308 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003309 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02003310 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07003311 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003312
3313 video_source_.set_adaptation_enabled(true);
3314
3315 video_source_.IncomingCapturedFrame(
3316 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003317 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003318
3319 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003320 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003321 video_source_.IncomingCapturedFrame(
3322 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003323 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003324
mflodmancc3d4422017-08-03 08:27:51 -07003325 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003326}
3327
mflodmancc3d4422017-08-03 08:27:51 -07003328TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003329 const int kFrameWidth = 1280;
3330 const int kFrameHeight = 720;
3331 const int kLowFps = 2;
3332 const int kHighFps = 30;
3333
Erik Språng610c7632019-03-06 15:37:33 +01003334 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3335 DataRate::Zero(), 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003336
3337 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3338 max_framerate_ = kLowFps;
3339
3340 // Insert 2 seconds of 2fps video.
3341 for (int i = 0; i < kLowFps * 2; ++i) {
3342 video_source_.IncomingCapturedFrame(
3343 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3344 WaitForEncodedFrame(timestamp_ms);
3345 timestamp_ms += 1000 / kLowFps;
3346 }
3347
3348 // Make sure encoder is updated with new target.
Erik Språng610c7632019-03-06 15:37:33 +01003349 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3350 DataRate::Zero(), 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003351 video_source_.IncomingCapturedFrame(
3352 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3353 WaitForEncodedFrame(timestamp_ms);
3354 timestamp_ms += 1000 / kLowFps;
3355
3356 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3357
3358 // Insert 30fps frames for just a little more than the forced update period.
3359 const int kVcmTimerIntervalFrames =
3360 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3361 const int kFrameIntervalMs = 1000 / kHighFps;
3362 max_framerate_ = kHighFps;
3363 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3364 video_source_.IncomingCapturedFrame(
3365 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3366 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3367 // be dropped if the encoder hans't been updated with the new higher target
3368 // framerate yet, causing it to overshoot the target bitrate and then
3369 // suffering the wrath of the media optimizer.
3370 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3371 timestamp_ms += kFrameIntervalMs;
3372 }
3373
3374 // Don expect correct measurement just yet, but it should be higher than
3375 // before.
3376 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3377
mflodmancc3d4422017-08-03 08:27:51 -07003378 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003379}
3380
mflodmancc3d4422017-08-03 08:27:51 -07003381TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003382 const int kFrameWidth = 1280;
3383 const int kFrameHeight = 720;
3384 const int kTargetBitrateBps = 1000000;
3385
3386 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02003387 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
Erik Språng610c7632019-03-06 15:37:33 +01003388 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3389 DataRate::Zero(), 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -07003390 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003391
3392 // Insert a first video frame, causes another bitrate update.
3393 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3394 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3395 video_source_.IncomingCapturedFrame(
3396 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3397 WaitForEncodedFrame(timestamp_ms);
3398
3399 // Next, simulate video suspension due to pacer queue overrun.
Erik Språng610c7632019-03-06 15:37:33 +01003400 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(0), DataRate::Zero(), 0,
3401 1);
sprang4847ae62017-06-27 07:06:52 -07003402
3403 // Skip ahead until a new periodic parameter update should have occured.
3404 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3405 fake_clock_.AdvanceTimeMicros(
3406 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3407 rtc::kNumMicrosecsPerMillisec);
3408
3409 // Bitrate observer should not be called.
3410 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3411 video_source_.IncomingCapturedFrame(
3412 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3413 ExpectDroppedFrame();
3414
mflodmancc3d4422017-08-03 08:27:51 -07003415 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003416}
ilnik6b826ef2017-06-16 06:53:48 -07003417
Niels Möller4db138e2018-04-19 09:04:13 +02003418TEST_F(VideoStreamEncoderTest,
3419 DefaultCpuAdaptationThresholdsForSoftwareEncoder) {
3420 const int kFrameWidth = 1280;
3421 const int kFrameHeight = 720;
3422 const CpuOveruseOptions default_options;
Erik Språng610c7632019-03-06 15:37:33 +01003423 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3424 DataRate::Zero(), 0, 0);
Niels Möller4db138e2018-04-19 09:04:13 +02003425 video_source_.IncomingCapturedFrame(
3426 CreateFrame(1, kFrameWidth, kFrameHeight));
3427 WaitForEncodedFrame(1);
3428 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3429 .low_encode_usage_threshold_percent,
3430 default_options.low_encode_usage_threshold_percent);
3431 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3432 .high_encode_usage_threshold_percent,
3433 default_options.high_encode_usage_threshold_percent);
3434 video_stream_encoder_->Stop();
3435}
3436
3437TEST_F(VideoStreamEncoderTest,
3438 HigherCpuAdaptationThresholdsForHardwareEncoder) {
3439 const int kFrameWidth = 1280;
3440 const int kFrameHeight = 720;
3441 CpuOveruseOptions hardware_options;
3442 hardware_options.low_encode_usage_threshold_percent = 150;
3443 hardware_options.high_encode_usage_threshold_percent = 200;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +01003444 fake_encoder_.SetIsHardwareAccelerated(true);
Niels Möller4db138e2018-04-19 09:04:13 +02003445
Erik Språng610c7632019-03-06 15:37:33 +01003446 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3447 DataRate::Zero(), 0, 0);
Niels Möller4db138e2018-04-19 09:04:13 +02003448 video_source_.IncomingCapturedFrame(
3449 CreateFrame(1, kFrameWidth, kFrameHeight));
3450 WaitForEncodedFrame(1);
3451 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3452 .low_encode_usage_threshold_percent,
3453 hardware_options.low_encode_usage_threshold_percent);
3454 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3455 .high_encode_usage_threshold_percent,
3456 hardware_options.high_encode_usage_threshold_percent);
3457 video_stream_encoder_->Stop();
3458}
3459
Niels Möller6bb5ab92019-01-11 11:11:10 +01003460TEST_F(VideoStreamEncoderTest, DropsFramesWhenEncoderOvershoots) {
3461 const int kFrameWidth = 320;
3462 const int kFrameHeight = 240;
3463 const int kFps = 30;
3464 const int kTargetBitrateBps = 120000;
3465 const int kNumFramesInRun = kFps * 5; // Runs of five seconds.
3466
Erik Språng610c7632019-03-06 15:37:33 +01003467 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3468 DataRate::Zero(), 0, 0);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003469
3470 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3471 max_framerate_ = kFps;
3472
3473 // Insert 3 seconds of video, verify number of drops with normal bitrate.
3474 fake_encoder_.SimulateOvershoot(1.0);
3475 int num_dropped = 0;
3476 for (int i = 0; i < kNumFramesInRun; ++i) {
3477 video_source_.IncomingCapturedFrame(
3478 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3479 // Wait up to two frame durations for a frame to arrive.
3480 if (!TimedWaitForEncodedFrame(timestamp_ms, 2 * 1000 / kFps)) {
3481 ++num_dropped;
3482 }
3483 timestamp_ms += 1000 / kFps;
3484 }
3485
Erik Språnga8d48ab2019-02-08 14:17:40 +01003486 // Framerate should be measured to be near the expected target rate.
3487 EXPECT_NEAR(fake_encoder_.GetLastFramerate(), kFps, 1);
3488
3489 // Frame drops should be within 5% of expected 0%.
3490 EXPECT_NEAR(num_dropped, 0, 5 * kNumFramesInRun / 100);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003491
3492 // Make encoder produce frames at double the expected bitrate during 3 seconds
3493 // of video, verify number of drops. Rate needs to be slightly changed in
3494 // order to force the rate to be reconfigured.
Erik Språng7ca375c2019-02-06 16:20:17 +01003495 double overshoot_factor = 2.0;
3496 if (RateControlSettings::ParseFromFieldTrials().UseEncoderBitrateAdjuster()) {
3497 // With bitrate adjuster, when need to overshoot even more to trigger
3498 // frame dropping.
3499 overshoot_factor *= 2;
3500 }
3501 fake_encoder_.SimulateOvershoot(overshoot_factor);
Erik Språng610c7632019-03-06 15:37:33 +01003502 video_stream_encoder_->OnBitrateUpdated(
3503 DataRate::bps(kTargetBitrateBps + 1000), DataRate::Zero(), 0, 0);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003504 num_dropped = 0;
3505 for (int i = 0; i < kNumFramesInRun; ++i) {
3506 video_source_.IncomingCapturedFrame(
3507 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3508 // Wait up to two frame durations for a frame to arrive.
3509 if (!TimedWaitForEncodedFrame(timestamp_ms, 2 * 1000 / kFps)) {
3510 ++num_dropped;
3511 }
3512 timestamp_ms += 1000 / kFps;
3513 }
3514
Erik Språng610c7632019-03-06 15:37:33 +01003515 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3516 DataRate::Zero(), 0, 0);
Erik Språnga8d48ab2019-02-08 14:17:40 +01003517
3518 // Target framerate should be still be near the expected target, despite
3519 // the frame drops.
3520 EXPECT_NEAR(fake_encoder_.GetLastFramerate(), kFps, 1);
3521
3522 // Frame drops should be within 5% of expected 50%.
3523 EXPECT_NEAR(num_dropped, kNumFramesInRun / 2, 5 * kNumFramesInRun / 100);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003524
3525 video_stream_encoder_->Stop();
3526}
3527
3528TEST_F(VideoStreamEncoderTest, ConfiguresCorrectFrameRate) {
3529 const int kFrameWidth = 320;
3530 const int kFrameHeight = 240;
3531 const int kActualInputFps = 24;
3532 const int kTargetBitrateBps = 120000;
3533
3534 ASSERT_GT(max_framerate_, kActualInputFps);
3535
3536 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3537 max_framerate_ = kActualInputFps;
Erik Språng610c7632019-03-06 15:37:33 +01003538 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3539 DataRate::Zero(), 0, 0);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003540
3541 // Insert 3 seconds of video, with an input fps lower than configured max.
3542 for (int i = 0; i < kActualInputFps * 3; ++i) {
3543 video_source_.IncomingCapturedFrame(
3544 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3545 // Wait up to two frame durations for a frame to arrive.
3546 WaitForEncodedFrame(timestamp_ms);
3547 timestamp_ms += 1000 / kActualInputFps;
3548 }
3549
3550 EXPECT_NEAR(kActualInputFps, fake_encoder_.GetLastFramerate(), 1);
3551
3552 video_stream_encoder_->Stop();
3553}
3554
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01003555TEST_F(VideoStreamEncoderTest, AccumulatesUpdateRectOnDroppedFrames) {
3556 VideoFrame::UpdateRect rect;
Erik Språng610c7632019-03-06 15:37:33 +01003557 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3558 DataRate::Zero(), 0, 0);
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01003559
3560 fake_encoder_.BlockNextEncode();
3561 video_source_.IncomingCapturedFrame(
3562 CreateFrameWithUpdatedPixel(1, nullptr, 0));
3563 WaitForEncodedFrame(1);
3564 // On the very first frame full update should be forced.
3565 rect = fake_encoder_.GetLastUpdateRect();
3566 EXPECT_EQ(rect.offset_x, 0);
3567 EXPECT_EQ(rect.offset_y, 0);
3568 EXPECT_EQ(rect.height, codec_height_);
3569 EXPECT_EQ(rect.width, codec_width_);
3570 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
3571 // call to ContinueEncode.
3572 video_source_.IncomingCapturedFrame(
3573 CreateFrameWithUpdatedPixel(2, nullptr, 1));
3574 ExpectDroppedFrame();
3575 video_source_.IncomingCapturedFrame(
3576 CreateFrameWithUpdatedPixel(3, nullptr, 10));
3577 ExpectDroppedFrame();
3578 fake_encoder_.ContinueEncode();
3579 WaitForEncodedFrame(3);
3580 // Updates to pixels 1 and 10 should be accumulated to one 10x1 rect.
3581 rect = fake_encoder_.GetLastUpdateRect();
3582 EXPECT_EQ(rect.offset_x, 1);
3583 EXPECT_EQ(rect.offset_y, 0);
3584 EXPECT_EQ(rect.width, 10);
3585 EXPECT_EQ(rect.height, 1);
3586
3587 video_source_.IncomingCapturedFrame(
3588 CreateFrameWithUpdatedPixel(4, nullptr, 0));
3589 WaitForEncodedFrame(4);
3590 // Previous frame was encoded, so no accumulation should happen.
3591 rect = fake_encoder_.GetLastUpdateRect();
3592 EXPECT_EQ(rect.offset_x, 0);
3593 EXPECT_EQ(rect.offset_y, 0);
3594 EXPECT_EQ(rect.width, 1);
3595 EXPECT_EQ(rect.height, 1);
3596
3597 video_stream_encoder_->Stop();
3598}
3599
Erik Språngd7329ca2019-02-21 21:19:53 +01003600TEST_F(VideoStreamEncoderTest, SetsFrameTypes) {
Erik Språng610c7632019-03-06 15:37:33 +01003601 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3602 DataRate::Zero(), 0, 0);
Erik Språngd7329ca2019-02-21 21:19:53 +01003603
3604 // First frame is always keyframe.
3605 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
3606 WaitForEncodedFrame(1);
3607 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
3608 testing::ElementsAre(FrameType{kVideoFrameKey}));
3609
3610 // Insert delta frame.
3611 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
3612 WaitForEncodedFrame(2);
3613 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
3614 testing::ElementsAre(FrameType{kVideoFrameDelta}));
3615
3616 // Request next frame be a key-frame.
3617 video_stream_encoder_->SendKeyFrame();
3618 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
3619 WaitForEncodedFrame(3);
3620 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
3621 testing::ElementsAre(FrameType{kVideoFrameKey}));
3622
3623 video_stream_encoder_->Stop();
3624}
3625
3626TEST_F(VideoStreamEncoderTest, SetsFrameTypesSimulcast) {
3627 // Setup simulcast with three streams.
3628 ResetEncoder("VP8", 3, 1, 1, false);
Erik Språng610c7632019-03-06 15:37:33 +01003629 video_stream_encoder_->OnBitrateUpdated(
3630 DataRate::bps(kSimulcastTargetBitrateBps), DataRate::Zero(), 0, 0);
Erik Språngd7329ca2019-02-21 21:19:53 +01003631 // Wait for all three layers before triggering event.
3632 sink_.SetNumExpectedLayers(3);
3633
3634 // First frame is always keyframe.
3635 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
3636 WaitForEncodedFrame(1);
3637 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
3638 testing::ElementsAreArray(
3639 {kVideoFrameKey, kVideoFrameKey, kVideoFrameKey}));
3640
3641 // Insert delta frame.
3642 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
3643 WaitForEncodedFrame(2);
3644 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
3645 testing::ElementsAreArray(
3646 {kVideoFrameDelta, kVideoFrameDelta, kVideoFrameDelta}));
3647
3648 // Request next frame be a key-frame.
3649 // Only first stream is configured to produce key-frame.
3650 video_stream_encoder_->SendKeyFrame();
3651 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
3652 WaitForEncodedFrame(3);
3653 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
3654 testing::ElementsAreArray(
3655 {kVideoFrameKey, kVideoFrameDelta, kVideoFrameDelta}));
3656
3657 video_stream_encoder_->Stop();
3658}
3659
3660TEST_F(VideoStreamEncoderTest, RequestKeyframeInternalSource) {
3661 // Configure internal source factory and setup test again.
3662 encoder_factory_.SetHasInternalSource(true);
3663 ResetEncoder("VP8", 1, 1, 1, false);
Erik Språng610c7632019-03-06 15:37:33 +01003664 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3665 DataRate::Zero(), 0, 0);
Erik Språngd7329ca2019-02-21 21:19:53 +01003666
3667 // Call encoder directly, simulating internal source where encoded frame
3668 // callback in VideoStreamEncoder is called despite no OnFrame().
3669 fake_encoder_.InjectFrame(CreateFrame(1, nullptr), true);
3670 EXPECT_TRUE(WaitForFrame(kDefaultTimeoutMs));
3671 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
3672 testing::ElementsAre(FrameType{kVideoFrameKey}));
3673
3674 const std::vector<FrameType> kDeltaFrame = {kVideoFrameDelta};
3675 // Need to set timestamp manually since manually for injected frame.
3676 VideoFrame frame = CreateFrame(101, nullptr);
3677 frame.set_timestamp(101);
3678 fake_encoder_.InjectFrame(frame, false);
3679 EXPECT_TRUE(WaitForFrame(kDefaultTimeoutMs));
3680 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
3681 testing::ElementsAre(FrameType{kVideoFrameDelta}));
3682
3683 // Request key-frame. The forces a dummy frame down into the encoder.
3684 fake_encoder_.ExpectNullFrame();
3685 video_stream_encoder_->SendKeyFrame();
3686 EXPECT_TRUE(WaitForFrame(kDefaultTimeoutMs));
3687 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
3688 testing::ElementsAre(FrameType{kVideoFrameKey}));
3689
3690 video_stream_encoder_->Stop();
3691}
Erik Språngb7cb7b52019-02-26 15:52:33 +01003692
3693TEST_F(VideoStreamEncoderTest, AdjustsTimestampInternalSource) {
3694 // Configure internal source factory and setup test again.
3695 encoder_factory_.SetHasInternalSource(true);
3696 ResetEncoder("VP8", 1, 1, 1, false);
Erik Språng610c7632019-03-06 15:37:33 +01003697 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
3698 DataRate::Zero(), 0, 0);
Erik Språngb7cb7b52019-02-26 15:52:33 +01003699
3700 int64_t timestamp = 1;
3701 EncodedImage image;
3702 image.Allocate(kTargetBitrateBps / kDefaultFramerate / 8);
3703 image.capture_time_ms_ = ++timestamp;
3704 image.SetTimestamp(static_cast<uint32_t>(timestamp * 90));
3705 const int64_t kEncodeFinishDelayMs = 10;
3706 image.timing_.encode_start_ms = timestamp;
3707 image.timing_.encode_finish_ms = timestamp + kEncodeFinishDelayMs;
3708 fake_encoder_.InjectEncodedImage(image);
3709 // Wait for frame without incrementing clock.
3710 EXPECT_TRUE(sink_.WaitForFrame(kDefaultTimeoutMs));
3711 // Frame is captured kEncodeFinishDelayMs before it's encoded, so restored
3712 // capture timestamp should be kEncodeFinishDelayMs in the past.
3713 EXPECT_EQ(sink_.GetLastCaptureTimeMs(),
3714 fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec -
3715 kEncodeFinishDelayMs);
3716
3717 video_stream_encoder_->Stop();
3718}
perkj26091b12016-09-01 01:17:40 -07003719} // namespace webrtc