blob: 982ba2d4971a73396dde1fa01c8b9b19458f5a1c [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>
Danil Chapovalovd3ba2362019-04-10 17:01:23 +020015#include <memory>
Per512ecb32016-09-23 15:52:06 +020016#include <utility>
17
Mirta Dvornicic28f0eb22019-05-28 16:30:16 +020018#include "absl/memory/memory.h"
Danil Chapovalovd3ba2362019-04-10 17:01:23 +020019#include "api/task_queue/default_task_queue_factory.h"
Elad Alon45befc52019-07-02 11:20:09 +020020#include "api/test/mock_fec_controller_override.h"
Jiawei Ouc2ebe212018-11-08 10:02:56 -080021#include "api/video/builtin_video_bitrate_allocator_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "api/video/i420_buffer.h"
Erik Språngf93eda12019-01-16 17:10:57 +010023#include "api/video/video_bitrate_allocation.h"
Elad Alon370f93a2019-06-11 14:57:57 +020024#include "api/video_codecs/video_encoder.h"
Erik Språng4529fbc2018-10-12 10:30:31 +020025#include "api/video_codecs/vp8_temporal_layers.h"
Elad Aloncde8ab22019-03-20 11:56:20 +010026#include "api/video_codecs/vp8_temporal_layers_factory.h"
Mirta Dvornicic28f0eb22019-05-28 16:30:16 +020027#include "common_video/h264/h264_common.h"
Noah Richards51db4212019-06-12 06:59:12 -070028#include "common_video/include/video_frame_buffer.h"
Steve Anton10542f22019-01-11 09:11:00 -080029#include "media/base/video_adapter.h"
Sergey Silkin86684962018-03-28 19:32:37 +020030#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020031#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
Åsa Perssonc29cb2c2019-03-25 12:06:59 +010032#include "modules/video_coding/utility/simulcast_rate_allocator.h"
Steve Anton10542f22019-01-11 09:11:00 -080033#include "rtc_base/fake_clock.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020034#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080035#include "rtc_base/ref_counted_object.h"
Erik Språng7ca375c2019-02-06 16:20:17 +010036#include "system_wrappers/include/field_trial.h"
Mirko Bonadei17f48782018-09-28 08:51:10 +020037#include "system_wrappers/include/metrics.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020038#include "system_wrappers/include/sleep.h"
39#include "test/encoder_settings.h"
40#include "test/fake_encoder.h"
Kári Tristan Helgason639602a2018-08-02 10:51:40 +020041#include "test/field_trial.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020042#include "test/frame_generator.h"
43#include "test/gmock.h"
44#include "test/gtest.h"
Niels Möllercbcbc222018-09-28 09:07:24 +020045#include "test/video_encoder_proxy_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020046#include "video/send_statistics_proxy.h"
perkj26091b12016-09-01 01:17:40 -070047
48namespace webrtc {
49
sprangb1ca0732017-02-01 08:38:12 -080050using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080051using ::testing::_;
kthelgason876222f2016-11-29 01:44:11 -080052
perkj803d97f2016-11-01 11:45:46 -070053namespace {
Åsa Persson8c1bf952018-09-13 10:42:19 +020054const int kMinPixelsPerFrame = 320 * 180;
55const int kMinFramerateFps = 2;
56const int kMinBalancedFramerateFps = 7;
57const int64_t kFrameTimeoutMs = 100;
asapersson5f7226f2016-11-25 04:37:00 -080058const size_t kMaxPayloadLength = 1440;
Erik Språngd7329ca2019-02-21 21:19:53 +010059const uint32_t kTargetBitrateBps = 1000000;
60const uint32_t kSimulcastTargetBitrateBps = 3150000;
61const uint32_t kLowTargetBitrateBps = kTargetBitrateBps / 10;
kthelgason2bc68642017-02-07 07:02:22 -080062const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070063const int kDefaultFramerate = 30;
Åsa Persson8c1bf952018-09-13 10:42:19 +020064const int64_t kFrameIntervalMs = rtc::kNumMillisecsPerSec / kDefaultFramerate;
asapersson5f7226f2016-11-25 04:37:00 -080065
Mirta Dvornicic28f0eb22019-05-28 16:30:16 +020066uint8_t optimal_sps[] = {0, 0, 0, 1, H264::NaluType::kSps,
67 0x00, 0x00, 0x03, 0x03, 0xF4,
68 0x05, 0x03, 0xC7, 0xE0, 0x1B,
69 0x41, 0x10, 0x8D, 0x00};
70
perkj803d97f2016-11-01 11:45:46 -070071class TestBuffer : public webrtc::I420Buffer {
72 public:
73 TestBuffer(rtc::Event* event, int width, int height)
74 : I420Buffer(width, height), event_(event) {}
75
76 private:
77 friend class rtc::RefCountedObject<TestBuffer>;
78 ~TestBuffer() override {
79 if (event_)
80 event_->Set();
81 }
82 rtc::Event* const event_;
83};
84
Noah Richards51db4212019-06-12 06:59:12 -070085// A fake native buffer that can't be converted to I420.
86class FakeNativeBuffer : public webrtc::VideoFrameBuffer {
87 public:
88 FakeNativeBuffer(rtc::Event* event, int width, int height)
89 : event_(event), width_(width), height_(height) {}
90 webrtc::VideoFrameBuffer::Type type() const override { return Type::kNative; }
91 int width() const override { return width_; }
92 int height() const override { return height_; }
93 rtc::scoped_refptr<webrtc::I420BufferInterface> ToI420() override {
94 return nullptr;
95 }
96
97 private:
98 friend class rtc::RefCountedObject<FakeNativeBuffer>;
99 ~FakeNativeBuffer() override {
100 if (event_)
101 event_->Set();
102 }
103 rtc::Event* const event_;
104 const int width_;
105 const int height_;
106};
107
Niels Möller7dc26b72017-12-06 10:27:48 +0100108class CpuOveruseDetectorProxy : public OveruseFrameDetector {
109 public:
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200110 explicit CpuOveruseDetectorProxy(CpuOveruseMetricsObserver* metrics_observer)
111 : OveruseFrameDetector(metrics_observer),
Niels Möller7dc26b72017-12-06 10:27:48 +0100112 last_target_framerate_fps_(-1) {}
113 virtual ~CpuOveruseDetectorProxy() {}
114
115 void OnTargetFramerateUpdated(int framerate_fps) override {
116 rtc::CritScope cs(&lock_);
117 last_target_framerate_fps_ = framerate_fps;
118 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
119 }
120
121 int GetLastTargetFramerate() {
122 rtc::CritScope cs(&lock_);
123 return last_target_framerate_fps_;
124 }
125
Niels Möller4db138e2018-04-19 09:04:13 +0200126 CpuOveruseOptions GetOptions() { return options_; }
127
Niels Möller7dc26b72017-12-06 10:27:48 +0100128 private:
129 rtc::CriticalSection lock_;
130 int last_target_framerate_fps_ RTC_GUARDED_BY(lock_);
131};
132
mflodmancc3d4422017-08-03 08:27:51 -0700133class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -0700134 public:
Niels Möller213618e2018-07-24 09:29:58 +0200135 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
Danil Chapovalovd3ba2362019-04-10 17:01:23 +0200136 const VideoStreamEncoderSettings& settings,
137 TaskQueueFactory* task_queue_factory)
Sebastian Jansson572c60f2019-03-04 18:30:41 +0100138 : VideoStreamEncoder(Clock::GetRealTimeClock(),
139 1 /* number_of_cores */,
Yves Gerey665174f2018-06-19 15:03:05 +0200140 stats_proxy,
141 settings,
Yves Gerey665174f2018-06-19 15:03:05 +0200142 std::unique_ptr<OveruseFrameDetector>(
143 overuse_detector_proxy_ =
Sebastian Jansson74682c12019-03-01 11:50:20 +0100144 new CpuOveruseDetectorProxy(stats_proxy)),
Danil Chapovalovd3ba2362019-04-10 17:01:23 +0200145 task_queue_factory) {}
perkj803d97f2016-11-01 11:45:46 -0700146
sprangb1ca0732017-02-01 08:38:12 -0800147 void PostTaskAndWait(bool down, AdaptReason reason) {
Niels Möllerc572ff32018-11-07 08:43:50 +0100148 rtc::Event event;
kthelgason876222f2016-11-29 01:44:11 -0800149 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800150 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700151 event.Set();
152 });
perkj070ba852017-02-16 15:46:27 -0800153 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700154 }
155
kthelgason2fc52542017-03-03 00:24:41 -0800156 // This is used as a synchronisation mechanism, to make sure that the
157 // encoder queue is not blocked before we start sending it frames.
158 void WaitUntilTaskQueueIsIdle() {
Niels Möllerc572ff32018-11-07 08:43:50 +0100159 rtc::Event event;
Yves Gerey665174f2018-06-19 15:03:05 +0200160 encoder_queue()->PostTask([&event] { event.Set(); });
kthelgason2fc52542017-03-03 00:24:41 -0800161 ASSERT_TRUE(event.Wait(5000));
162 }
163
sprangb1ca0732017-02-01 08:38:12 -0800164 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800165
sprangb1ca0732017-02-01 08:38:12 -0800166 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800167
sprangb1ca0732017-02-01 08:38:12 -0800168 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800169
sprangb1ca0732017-02-01 08:38:12 -0800170 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700171
Niels Möller7dc26b72017-12-06 10:27:48 +0100172 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700173};
174
asapersson5f7226f2016-11-25 04:37:00 -0800175class VideoStreamFactory
176 : public VideoEncoderConfig::VideoStreamFactoryInterface {
177 public:
sprangfda496a2017-06-15 04:21:07 -0700178 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
179 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800180 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700181 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800182 }
183
184 private:
185 std::vector<VideoStream> CreateEncoderStreams(
186 int width,
187 int height,
188 const VideoEncoderConfig& encoder_config) override {
189 std::vector<VideoStream> streams =
190 test::CreateVideoStreams(width, height, encoder_config);
191 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +0100192 stream.num_temporal_layers = num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700193 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800194 }
195 return streams;
196 }
sprangfda496a2017-06-15 04:21:07 -0700197
asapersson5f7226f2016-11-25 04:37:00 -0800198 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700199 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800200};
201
Noah Richards51db4212019-06-12 06:59:12 -0700202// Simulates simulcast behavior and makes highest stream resolutions divisible
203// by 4.
204class CroppingVideoStreamFactory
205 : public VideoEncoderConfig::VideoStreamFactoryInterface {
206 public:
207 explicit CroppingVideoStreamFactory(size_t num_temporal_layers, int framerate)
208 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
209 EXPECT_GT(num_temporal_layers, 0u);
210 EXPECT_GT(framerate, 0);
211 }
212
213 private:
214 std::vector<VideoStream> CreateEncoderStreams(
215 int width,
216 int height,
217 const VideoEncoderConfig& encoder_config) override {
218 std::vector<VideoStream> streams = test::CreateVideoStreams(
219 width - width % 4, height - height % 4, encoder_config);
220 for (VideoStream& stream : streams) {
221 stream.num_temporal_layers = num_temporal_layers_;
222 stream.max_framerate = framerate_;
223 }
224 return streams;
225 }
226
227 const size_t num_temporal_layers_;
228 const int framerate_;
229};
230
sprangb1ca0732017-02-01 08:38:12 -0800231class AdaptingFrameForwarder : public test::FrameForwarder {
232 public:
233 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700234 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800235
236 void set_adaptation_enabled(bool enabled) {
237 rtc::CritScope cs(&crit_);
238 adaptation_enabled_ = enabled;
239 }
240
asaperssonfab67072017-04-04 05:51:49 -0700241 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800242 rtc::CritScope cs(&crit_);
243 return adaptation_enabled_;
244 }
245
asapersson09f05612017-05-15 23:40:18 -0700246 rtc::VideoSinkWants last_wants() const {
247 rtc::CritScope cs(&crit_);
248 return last_wants_;
249 }
250
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200251 absl::optional<int> last_sent_width() const { return last_width_; }
252 absl::optional<int> last_sent_height() const { return last_height_; }
Jonathan Yubc771b72017-12-08 17:04:29 -0800253
sprangb1ca0732017-02-01 08:38:12 -0800254 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
255 int cropped_width = 0;
256 int cropped_height = 0;
257 int out_width = 0;
258 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700259 if (adaption_enabled()) {
260 if (adapter_.AdaptFrameResolution(
261 video_frame.width(), video_frame.height(),
262 video_frame.timestamp_us() * 1000, &cropped_width,
263 &cropped_height, &out_width, &out_height)) {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100264 VideoFrame adapted_frame =
265 VideoFrame::Builder()
266 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
267 nullptr, out_width, out_height))
268 .set_timestamp_rtp(99)
269 .set_timestamp_ms(99)
270 .set_rotation(kVideoRotation_0)
271 .build();
sprangc5d62e22017-04-02 23:53:04 -0700272 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
273 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800274 last_width_.emplace(adapted_frame.width());
275 last_height_.emplace(adapted_frame.height());
276 } else {
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200277 last_width_ = absl::nullopt;
278 last_height_ = absl::nullopt;
sprangc5d62e22017-04-02 23:53:04 -0700279 }
sprangb1ca0732017-02-01 08:38:12 -0800280 } else {
281 test::FrameForwarder::IncomingCapturedFrame(video_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800282 last_width_.emplace(video_frame.width());
283 last_height_.emplace(video_frame.height());
sprangb1ca0732017-02-01 08:38:12 -0800284 }
285 }
286
287 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
288 const rtc::VideoSinkWants& wants) override {
289 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700290 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700291 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
292 wants.max_pixel_count,
293 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800294 test::FrameForwarder::AddOrUpdateSink(sink, wants);
295 }
sprangb1ca0732017-02-01 08:38:12 -0800296 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700297 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
298 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200299 absl::optional<int> last_width_;
300 absl::optional<int> last_height_;
sprangb1ca0732017-02-01 08:38:12 -0800301};
sprangc5d62e22017-04-02 23:53:04 -0700302
Niels Möller213618e2018-07-24 09:29:58 +0200303// TODO(nisse): Mock only VideoStreamEncoderObserver.
sprangc5d62e22017-04-02 23:53:04 -0700304class MockableSendStatisticsProxy : public SendStatisticsProxy {
305 public:
306 MockableSendStatisticsProxy(Clock* clock,
307 const VideoSendStream::Config& config,
308 VideoEncoderConfig::ContentType content_type)
309 : SendStatisticsProxy(clock, config, content_type) {}
310
311 VideoSendStream::Stats GetStats() override {
312 rtc::CritScope cs(&lock_);
313 if (mock_stats_)
314 return *mock_stats_;
315 return SendStatisticsProxy::GetStats();
316 }
317
Niels Möller213618e2018-07-24 09:29:58 +0200318 int GetInputFrameRate() const override {
319 rtc::CritScope cs(&lock_);
320 if (mock_stats_)
321 return mock_stats_->input_frame_rate;
322 return SendStatisticsProxy::GetInputFrameRate();
323 }
sprangc5d62e22017-04-02 23:53:04 -0700324 void SetMockStats(const VideoSendStream::Stats& stats) {
325 rtc::CritScope cs(&lock_);
326 mock_stats_.emplace(stats);
327 }
328
329 void ResetMockStats() {
330 rtc::CritScope cs(&lock_);
331 mock_stats_.reset();
332 }
333
334 private:
335 rtc::CriticalSection lock_;
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200336 absl::optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700337};
338
sprang4847ae62017-06-27 07:06:52 -0700339class MockBitrateObserver : public VideoBitrateAllocationObserver {
340 public:
Erik Språng566124a2018-04-23 12:32:22 +0200341 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const VideoBitrateAllocation&));
sprang4847ae62017-06-27 07:06:52 -0700342};
343
perkj803d97f2016-11-01 11:45:46 -0700344} // namespace
345
mflodmancc3d4422017-08-03 08:27:51 -0700346class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700347 public:
348 static const int kDefaultTimeoutMs = 30 * 1000;
349
mflodmancc3d4422017-08-03 08:27:51 -0700350 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700351 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700352 codec_width_(320),
353 codec_height_(240),
Åsa Persson8c1bf952018-09-13 10:42:19 +0200354 max_framerate_(kDefaultFramerate),
Danil Chapovalovd3ba2362019-04-10 17:01:23 +0200355 task_queue_factory_(CreateDefaultTaskQueueFactory()),
perkj26091b12016-09-01 01:17:40 -0700356 fake_encoder_(),
Niels Möller4db138e2018-04-19 09:04:13 +0200357 encoder_factory_(&fake_encoder_),
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800358 bitrate_allocator_factory_(CreateBuiltinVideoBitrateAllocatorFactory()),
sprangc5d62e22017-04-02 23:53:04 -0700359 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700360 Clock::GetRealTimeClock(),
361 video_send_config_,
362 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700363 sink_(&fake_encoder_) {}
364
365 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700366 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700367 video_send_config_ = VideoSendStream::Config(nullptr);
Niels Möller4db138e2018-04-19 09:04:13 +0200368 video_send_config_.encoder_settings.encoder_factory = &encoder_factory_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800369 video_send_config_.encoder_settings.bitrate_allocator_factory =
370 bitrate_allocator_factory_.get();
Niels Möller259a4972018-04-05 15:36:51 +0200371 video_send_config_.rtp.payload_name = "FAKE";
372 video_send_config_.rtp.payload_type = 125;
perkj26091b12016-09-01 01:17:40 -0700373
Per512ecb32016-09-23 15:52:06 +0200374 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200375 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700376 video_encoder_config.video_stream_factory =
377 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100378 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700379
380 // Framerate limit is specified by the VideoStreamFactory.
381 std::vector<VideoStream> streams =
382 video_encoder_config.video_stream_factory->CreateEncoderStreams(
383 codec_width_, codec_height_, video_encoder_config);
384 max_framerate_ = streams[0].max_framerate;
Sebastian Jansson40889f32019-04-17 12:11:20 +0200385 fake_clock_.SetTime(Timestamp::us(1234));
sprang4847ae62017-06-27 07:06:52 -0700386
Niels Möllerf1338562018-04-26 09:51:47 +0200387 ConfigureEncoder(std::move(video_encoder_config));
asapersson5f7226f2016-11-25 04:37:00 -0800388 }
389
Niels Möllerf1338562018-04-26 09:51:47 +0200390 void ConfigureEncoder(VideoEncoderConfig video_encoder_config) {
mflodmancc3d4422017-08-03 08:27:51 -0700391 if (video_stream_encoder_)
392 video_stream_encoder_->Stop();
393 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
Danil Chapovalovd3ba2362019-04-10 17:01:23 +0200394 stats_proxy_.get(), video_send_config_.encoder_settings,
395 task_queue_factory_.get()));
mflodmancc3d4422017-08-03 08:27:51 -0700396 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
397 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700398 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -0700399 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
400 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200401 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -0700402 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800403 }
404
405 void ResetEncoder(const std::string& payload_name,
406 size_t num_streams,
407 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700408 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700409 bool screenshare) {
Niels Möller259a4972018-04-05 15:36:51 +0200410 video_send_config_.rtp.payload_name = payload_name;
asapersson5f7226f2016-11-25 04:37:00 -0800411
412 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200413 video_encoder_config.codec_type = PayloadStringToCodecType(payload_name);
asapersson5f7226f2016-11-25 04:37:00 -0800414 video_encoder_config.number_of_streams = num_streams;
Erik Språngd7329ca2019-02-21 21:19:53 +0100415 video_encoder_config.max_bitrate_bps =
416 num_streams == 1 ? kTargetBitrateBps : kSimulcastTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800417 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700418 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
419 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700420 video_encoder_config.content_type =
421 screenshare ? VideoEncoderConfig::ContentType::kScreen
422 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700423 if (payload_name == "VP9") {
424 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
425 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
426 video_encoder_config.encoder_specific_settings =
427 new rtc::RefCountedObject<
428 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
429 }
Niels Möllerf1338562018-04-26 09:51:47 +0200430 ConfigureEncoder(std::move(video_encoder_config));
perkj26091b12016-09-01 01:17:40 -0700431 }
432
sprang57c2fff2017-01-16 06:24:02 -0800433 VideoFrame CreateFrame(int64_t ntp_time_ms,
434 rtc::Event* destruction_event) const {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100435 VideoFrame frame =
436 VideoFrame::Builder()
437 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
438 destruction_event, codec_width_, codec_height_))
439 .set_timestamp_rtp(99)
440 .set_timestamp_ms(99)
441 .set_rotation(kVideoRotation_0)
442 .build();
sprang57c2fff2017-01-16 06:24:02 -0800443 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700444 return frame;
445 }
446
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100447 VideoFrame CreateFrameWithUpdatedPixel(int64_t ntp_time_ms,
448 rtc::Event* destruction_event,
449 int offset_x) const {
450 VideoFrame frame =
451 VideoFrame::Builder()
452 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
453 destruction_event, codec_width_, codec_height_))
454 .set_timestamp_rtp(99)
455 .set_timestamp_ms(99)
456 .set_rotation(kVideoRotation_0)
457 .set_update_rect({offset_x, 0, 1, 1})
458 .build();
459 frame.set_ntp_time_ms(ntp_time_ms);
460 return frame;
461 }
462
sprang57c2fff2017-01-16 06:24:02 -0800463 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100464 VideoFrame frame =
465 VideoFrame::Builder()
466 .set_video_frame_buffer(
467 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height))
468 .set_timestamp_rtp(99)
469 .set_timestamp_ms(99)
470 .set_rotation(kVideoRotation_0)
471 .build();
sprang57c2fff2017-01-16 06:24:02 -0800472 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700473 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700474 return frame;
475 }
476
Noah Richards51db4212019-06-12 06:59:12 -0700477 VideoFrame CreateFakeNativeFrame(int64_t ntp_time_ms,
478 rtc::Event* destruction_event,
479 int width,
480 int height) const {
481 VideoFrame frame =
482 VideoFrame::Builder()
483 .set_video_frame_buffer(new rtc::RefCountedObject<FakeNativeBuffer>(
484 destruction_event, width, height))
485 .set_timestamp_rtp(99)
486 .set_timestamp_ms(99)
487 .set_rotation(kVideoRotation_0)
488 .build();
489 frame.set_ntp_time_ms(ntp_time_ms);
490 return frame;
491 }
492
493 VideoFrame CreateFakeNativeFrame(int64_t ntp_time_ms,
494 rtc::Event* destruction_event) const {
495 return CreateFakeNativeFrame(ntp_time_ms, destruction_event, codec_width_,
496 codec_height_);
497 }
498
Åsa Perssonc29cb2c2019-03-25 12:06:59 +0100499 void VerifyAllocatedBitrate(const VideoBitrateAllocation& expected_bitrate) {
500 MockBitrateObserver bitrate_observer;
501 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
502
503 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
504 .Times(1);
505 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
Erik Språng4c6ca302019-04-08 15:14:01 +0200506 DataRate::bps(kTargetBitrateBps), 0,
507 0);
Åsa Perssonc29cb2c2019-03-25 12:06:59 +0100508
509 video_source_.IncomingCapturedFrame(
510 CreateFrame(1, codec_width_, codec_height_));
511 WaitForEncodedFrame(1);
512 }
513
asapersson02465b82017-04-10 01:12:52 -0700514 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700515 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700516 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
517 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700518 }
519
asapersson09f05612017-05-15 23:40:18 -0700520 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
521 const rtc::VideoSinkWants& wants2) {
522 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
523 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
524 }
525
Åsa Persson8c1bf952018-09-13 10:42:19 +0200526 void VerifyFpsMaxResolutionMax(const rtc::VideoSinkWants& wants) {
527 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
528 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
529 EXPECT_FALSE(wants.target_pixel_count);
530 }
531
asapersson09f05612017-05-15 23:40:18 -0700532 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
533 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200534 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700535 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
536 EXPECT_GT(wants1.max_pixel_count, 0);
537 }
538
539 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
540 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200541 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700542 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
543 }
544
asaperssonf7e294d2017-06-13 23:25:22 -0700545 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
546 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200547 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700548 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
549 }
550
551 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
552 const rtc::VideoSinkWants& wants2) {
553 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
554 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
555 }
556
557 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
558 const rtc::VideoSinkWants& wants2) {
559 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
560 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
561 }
562
563 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
564 const rtc::VideoSinkWants& wants2) {
565 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
566 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
567 EXPECT_GT(wants1.max_pixel_count, 0);
568 }
569
570 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
571 const rtc::VideoSinkWants& wants2) {
572 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
573 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
574 }
575
asapersson09f05612017-05-15 23:40:18 -0700576 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
577 int pixel_count) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200578 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700579 EXPECT_LT(wants.max_pixel_count, pixel_count);
580 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700581 }
582
583 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
584 EXPECT_LT(wants.max_framerate_fps, fps);
585 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
586 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700587 }
588
asaperssonf7e294d2017-06-13 23:25:22 -0700589 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
590 int expected_fps) {
591 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
592 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
593 EXPECT_FALSE(wants.target_pixel_count);
594 }
595
Jonathan Yubc771b72017-12-08 17:04:29 -0800596 void VerifyBalancedModeFpsRange(const rtc::VideoSinkWants& wants,
597 int last_frame_pixels) {
598 // Balanced mode should always scale FPS to the desired range before
599 // attempting to scale resolution.
600 int fps_limit = wants.max_framerate_fps;
601 if (last_frame_pixels <= 320 * 240) {
602 EXPECT_TRUE(7 <= fps_limit && fps_limit <= 10);
603 } else if (last_frame_pixels <= 480 * 270) {
604 EXPECT_TRUE(10 <= fps_limit && fps_limit <= 15);
605 } else if (last_frame_pixels <= 640 * 480) {
606 EXPECT_LE(15, fps_limit);
607 } else {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200608 EXPECT_EQ(kDefaultFramerate, fps_limit);
Jonathan Yubc771b72017-12-08 17:04:29 -0800609 }
610 }
611
sprang4847ae62017-06-27 07:06:52 -0700612 void WaitForEncodedFrame(int64_t expected_ntp_time) {
613 sink_.WaitForEncodedFrame(expected_ntp_time);
Sebastian Jansson40889f32019-04-17 12:11:20 +0200614 fake_clock_.AdvanceTime(TimeDelta::seconds(1) / max_framerate_);
sprang4847ae62017-06-27 07:06:52 -0700615 }
616
617 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
618 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
Sebastian Jansson40889f32019-04-17 12:11:20 +0200619 fake_clock_.AdvanceTime(TimeDelta::seconds(1) / max_framerate_);
sprang4847ae62017-06-27 07:06:52 -0700620 return ok;
621 }
622
623 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
624 sink_.WaitForEncodedFrame(expected_width, expected_height);
Sebastian Jansson40889f32019-04-17 12:11:20 +0200625 fake_clock_.AdvanceTime(TimeDelta::seconds(1) / max_framerate_);
sprang4847ae62017-06-27 07:06:52 -0700626 }
627
628 void ExpectDroppedFrame() {
629 sink_.ExpectDroppedFrame();
Sebastian Jansson40889f32019-04-17 12:11:20 +0200630 fake_clock_.AdvanceTime(TimeDelta::seconds(1) / max_framerate_);
sprang4847ae62017-06-27 07:06:52 -0700631 }
632
633 bool WaitForFrame(int64_t timeout_ms) {
634 bool ok = sink_.WaitForFrame(timeout_ms);
Sebastian Jansson40889f32019-04-17 12:11:20 +0200635 fake_clock_.AdvanceTime(TimeDelta::seconds(1) / max_framerate_);
sprang4847ae62017-06-27 07:06:52 -0700636 return ok;
637 }
638
perkj26091b12016-09-01 01:17:40 -0700639 class TestEncoder : public test::FakeEncoder {
640 public:
Niels Möllerc572ff32018-11-07 08:43:50 +0100641 TestEncoder() : FakeEncoder(Clock::GetRealTimeClock()) {}
perkj26091b12016-09-01 01:17:40 -0700642
asaperssonfab67072017-04-04 05:51:49 -0700643 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800644 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700645 return config_;
646 }
647
648 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800649 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700650 block_next_encode_ = true;
651 }
652
Erik Språngaed30702018-11-05 12:57:17 +0100653 VideoEncoder::EncoderInfo GetEncoderInfo() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800654 rtc::CritScope lock(&local_crit_sect_);
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100655 EncoderInfo info;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100656 if (initialized_ == EncoderState::kInitialized) {
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100657 if (quality_scaling_) {
658 info.scaling_settings =
659 VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
660 }
661 info.is_hardware_accelerated = is_hardware_accelerated_;
Åsa Perssonc29cb2c2019-03-25 12:06:59 +0100662 for (int i = 0; i < kMaxSpatialLayers; ++i) {
663 if (temporal_layers_supported_[i]) {
664 int num_layers = temporal_layers_supported_[i].value() ? 2 : 1;
665 info.fps_allocation[i].resize(num_layers);
666 }
667 }
Erik Språngaed30702018-11-05 12:57:17 +0100668 }
669 return info;
kthelgason876222f2016-11-29 01:44:11 -0800670 }
671
Erik Språngb7cb7b52019-02-26 15:52:33 +0100672 int32_t RegisterEncodeCompleteCallback(
673 EncodedImageCallback* callback) override {
674 rtc::CritScope lock(&local_crit_sect_);
675 encoded_image_callback_ = callback;
676 return FakeEncoder::RegisterEncodeCompleteCallback(callback);
677 }
678
perkjfa10b552016-10-02 23:45:26 -0700679 void ContinueEncode() { continue_encode_event_.Set(); }
680
681 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
682 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800683 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700684 EXPECT_EQ(timestamp_, timestamp);
685 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
686 }
687
kthelgason2fc52542017-03-03 00:24:41 -0800688 void SetQualityScaling(bool b) {
689 rtc::CritScope lock(&local_crit_sect_);
690 quality_scaling_ = b;
691 }
kthelgasonad9010c2017-02-14 00:46:51 -0800692
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100693 void SetIsHardwareAccelerated(bool is_hardware_accelerated) {
694 rtc::CritScope lock(&local_crit_sect_);
695 is_hardware_accelerated_ = is_hardware_accelerated;
696 }
697
Åsa Perssonc29cb2c2019-03-25 12:06:59 +0100698 void SetTemporalLayersSupported(size_t spatial_idx, bool supported) {
699 RTC_DCHECK_LT(spatial_idx, kMaxSpatialLayers);
700 rtc::CritScope lock(&local_crit_sect_);
701 temporal_layers_supported_[spatial_idx] = supported;
702 }
703
sprangfe627f32017-03-29 08:24:59 -0700704 void ForceInitEncodeFailure(bool force_failure) {
705 rtc::CritScope lock(&local_crit_sect_);
706 force_init_encode_failed_ = force_failure;
707 }
708
Niels Möller6bb5ab92019-01-11 11:11:10 +0100709 void SimulateOvershoot(double rate_factor) {
710 rtc::CritScope lock(&local_crit_sect_);
711 rate_factor_ = rate_factor;
712 }
713
Erik Språngd7329ca2019-02-21 21:19:53 +0100714 uint32_t GetLastFramerate() const {
Niels Möller6bb5ab92019-01-11 11:11:10 +0100715 rtc::CritScope lock(&local_crit_sect_);
716 return last_framerate_;
717 }
718
Erik Språngd7329ca2019-02-21 21:19:53 +0100719 VideoFrame::UpdateRect GetLastUpdateRect() const {
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100720 rtc::CritScope lock(&local_crit_sect_);
721 return last_update_rect_;
722 }
723
Niels Möller87e2d782019-03-07 10:18:23 +0100724 const std::vector<VideoFrameType>& LastFrameTypes() const {
Erik Språngd7329ca2019-02-21 21:19:53 +0100725 rtc::CritScope lock(&local_crit_sect_);
726 return last_frame_types_;
727 }
728
729 void InjectFrame(const VideoFrame& input_image, bool keyframe) {
Niels Möller87e2d782019-03-07 10:18:23 +0100730 const std::vector<VideoFrameType> frame_type = {
Niels Möller8f7ce222019-03-21 15:43:58 +0100731 keyframe ? VideoFrameType::kVideoFrameKey
732 : VideoFrameType::kVideoFrameDelta};
Erik Språngd7329ca2019-02-21 21:19:53 +0100733 {
734 rtc::CritScope lock(&local_crit_sect_);
735 last_frame_types_ = frame_type;
736 }
Niels Möllerb859b322019-03-07 12:40:01 +0100737 FakeEncoder::Encode(input_image, &frame_type);
Erik Språngd7329ca2019-02-21 21:19:53 +0100738 }
739
Erik Språngb7cb7b52019-02-26 15:52:33 +0100740 void InjectEncodedImage(const EncodedImage& image) {
741 rtc::CritScope lock(&local_crit_sect_);
742 encoded_image_callback_->OnEncodedImage(image, nullptr, nullptr);
743 }
744
Mirta Dvornicic28f0eb22019-05-28 16:30:16 +0200745 void InjectEncodedImage(const EncodedImage& image,
746 const CodecSpecificInfo* codec_specific_info,
747 const RTPFragmentationHeader* fragmentation) {
748 rtc::CritScope lock(&local_crit_sect_);
749 encoded_image_callback_->OnEncodedImage(image, codec_specific_info,
750 fragmentation);
751 }
752
Erik Språngd7329ca2019-02-21 21:19:53 +0100753 void ExpectNullFrame() {
754 rtc::CritScope lock(&local_crit_sect_);
755 expect_null_frame_ = true;
756 }
757
758 absl::optional<VideoBitrateAllocation> GetAndResetLastBitrateAllocation() {
759 auto allocation = last_bitrate_allocation_;
760 last_bitrate_allocation_.reset();
761 return allocation;
762 }
763
perkjfa10b552016-10-02 23:45:26 -0700764 private:
perkj26091b12016-09-01 01:17:40 -0700765 int32_t Encode(const VideoFrame& input_image,
Niels Möller87e2d782019-03-07 10:18:23 +0100766 const std::vector<VideoFrameType>* frame_types) override {
perkj26091b12016-09-01 01:17:40 -0700767 bool block_encode;
768 {
brandtre78d2662017-01-16 05:57:16 -0800769 rtc::CritScope lock(&local_crit_sect_);
Erik Språngd7329ca2019-02-21 21:19:53 +0100770 if (expect_null_frame_) {
771 EXPECT_EQ(input_image.timestamp(), 0u);
772 EXPECT_EQ(input_image.width(), 1);
773 last_frame_types_ = *frame_types;
774 expect_null_frame_ = false;
775 } else {
776 EXPECT_GT(input_image.timestamp(), timestamp_);
777 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
778 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
779 }
perkj26091b12016-09-01 01:17:40 -0700780
781 timestamp_ = input_image.timestamp();
782 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700783 last_input_width_ = input_image.width();
784 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700785 block_encode = block_next_encode_;
786 block_next_encode_ = false;
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100787 last_update_rect_ = input_image.update_rect();
Erik Språngd7329ca2019-02-21 21:19:53 +0100788 last_frame_types_ = *frame_types;
perkj26091b12016-09-01 01:17:40 -0700789 }
Niels Möllerb859b322019-03-07 12:40:01 +0100790 int32_t result = FakeEncoder::Encode(input_image, frame_types);
perkj26091b12016-09-01 01:17:40 -0700791 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700792 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700793 return result;
794 }
795
sprangfe627f32017-03-29 08:24:59 -0700796 int32_t InitEncode(const VideoCodec* config,
Elad Alon370f93a2019-06-11 14:57:57 +0200797 const Settings& settings) override {
798 int res = FakeEncoder::InitEncode(config, settings);
sprangfe627f32017-03-29 08:24:59 -0700799 rtc::CritScope lock(&local_crit_sect_);
Erik Språngb7cb7b52019-02-26 15:52:33 +0100800 EXPECT_EQ(initialized_, EncoderState::kUninitialized);
Erik Språng82fad3d2018-03-21 09:57:23 +0100801 if (config->codecType == kVideoCodecVP8) {
sprangfe627f32017-03-29 08:24:59 -0700802 // Simulate setting up temporal layers, in order to validate the life
803 // cycle of these objects.
Elad Aloncde8ab22019-03-20 11:56:20 +0100804 Vp8TemporalLayersFactory factory;
Elad Alon45befc52019-07-02 11:20:09 +0200805 frame_buffer_controller_ =
806 factory.Create(*config, settings, &fec_controller_override_);
sprangfe627f32017-03-29 08:24:59 -0700807 }
Erik Språngb7cb7b52019-02-26 15:52:33 +0100808 if (force_init_encode_failed_) {
809 initialized_ = EncoderState::kInitializationFailed;
sprangfe627f32017-03-29 08:24:59 -0700810 return -1;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100811 }
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100812
Erik Språngb7cb7b52019-02-26 15:52:33 +0100813 initialized_ = EncoderState::kInitialized;
sprangfe627f32017-03-29 08:24:59 -0700814 return res;
815 }
816
Erik Språngb7cb7b52019-02-26 15:52:33 +0100817 int32_t Release() override {
818 rtc::CritScope lock(&local_crit_sect_);
819 EXPECT_NE(initialized_, EncoderState::kUninitialized);
820 initialized_ = EncoderState::kUninitialized;
821 return FakeEncoder::Release();
822 }
823
Erik Språng16cb8f52019-04-12 13:59:09 +0200824 void SetRates(const RateControlParameters& parameters) {
Niels Möller6bb5ab92019-01-11 11:11:10 +0100825 rtc::CritScope lock(&local_crit_sect_);
826 VideoBitrateAllocation adjusted_rate_allocation;
827 for (size_t si = 0; si < kMaxSpatialLayers; ++si) {
828 for (size_t ti = 0; ti < kMaxTemporalStreams; ++ti) {
Erik Språng16cb8f52019-04-12 13:59:09 +0200829 if (parameters.bitrate.HasBitrate(si, ti)) {
Niels Möller6bb5ab92019-01-11 11:11:10 +0100830 adjusted_rate_allocation.SetBitrate(
831 si, ti,
Erik Språng16cb8f52019-04-12 13:59:09 +0200832 static_cast<uint32_t>(parameters.bitrate.GetBitrate(si, ti) *
Niels Möller6bb5ab92019-01-11 11:11:10 +0100833 rate_factor_));
834 }
835 }
836 }
Erik Språng16cb8f52019-04-12 13:59:09 +0200837 last_framerate_ = static_cast<uint32_t>(parameters.framerate_fps + 0.5);
838 last_bitrate_allocation_ = parameters.bitrate;
839 RateControlParameters adjusted_paramters = parameters;
840 adjusted_paramters.bitrate = adjusted_rate_allocation;
841 FakeEncoder::SetRates(adjusted_paramters);
Niels Möller6bb5ab92019-01-11 11:11:10 +0100842 }
843
brandtre78d2662017-01-16 05:57:16 -0800844 rtc::CriticalSection local_crit_sect_;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100845 enum class EncoderState {
846 kUninitialized,
847 kInitializationFailed,
848 kInitialized
849 } initialized_ RTC_GUARDED_BY(local_crit_sect_) =
850 EncoderState::kUninitialized;
danilchapa37de392017-09-09 04:17:22 -0700851 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700852 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700853 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
854 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
855 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
856 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
857 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100858 bool is_hardware_accelerated_ RTC_GUARDED_BY(local_crit_sect_) = false;
Elad Aloncde8ab22019-03-20 11:56:20 +0100859 std::unique_ptr<Vp8FrameBufferController> frame_buffer_controller_
danilchapa37de392017-09-09 04:17:22 -0700860 RTC_GUARDED_BY(local_crit_sect_);
Åsa Perssonc29cb2c2019-03-25 12:06:59 +0100861 absl::optional<bool>
862 temporal_layers_supported_[kMaxSpatialLayers] RTC_GUARDED_BY(
863 local_crit_sect_);
danilchapa37de392017-09-09 04:17:22 -0700864 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
Niels Möller6bb5ab92019-01-11 11:11:10 +0100865 double rate_factor_ RTC_GUARDED_BY(local_crit_sect_) = 1.0;
866 uint32_t last_framerate_ RTC_GUARDED_BY(local_crit_sect_) = 0;
Erik Språngd7329ca2019-02-21 21:19:53 +0100867 absl::optional<VideoBitrateAllocation> last_bitrate_allocation_;
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100868 VideoFrame::UpdateRect last_update_rect_
869 RTC_GUARDED_BY(local_crit_sect_) = {0, 0, 0, 0};
Niels Möller87e2d782019-03-07 10:18:23 +0100870 std::vector<VideoFrameType> last_frame_types_;
Erik Språngd7329ca2019-02-21 21:19:53 +0100871 bool expect_null_frame_ = false;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100872 EncodedImageCallback* encoded_image_callback_
873 RTC_GUARDED_BY(local_crit_sect_) = nullptr;
Elad Alon45befc52019-07-02 11:20:09 +0200874 MockFecControllerOverride fec_controller_override_;
perkj26091b12016-09-01 01:17:40 -0700875 };
876
mflodmancc3d4422017-08-03 08:27:51 -0700877 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700878 public:
879 explicit TestSink(TestEncoder* test_encoder)
Niels Möllerc572ff32018-11-07 08:43:50 +0100880 : test_encoder_(test_encoder) {}
perkj26091b12016-09-01 01:17:40 -0700881
perkj26091b12016-09-01 01:17:40 -0700882 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700883 EXPECT_TRUE(
884 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
885 }
886
887 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
888 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700889 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700890 if (!encoded_frame_event_.Wait(timeout_ms))
891 return false;
perkj26091b12016-09-01 01:17:40 -0700892 {
893 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800894 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700895 }
896 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700897 return true;
perkj26091b12016-09-01 01:17:40 -0700898 }
899
sprangb1ca0732017-02-01 08:38:12 -0800900 void WaitForEncodedFrame(uint32_t expected_width,
901 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700902 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100903 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700904 }
905
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100906 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700907 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800908 uint32_t width = 0;
909 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800910 {
911 rtc::CritScope lock(&crit_);
912 width = last_width_;
913 height = last_height_;
914 }
915 EXPECT_EQ(expected_height, height);
916 EXPECT_EQ(expected_width, width);
917 }
918
Ilya Nikolaevskiyba96e2f2019-06-04 15:15:14 +0200919 void CheckLastFrameRotationMatches(VideoRotation expected_rotation) {
920 VideoRotation rotation;
921 {
922 rtc::CritScope lock(&crit_);
923 rotation = last_rotation_;
924 }
925 EXPECT_EQ(expected_rotation, rotation);
926 }
927
kthelgason2fc52542017-03-03 00:24:41 -0800928 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800929
sprangc5d62e22017-04-02 23:53:04 -0700930 bool WaitForFrame(int64_t timeout_ms) {
931 return encoded_frame_event_.Wait(timeout_ms);
932 }
933
perkj26091b12016-09-01 01:17:40 -0700934 void SetExpectNoFrames() {
935 rtc::CritScope lock(&crit_);
936 expect_frames_ = false;
937 }
938
asaperssonfab67072017-04-04 05:51:49 -0700939 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200940 rtc::CritScope lock(&crit_);
941 return number_of_reconfigurations_;
942 }
943
asaperssonfab67072017-04-04 05:51:49 -0700944 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200945 rtc::CritScope lock(&crit_);
946 return min_transmit_bitrate_bps_;
947 }
948
Erik Språngd7329ca2019-02-21 21:19:53 +0100949 void SetNumExpectedLayers(size_t num_layers) {
950 rtc::CritScope lock(&crit_);
951 num_expected_layers_ = num_layers;
952 }
953
Erik Språngb7cb7b52019-02-26 15:52:33 +0100954 int64_t GetLastCaptureTimeMs() const {
955 rtc::CritScope lock(&crit_);
956 return last_capture_time_ms_;
957 }
958
Mirta Dvornicic28f0eb22019-05-28 16:30:16 +0200959 std::vector<uint8_t> GetLastEncodedImageData() {
960 rtc::CritScope lock(&crit_);
961 return std::move(last_encoded_image_data_);
962 }
963
964 RTPFragmentationHeader GetLastFragmentation() {
965 rtc::CritScope lock(&crit_);
966 return std::move(last_fragmentation_);
967 }
968
perkj26091b12016-09-01 01:17:40 -0700969 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700970 Result OnEncodedImage(
971 const EncodedImage& encoded_image,
972 const CodecSpecificInfo* codec_specific_info,
973 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200974 rtc::CritScope lock(&crit_);
975 EXPECT_TRUE(expect_frames_);
Mirta Dvornicic28f0eb22019-05-28 16:30:16 +0200976 last_encoded_image_data_ = std::vector<uint8_t>(
977 encoded_image.data(), encoded_image.data() + encoded_image.size());
978 if (fragmentation) {
979 last_fragmentation_.CopyFrom(*fragmentation);
980 }
Erik Språngd7329ca2019-02-21 21:19:53 +0100981 uint32_t timestamp = encoded_image.Timestamp();
982 if (last_timestamp_ != timestamp) {
983 num_received_layers_ = 1;
984 } else {
985 ++num_received_layers_;
986 }
987 last_timestamp_ = timestamp;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100988 last_capture_time_ms_ = encoded_image.capture_time_ms_;
sprangb1ca0732017-02-01 08:38:12 -0800989 last_width_ = encoded_image._encodedWidth;
990 last_height_ = encoded_image._encodedHeight;
Ilya Nikolaevskiyba96e2f2019-06-04 15:15:14 +0200991 last_rotation_ = encoded_image.rotation_;
Erik Språngd7329ca2019-02-21 21:19:53 +0100992 if (num_received_layers_ == num_expected_layers_) {
993 encoded_frame_event_.Set();
994 }
sprangb1ca0732017-02-01 08:38:12 -0800995 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200996 }
997
Rasmus Brandtc402dbe2019-02-04 11:09:46 +0100998 void OnEncoderConfigurationChanged(
999 std::vector<VideoStream> streams,
1000 VideoEncoderConfig::ContentType content_type,
1001 int min_transmit_bitrate_bps) override {
Per512ecb32016-09-23 15:52:06 +02001002 rtc::CriticalSection crit_;
1003 ++number_of_reconfigurations_;
1004 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
1005 }
1006
perkj26091b12016-09-01 01:17:40 -07001007 rtc::CriticalSection crit_;
1008 TestEncoder* test_encoder_;
1009 rtc::Event encoded_frame_event_;
Mirta Dvornicic28f0eb22019-05-28 16:30:16 +02001010 std::vector<uint8_t> last_encoded_image_data_;
1011 RTPFragmentationHeader last_fragmentation_;
sprangb1ca0732017-02-01 08:38:12 -08001012 uint32_t last_timestamp_ = 0;
Erik Språngb7cb7b52019-02-26 15:52:33 +01001013 int64_t last_capture_time_ms_ = 0;
sprangb1ca0732017-02-01 08:38:12 -08001014 uint32_t last_height_ = 0;
1015 uint32_t last_width_ = 0;
Ilya Nikolaevskiyba96e2f2019-06-04 15:15:14 +02001016 VideoRotation last_rotation_ = kVideoRotation_0;
Erik Språngd7329ca2019-02-21 21:19:53 +01001017 size_t num_expected_layers_ = 1;
1018 size_t num_received_layers_ = 0;
perkj26091b12016-09-01 01:17:40 -07001019 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +02001020 int number_of_reconfigurations_ = 0;
1021 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -07001022 };
1023
1024 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +01001025 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +02001026 int codec_width_;
1027 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -07001028 int max_framerate_;
Danil Chapovalovd3ba2362019-04-10 17:01:23 +02001029 const std::unique_ptr<TaskQueueFactory> task_queue_factory_;
perkj26091b12016-09-01 01:17:40 -07001030 TestEncoder fake_encoder_;
Niels Möllercbcbc222018-09-28 09:07:24 +02001031 test::VideoEncoderProxyFactory encoder_factory_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -08001032 std::unique_ptr<VideoBitrateAllocatorFactory> bitrate_allocator_factory_;
sprangc5d62e22017-04-02 23:53:04 -07001033 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -07001034 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -08001035 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -07001036 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -07001037 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -07001038};
1039
mflodmancc3d4422017-08-03 08:27:51 -07001040TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001041 video_stream_encoder_->OnBitrateUpdated(
1042 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möllerc572ff32018-11-07 08:43:50 +01001043 rtc::Event frame_destroyed_event;
perkja49cbd32016-09-16 07:53:41 -07001044 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -07001045 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -07001046 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -07001047 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -07001048}
1049
mflodmancc3d4422017-08-03 08:27:51 -07001050TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -07001051 // Dropped since no target bitrate has been set.
Niels Möllerc572ff32018-11-07 08:43:50 +01001052 rtc::Event frame_destroyed_event;
Sebastian Janssona3177052018-04-10 13:05:49 +02001053 // The encoder will cache up to one frame for a short duration. Adding two
1054 // frames means that the first frame will be dropped and the second frame will
1055 // be sent when the encoder is enabled.
perkja49cbd32016-09-16 07:53:41 -07001056 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
Sebastian Janssona3177052018-04-10 13:05:49 +02001057 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkja49cbd32016-09-16 07:53:41 -07001058 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -07001059
Erik Språng4c6ca302019-04-08 15:14:01 +02001060 video_stream_encoder_->OnBitrateUpdated(
1061 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkj26091b12016-09-01 01:17:40 -07001062
Sebastian Janssona3177052018-04-10 13:05:49 +02001063 // The pending frame should be received.
sprang4847ae62017-06-27 07:06:52 -07001064 WaitForEncodedFrame(2);
Sebastian Janssona3177052018-04-10 13:05:49 +02001065 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
1066
1067 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001068 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -07001069}
1070
mflodmancc3d4422017-08-03 08:27:51 -07001071TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001072 video_stream_encoder_->OnBitrateUpdated(
1073 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkja49cbd32016-09-16 07:53:41 -07001074 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001075 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -07001076
Erik Språng4c6ca302019-04-08 15:14:01 +02001077 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(0), DataRate::bps(0), 0,
Erik Språng610c7632019-03-06 15:37:33 +01001078 0);
Sebastian Janssona3177052018-04-10 13:05:49 +02001079 // The encoder will cache up to one frame for a short duration. Adding two
1080 // frames means that the first frame will be dropped and the second frame will
1081 // be sent when the encoder is resumed.
perkja49cbd32016-09-16 07:53:41 -07001082 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Sebastian Janssona3177052018-04-10 13:05:49 +02001083 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -07001084
Erik Språng4c6ca302019-04-08 15:14:01 +02001085 video_stream_encoder_->OnBitrateUpdated(
1086 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
sprang4847ae62017-06-27 07:06:52 -07001087 WaitForEncodedFrame(3);
Sebastian Janssona3177052018-04-10 13:05:49 +02001088 video_source_.IncomingCapturedFrame(CreateFrame(4, nullptr));
1089 WaitForEncodedFrame(4);
mflodmancc3d4422017-08-03 08:27:51 -07001090 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -07001091}
1092
mflodmancc3d4422017-08-03 08:27:51 -07001093TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001094 video_stream_encoder_->OnBitrateUpdated(
1095 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkja49cbd32016-09-16 07:53:41 -07001096 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001097 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -07001098
1099 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -07001100 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -07001101
perkja49cbd32016-09-16 07:53:41 -07001102 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001103 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001104 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -07001105}
1106
mflodmancc3d4422017-08-03 08:27:51 -07001107TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001108 video_stream_encoder_->OnBitrateUpdated(
1109 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkj26091b12016-09-01 01:17:40 -07001110
perkja49cbd32016-09-16 07:53:41 -07001111 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001112 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -07001113
mflodmancc3d4422017-08-03 08:27:51 -07001114 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -07001115 sink_.SetExpectNoFrames();
Niels Möllerc572ff32018-11-07 08:43:50 +01001116 rtc::Event frame_destroyed_event;
perkja49cbd32016-09-16 07:53:41 -07001117 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
1118 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -07001119}
1120
mflodmancc3d4422017-08-03 08:27:51 -07001121TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001122 video_stream_encoder_->OnBitrateUpdated(
1123 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkj26091b12016-09-01 01:17:40 -07001124
1125 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -07001126 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001127 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -07001128 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
1129 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -07001130 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
1131 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -07001132 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -07001133 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -07001134
mflodmancc3d4422017-08-03 08:27:51 -07001135 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -07001136}
1137
Noah Richards51db4212019-06-12 06:59:12 -07001138TEST_F(VideoStreamEncoderTest, DropFrameWithFailedI420Conversion) {
1139 video_stream_encoder_->OnBitrateUpdated(
1140 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
1141
1142 rtc::Event frame_destroyed_event;
1143 video_source_.IncomingCapturedFrame(
1144 CreateFakeNativeFrame(1, &frame_destroyed_event));
1145 ExpectDroppedFrame();
1146 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
1147 video_stream_encoder_->Stop();
1148}
1149
1150TEST_F(VideoStreamEncoderTest, DropFrameWithFailedI420ConversionWithCrop) {
1151 // Use the cropping factory.
1152 video_encoder_config_.video_stream_factory =
1153 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, 30);
1154 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config_),
1155 kMaxPayloadLength);
1156 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
1157
1158 // Capture a frame at codec_width_/codec_height_.
1159 video_stream_encoder_->OnBitrateUpdated(
1160 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
1161 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
1162 WaitForEncodedFrame(1);
1163 // The encoder will have been configured once.
1164 EXPECT_EQ(1, sink_.number_of_reconfigurations());
1165 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
1166 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
1167
1168 // Now send in a fake frame that needs to be cropped as the width/height
1169 // aren't divisible by 4 (see CreateEncoderStreams above).
1170 rtc::Event frame_destroyed_event;
1171 video_source_.IncomingCapturedFrame(CreateFakeNativeFrame(
1172 2, &frame_destroyed_event, codec_width_ + 1, codec_height_ + 1));
1173 ExpectDroppedFrame();
1174 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
1175 video_stream_encoder_->Stop();
1176}
1177
mflodmancc3d4422017-08-03 08:27:51 -07001178TEST_F(VideoStreamEncoderTest,
1179 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001180 video_stream_encoder_->OnBitrateUpdated(
1181 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Per21d45d22016-10-30 21:37:57 +01001182 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +02001183
1184 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +02001185 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001186 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +01001187 // The encoder will have been configured once when the first frame is
1188 // received.
1189 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +02001190
1191 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02001192 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +02001193 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -07001194 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001195 kMaxPayloadLength);
Per512ecb32016-09-23 15:52:06 +02001196
1197 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +02001198 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001199 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +01001200 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -07001201 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -07001202
mflodmancc3d4422017-08-03 08:27:51 -07001203 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -07001204}
1205
mflodmancc3d4422017-08-03 08:27:51 -07001206TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001207 video_stream_encoder_->OnBitrateUpdated(
1208 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkjfa10b552016-10-02 23:45:26 -07001209
1210 // Capture a frame and wait for it to synchronize with the encoder thread.
1211 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001212 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +01001213 // The encoder will have been configured once.
1214 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -07001215 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
1216 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
1217
1218 codec_width_ *= 2;
1219 codec_height_ *= 2;
1220 // Capture a frame with a higher resolution and wait for it to synchronize
1221 // with the encoder thread.
1222 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001223 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -07001224 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
1225 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +01001226 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -07001227
mflodmancc3d4422017-08-03 08:27:51 -07001228 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -07001229}
1230
mflodmancc3d4422017-08-03 08:27:51 -07001231TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -07001232 EXPECT_TRUE(video_source_.has_sinks());
1233 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001234 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001235 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001236 EXPECT_FALSE(video_source_.has_sinks());
1237 EXPECT_TRUE(new_video_source.has_sinks());
1238
mflodmancc3d4422017-08-03 08:27:51 -07001239 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001240}
1241
mflodmancc3d4422017-08-03 08:27:51 -07001242TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -07001243 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -07001244 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -07001245 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -07001246 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001247}
1248
Jonathan Yubc771b72017-12-08 17:04:29 -08001249TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
1250 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -07001251 const int kWidth = 1280;
1252 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -08001253
1254 // We rely on the automatic resolution adaptation, but we handle framerate
1255 // adaptation manually by mocking the stats proxy.
1256 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -07001257
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001258 // Enable BALANCED preference, no initial limitation.
Erik Språng4c6ca302019-04-08 15:14:01 +02001259 video_stream_encoder_->OnBitrateUpdated(
1260 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001261 video_stream_encoder_->SetSource(&video_source_,
1262 webrtc::DegradationPreference::BALANCED);
Jonathan Yubc771b72017-12-08 17:04:29 -08001263 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001264 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001265 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -07001266 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1267
Jonathan Yubc771b72017-12-08 17:04:29 -08001268 // Adapt down as far as possible.
1269 rtc::VideoSinkWants last_wants;
1270 int64_t t = 1;
1271 int loop_count = 0;
1272 do {
1273 ++loop_count;
1274 last_wants = video_source_.sink_wants();
1275
1276 // Simulate the framerate we've been asked to adapt to.
1277 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
1278 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
1279 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1280 mock_stats.input_frame_rate = fps;
1281 stats_proxy_->SetMockStats(mock_stats);
1282
1283 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1284 sink_.WaitForEncodedFrame(t);
1285 t += frame_interval_ms;
1286
mflodmancc3d4422017-08-03 08:27:51 -07001287 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08001288 VerifyBalancedModeFpsRange(
1289 video_source_.sink_wants(),
1290 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1291 } while (video_source_.sink_wants().max_pixel_count <
1292 last_wants.max_pixel_count ||
1293 video_source_.sink_wants().max_framerate_fps <
1294 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001295
Jonathan Yubc771b72017-12-08 17:04:29 -08001296 // Verify that we've adapted all the way down.
1297 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001298 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001299 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
1300 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -07001301 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -08001302 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
1303 *video_source_.last_sent_height());
1304 EXPECT_EQ(kMinBalancedFramerateFps,
1305 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001306
Jonathan Yubc771b72017-12-08 17:04:29 -08001307 // Adapt back up the same number of times we adapted down.
1308 for (int i = 0; i < loop_count - 1; ++i) {
1309 last_wants = video_source_.sink_wants();
1310
1311 // Simulate the framerate we've been asked to adapt to.
1312 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
1313 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
1314 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1315 mock_stats.input_frame_rate = fps;
1316 stats_proxy_->SetMockStats(mock_stats);
1317
1318 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1319 sink_.WaitForEncodedFrame(t);
1320 t += frame_interval_ms;
1321
mflodmancc3d4422017-08-03 08:27:51 -07001322 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -08001323 VerifyBalancedModeFpsRange(
1324 video_source_.sink_wants(),
1325 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1326 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
1327 last_wants.max_pixel_count ||
1328 video_source_.sink_wants().max_framerate_fps >
1329 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001330 }
1331
Åsa Persson8c1bf952018-09-13 10:42:19 +02001332 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001333 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001334 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001335 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1336 EXPECT_EQ((loop_count - 1) * 2,
1337 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -07001338
mflodmancc3d4422017-08-03 08:27:51 -07001339 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001340}
mflodmancc3d4422017-08-03 08:27:51 -07001341TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001342 video_stream_encoder_->OnBitrateUpdated(
1343 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001344 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001345
sprangc5d62e22017-04-02 23:53:04 -07001346 const int kFrameWidth = 1280;
1347 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07001348
Åsa Persson8c1bf952018-09-13 10:42:19 +02001349 int64_t frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -07001350
kthelgason5e13d412016-12-01 03:59:51 -08001351 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001352 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001353 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001354 frame_timestamp += kFrameIntervalMs;
1355
perkj803d97f2016-11-01 11:45:46 -07001356 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001357 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001358 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001359 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001360 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001361 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -07001362
asapersson0944a802017-04-07 00:57:58 -07001363 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -07001364 // wanted resolution.
1365 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
1366 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
1367 kFrameWidth * kFrameHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001368 EXPECT_EQ(kDefaultFramerate, video_source_.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001369
1370 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -07001371 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001372 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001373 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001374
sprangc5d62e22017-04-02 23:53:04 -07001375 // Initially no degradation registered.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001376 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001377
sprangc5d62e22017-04-02 23:53:04 -07001378 // Force an input frame rate to be available, or the adaptation call won't
1379 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -07001380 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -07001381 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -07001382 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -07001383 stats_proxy_->SetMockStats(stats);
1384
mflodmancc3d4422017-08-03 08:27:51 -07001385 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001386 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001387 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001388 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001389 frame_timestamp += kFrameIntervalMs;
1390
1391 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001392 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001393 EXPECT_EQ(std::numeric_limits<int>::max(),
1394 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001395 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001396
asapersson02465b82017-04-10 01:12:52 -07001397 // Turn off degradation completely.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001398 video_stream_encoder_->SetSource(&new_video_source,
1399 webrtc::DegradationPreference::DISABLED);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001400 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001401
mflodmancc3d4422017-08-03 08:27:51 -07001402 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001403 new_video_source.IncomingCapturedFrame(
1404 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001405 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001406 frame_timestamp += kFrameIntervalMs;
1407
1408 // Still no degradation.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001409 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001410
1411 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001412 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001413 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
sprangc5d62e22017-04-02 23:53:04 -07001414 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1415 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001416 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001417 EXPECT_EQ(kDefaultFramerate, new_video_source.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001418
1419 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001420 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001421 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001422 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1423 EXPECT_EQ(std::numeric_limits<int>::max(),
1424 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001425 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001426
mflodmancc3d4422017-08-03 08:27:51 -07001427 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001428}
1429
mflodmancc3d4422017-08-03 08:27:51 -07001430TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001431 video_stream_encoder_->OnBitrateUpdated(
1432 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001433
asaperssonfab67072017-04-04 05:51:49 -07001434 const int kWidth = 1280;
1435 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001436 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001437 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001438 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1439 EXPECT_FALSE(stats.bw_limited_resolution);
1440 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1441
1442 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001443 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001444 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001445 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001446
1447 stats = stats_proxy_->GetStats();
1448 EXPECT_TRUE(stats.bw_limited_resolution);
1449 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1450
1451 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001452 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001453 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001454 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001455
1456 stats = stats_proxy_->GetStats();
1457 EXPECT_FALSE(stats.bw_limited_resolution);
1458 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1459 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1460
mflodmancc3d4422017-08-03 08:27:51 -07001461 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001462}
1463
mflodmancc3d4422017-08-03 08:27:51 -07001464TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001465 video_stream_encoder_->OnBitrateUpdated(
1466 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001467
1468 const int kWidth = 1280;
1469 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001470 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001471 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001472 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1473 EXPECT_FALSE(stats.cpu_limited_resolution);
1474 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1475
1476 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001477 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001478 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001479 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001480
1481 stats = stats_proxy_->GetStats();
1482 EXPECT_TRUE(stats.cpu_limited_resolution);
1483 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1484
1485 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001486 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001487 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001488 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001489
1490 stats = stats_proxy_->GetStats();
1491 EXPECT_FALSE(stats.cpu_limited_resolution);
1492 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001493 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001494
mflodmancc3d4422017-08-03 08:27:51 -07001495 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001496}
1497
mflodmancc3d4422017-08-03 08:27:51 -07001498TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001499 video_stream_encoder_->OnBitrateUpdated(
1500 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001501
asaperssonfab67072017-04-04 05:51:49 -07001502 const int kWidth = 1280;
1503 const int kHeight = 720;
1504 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001505 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001506 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001507 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001508 EXPECT_FALSE(stats.cpu_limited_resolution);
1509 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1510
asaperssonfab67072017-04-04 05:51:49 -07001511 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001512 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001513 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001514 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001515 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001516 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001517 EXPECT_TRUE(stats.cpu_limited_resolution);
1518 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1519
1520 // Set new source with adaptation still enabled.
1521 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001522 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001523 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001524
asaperssonfab67072017-04-04 05:51:49 -07001525 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001526 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001527 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001528 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001529 EXPECT_TRUE(stats.cpu_limited_resolution);
1530 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1531
1532 // Set adaptation disabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001533 video_stream_encoder_->SetSource(&new_video_source,
1534 webrtc::DegradationPreference::DISABLED);
kthelgason876222f2016-11-29 01:44:11 -08001535
asaperssonfab67072017-04-04 05:51:49 -07001536 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001537 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001538 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001539 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001540 EXPECT_FALSE(stats.cpu_limited_resolution);
1541 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1542
1543 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001544 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001545 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001546
asaperssonfab67072017-04-04 05:51:49 -07001547 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001548 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001549 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001550 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001551 EXPECT_TRUE(stats.cpu_limited_resolution);
1552 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1553
asaperssonfab67072017-04-04 05:51:49 -07001554 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001555 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001556 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001557 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001558 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001559 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001560 EXPECT_FALSE(stats.cpu_limited_resolution);
1561 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001562 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001563
mflodmancc3d4422017-08-03 08:27:51 -07001564 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001565}
1566
mflodmancc3d4422017-08-03 08:27:51 -07001567TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001568 video_stream_encoder_->OnBitrateUpdated(
1569 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001570
asaperssonfab67072017-04-04 05:51:49 -07001571 const int kWidth = 1280;
1572 const int kHeight = 720;
1573 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001574 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001575 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001576 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001577 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001578 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001579
1580 // Set new source with adaptation still enabled.
1581 test::FrameForwarder new_video_source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001582 video_stream_encoder_->SetSource(&new_video_source,
1583 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001584
asaperssonfab67072017-04-04 05:51:49 -07001585 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001586 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001587 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001588 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001589 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001590 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001591
asaperssonfab67072017-04-04 05:51:49 -07001592 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001593 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001594 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001595 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001596 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001597 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001598 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001599 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001600
asaperssonfab67072017-04-04 05:51:49 -07001601 // Set new source with adaptation still enabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001602 video_stream_encoder_->SetSource(&new_video_source,
1603 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001604
asaperssonfab67072017-04-04 05:51:49 -07001605 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001606 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001607 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001608 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001609 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001610 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001611
asapersson02465b82017-04-10 01:12:52 -07001612 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001613 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001614 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001615
asaperssonfab67072017-04-04 05:51:49 -07001616 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001617 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001618 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001619 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001620 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001621 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1622 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001623
mflodmancc3d4422017-08-03 08:27:51 -07001624 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001625}
1626
mflodmancc3d4422017-08-03 08:27:51 -07001627TEST_F(VideoStreamEncoderTest,
1628 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001629 video_stream_encoder_->OnBitrateUpdated(
1630 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001631
1632 const int kWidth = 1280;
1633 const int kHeight = 720;
Åsa Persson8c1bf952018-09-13 10:42:19 +02001634 int64_t timestamp_ms = kFrameIntervalMs;
asapersson36e9eb42017-03-31 05:29:12 -07001635 video_source_.set_adaptation_enabled(true);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001636 video_source_.IncomingCapturedFrame(
1637 CreateFrame(timestamp_ms, kWidth, kHeight));
1638 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001639 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1640 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1641 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1642
1643 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001644 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001645 timestamp_ms += kFrameIntervalMs;
1646 video_source_.IncomingCapturedFrame(
1647 CreateFrame(timestamp_ms, kWidth, kHeight));
1648 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001649 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1650 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1651 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1652
1653 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001654 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001655 timestamp_ms += kFrameIntervalMs;
1656 video_source_.IncomingCapturedFrame(
1657 CreateFrame(timestamp_ms, kWidth, kHeight));
1658 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001659 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1660 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1661 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1662
Niels Möller4db138e2018-04-19 09:04:13 +02001663 // Leave source unchanged, but disable quality scaler.
asapersson36e9eb42017-03-31 05:29:12 -07001664 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02001665
1666 VideoEncoderConfig video_encoder_config;
1667 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
1668 // Make format different, to force recreation of encoder.
1669 video_encoder_config.video_format.parameters["foo"] = "foo";
1670 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001671 kMaxPayloadLength);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001672 timestamp_ms += kFrameIntervalMs;
1673 video_source_.IncomingCapturedFrame(
1674 CreateFrame(timestamp_ms, kWidth, kHeight));
1675 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001676 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1677 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1678 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1679
mflodmancc3d4422017-08-03 08:27:51 -07001680 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001681}
1682
mflodmancc3d4422017-08-03 08:27:51 -07001683TEST_F(VideoStreamEncoderTest,
1684 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001685 video_stream_encoder_->OnBitrateUpdated(
1686 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001687
asapersson0944a802017-04-07 00:57:58 -07001688 const int kWidth = 1280;
1689 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001690 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001691
asaperssonfab67072017-04-04 05:51:49 -07001692 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001693 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001694 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001695 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001696 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001697 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1698
asapersson02465b82017-04-10 01:12:52 -07001699 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001700 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001701 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001702 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001703 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001704 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001705 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001706 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1707
1708 // Set new source with adaptation still enabled.
1709 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001710 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001711 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001712
1713 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001714 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001715 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001716 stats = stats_proxy_->GetStats();
1717 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001718 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001719 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1720
sprangc5d62e22017-04-02 23:53:04 -07001721 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001722 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001723 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001724 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001725 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001726 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001727 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001728 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001729 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001730 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001731 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1732
sprangc5d62e22017-04-02 23:53:04 -07001733 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001734 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001735 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1736 mock_stats.input_frame_rate = 30;
1737 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001738 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001739 stats_proxy_->ResetMockStats();
1740
1741 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001742 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001743 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001744
1745 // Framerate now adapted.
1746 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001747 EXPECT_FALSE(stats.cpu_limited_resolution);
1748 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001749 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1750
1751 // Disable CPU adaptation.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001752 video_stream_encoder_->SetSource(&new_video_source,
1753 webrtc::DegradationPreference::DISABLED);
sprangc5d62e22017-04-02 23:53:04 -07001754 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001755 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001756 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001757
1758 stats = stats_proxy_->GetStats();
1759 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001760 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001761 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1762
1763 // Try to trigger overuse. Should not succeed.
1764 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001765 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001766 stats_proxy_->ResetMockStats();
1767
1768 stats = stats_proxy_->GetStats();
1769 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001770 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001771 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1772
1773 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001774 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001775 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssonfab67072017-04-04 05:51:49 -07001776 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001777 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001778 stats = stats_proxy_->GetStats();
1779 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001780 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001781 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001782
1783 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001784 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001785 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001786 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001787 stats = stats_proxy_->GetStats();
1788 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001789 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001790 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1791
1792 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001793 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001794 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001795 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001796 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001797 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001798 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001799 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001800 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001801 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001802 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1803
1804 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001805 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001806 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001807 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001808 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001809 stats = stats_proxy_->GetStats();
1810 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001811 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001812 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001813 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001814
mflodmancc3d4422017-08-03 08:27:51 -07001815 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001816}
1817
mflodmancc3d4422017-08-03 08:27:51 -07001818TEST_F(VideoStreamEncoderTest,
1819 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001820 const int kWidth = 1280;
1821 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02001822 video_stream_encoder_->OnBitrateUpdated(
1823 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001824
asaperssonfab67072017-04-04 05:51:49 -07001825 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001826 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001827
asaperssonfab67072017-04-04 05:51:49 -07001828 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001829 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001830
asaperssonfab67072017-04-04 05:51:49 -07001831 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001832 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001833
asaperssonfab67072017-04-04 05:51:49 -07001834 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001835 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001836
kthelgason876222f2016-11-29 01:44:11 -08001837 // Expect a scale down.
1838 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001839 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001840
asapersson02465b82017-04-10 01:12:52 -07001841 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001842 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001843 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001844 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001845
asaperssonfab67072017-04-04 05:51:49 -07001846 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001847 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001848 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001849 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001850
asaperssonfab67072017-04-04 05:51:49 -07001851 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001852 EXPECT_EQ(std::numeric_limits<int>::max(),
1853 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001854
asaperssonfab67072017-04-04 05:51:49 -07001855 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001856 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001857 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001858 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001859
asapersson02465b82017-04-10 01:12:52 -07001860 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001861 EXPECT_EQ(std::numeric_limits<int>::max(),
1862 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001863
mflodmancc3d4422017-08-03 08:27:51 -07001864 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001865}
1866
mflodmancc3d4422017-08-03 08:27:51 -07001867TEST_F(VideoStreamEncoderTest,
1868 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001869 const int kWidth = 1280;
1870 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02001871 video_stream_encoder_->OnBitrateUpdated(
1872 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001873
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001874 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001875 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001876 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001877 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001878
1879 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001880 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001881 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001882 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1883 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1884
1885 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001886 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001887 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001888 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1889 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1890 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1891
1892 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001893 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001894 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1895 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1896 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1897
mflodmancc3d4422017-08-03 08:27:51 -07001898 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001899}
1900
mflodmancc3d4422017-08-03 08:27:51 -07001901TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001902 const int kWidth = 1280;
1903 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02001904 video_stream_encoder_->OnBitrateUpdated(
1905 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001906
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001907 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001908 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001909 video_stream_encoder_->SetSource(&source,
1910 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001911 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1912 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001913 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001914
1915 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001916 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001917 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1918 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1919 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1920 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1921
1922 // Trigger adapt down for same input resolution, expect no change.
1923 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1924 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001925 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001926 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1927 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1928 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1929
1930 // Trigger adapt down for larger input resolution, expect no change.
1931 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1932 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001933 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001934 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1935 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1936 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1937
mflodmancc3d4422017-08-03 08:27:51 -07001938 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001939}
1940
mflodmancc3d4422017-08-03 08:27:51 -07001941TEST_F(VideoStreamEncoderTest,
1942 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001943 const int kWidth = 1280;
1944 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02001945 video_stream_encoder_->OnBitrateUpdated(
1946 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001947
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001948 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001949 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001950 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001951 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001952
1953 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001954 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001955 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001956 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1957 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1958
1959 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001960 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001961 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001962 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1963 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1964
mflodmancc3d4422017-08-03 08:27:51 -07001965 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001966}
1967
mflodmancc3d4422017-08-03 08:27:51 -07001968TEST_F(VideoStreamEncoderTest,
1969 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001970 const int kWidth = 1280;
1971 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02001972 video_stream_encoder_->OnBitrateUpdated(
1973 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001974
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001975 // Enable MAINTAIN_RESOLUTION preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001976 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001977 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001978 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
asapersson02465b82017-04-10 01:12:52 -07001979
1980 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001981 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001982 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001983 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001984 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1985
1986 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001987 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001988 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001989 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001990 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1991
mflodmancc3d4422017-08-03 08:27:51 -07001992 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001993}
1994
mflodmancc3d4422017-08-03 08:27:51 -07001995TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001996 const int kWidth = 1280;
1997 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02001998 video_stream_encoder_->OnBitrateUpdated(
1999 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002000
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002001 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002002 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002003 video_stream_encoder_->SetSource(&source,
2004 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002005
2006 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2007 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002008 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002009 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2010 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2011 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2012
2013 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002014 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002015 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002016 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2017 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2018 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2019
mflodmancc3d4422017-08-03 08:27:51 -07002020 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002021}
2022
mflodmancc3d4422017-08-03 08:27:51 -07002023TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07002024 const int kWidth = 1280;
2025 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02002026 video_stream_encoder_->OnBitrateUpdated(
2027 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002028
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002029 // Enable DISABLED preference, no initial limitation.
asapersson09f05612017-05-15 23:40:18 -07002030 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002031 video_stream_encoder_->SetSource(&source,
2032 webrtc::DegradationPreference::DISABLED);
asapersson09f05612017-05-15 23:40:18 -07002033
2034 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2035 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002036 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07002037 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2038 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2039 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2040
2041 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002042 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002043 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07002044 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2045 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2046 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2047
mflodmancc3d4422017-08-03 08:27:51 -07002048 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07002049}
2050
mflodmancc3d4422017-08-03 08:27:51 -07002051TEST_F(VideoStreamEncoderTest,
2052 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07002053 const int kWidth = 1280;
2054 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02002055 video_stream_encoder_->OnBitrateUpdated(
2056 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07002057
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002058 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07002059 AdaptingFrameForwarder source;
2060 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002061 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002062 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07002063
2064 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002065 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002066 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07002067 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2068 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2069
2070 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002071 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07002072 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002073 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07002074 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07002075 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2076 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2077
2078 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002079 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002080 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07002081 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2082 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2083 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2084
mflodmancc3d4422017-08-03 08:27:51 -07002085 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002086}
2087
mflodmancc3d4422017-08-03 08:27:51 -07002088TEST_F(VideoStreamEncoderTest,
2089 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07002090 const int kWidth = 1280;
2091 const int kHeight = 720;
2092 const int kInputFps = 30;
Erik Språng4c6ca302019-04-08 15:14:01 +02002093 video_stream_encoder_->OnBitrateUpdated(
2094 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002095
2096 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2097 stats.input_frame_rate = kInputFps;
2098 stats_proxy_->SetMockStats(stats);
2099
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002100 // Expect no scaling to begin with (preference: MAINTAIN_FRAMERATE).
asapersson09f05612017-05-15 23:40:18 -07002101 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2102 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002103 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07002104
2105 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002106 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07002107 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
2108 sink_.WaitForEncodedFrame(2);
2109 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
2110
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002111 // Enable MAINTAIN_RESOLUTION preference.
asapersson09f05612017-05-15 23:40:18 -07002112 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07002113 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002114 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002115 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07002116
2117 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07002118 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07002119 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
2120 sink_.WaitForEncodedFrame(3);
2121 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
2122
2123 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002124 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002125 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07002126
mflodmancc3d4422017-08-03 08:27:51 -07002127 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07002128}
2129
mflodmancc3d4422017-08-03 08:27:51 -07002130TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07002131 const int kWidth = 1280;
2132 const int kHeight = 720;
2133 const size_t kNumFrames = 10;
2134
Erik Språng4c6ca302019-04-08 15:14:01 +02002135 video_stream_encoder_->OnBitrateUpdated(
2136 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08002137
asaperssond0de2952017-04-21 01:47:31 -07002138 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07002139 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07002140 video_source_.set_adaptation_enabled(true);
2141
2142 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2143 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2144
2145 int downscales = 0;
2146 for (size_t i = 1; i <= kNumFrames; i++) {
Åsa Persson8c1bf952018-09-13 10:42:19 +02002147 video_source_.IncomingCapturedFrame(
2148 CreateFrame(i * kFrameIntervalMs, kWidth, kHeight));
2149 WaitForEncodedFrame(i * kFrameIntervalMs);
asaperssond0de2952017-04-21 01:47:31 -07002150
asaperssonfab67072017-04-04 05:51:49 -07002151 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07002152 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07002153 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07002154 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07002155
2156 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
2157 ++downscales;
2158
2159 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2160 EXPECT_EQ(downscales,
2161 stats_proxy_->GetStats().number_of_quality_adapt_changes);
2162 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08002163 }
mflodmancc3d4422017-08-03 08:27:51 -07002164 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002165}
2166
mflodmancc3d4422017-08-03 08:27:51 -07002167TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002168 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
2169 const int kWidth = 1280;
2170 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02002171 video_stream_encoder_->OnBitrateUpdated(
2172 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002173
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002174 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002175 AdaptingFrameForwarder source;
2176 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002177 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002178 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002179
Åsa Persson8c1bf952018-09-13 10:42:19 +02002180 int64_t timestamp_ms = kFrameIntervalMs;
2181 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002182 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002183 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002184 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2185 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2186
2187 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002188 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002189 timestamp_ms += kFrameIntervalMs;
2190 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2191 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002192 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002193 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2194 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2195
2196 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002197 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002198 timestamp_ms += kFrameIntervalMs;
2199 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002200 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002201 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002202 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2203 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2204
2205 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002206 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002207 timestamp_ms += kFrameIntervalMs;
2208 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2209 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002210 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002211 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2212 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2213
2214 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002215 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002216 timestamp_ms += kFrameIntervalMs;
2217 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asapersson09f05612017-05-15 23:40:18 -07002218 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002219 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002220 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2221 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2222
mflodmancc3d4422017-08-03 08:27:51 -07002223 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002224}
2225
mflodmancc3d4422017-08-03 08:27:51 -07002226TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07002227 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
2228 const int kWidth = 1280;
2229 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02002230 video_stream_encoder_->OnBitrateUpdated(
2231 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002232
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002233 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002234 AdaptingFrameForwarder source;
2235 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002236 video_stream_encoder_->SetSource(&source,
2237 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002238
Åsa Persson8c1bf952018-09-13 10:42:19 +02002239 int64_t timestamp_ms = kFrameIntervalMs;
2240 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07002241 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002242 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002243 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2244 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2245
2246 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002247 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002248 timestamp_ms += kFrameIntervalMs;
2249 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2250 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002251 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2252 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2253 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2254
2255 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002256 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002257 timestamp_ms += kFrameIntervalMs;
2258 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07002259 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002260 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002261 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2262 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2263
2264 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002265 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002266 timestamp_ms += kFrameIntervalMs;
2267 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2268 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002269 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2270 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2271 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2272
2273 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002274 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002275 timestamp_ms += kFrameIntervalMs;
2276 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07002277 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002278 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002279 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2280 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2281
mflodmancc3d4422017-08-03 08:27:51 -07002282 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002283}
2284
mflodmancc3d4422017-08-03 08:27:51 -07002285TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002286 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
2287 const int kWidth = 1280;
2288 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02002289 video_stream_encoder_->OnBitrateUpdated(
2290 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002291
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002292 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002293 AdaptingFrameForwarder source;
2294 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002295 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002296 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002297
Åsa Persson8c1bf952018-09-13 10:42:19 +02002298 int64_t timestamp_ms = kFrameIntervalMs;
2299 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002300 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002301 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002302 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2303 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2304 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2305 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2306
2307 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002308 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002309 timestamp_ms += kFrameIntervalMs;
2310 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2311 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002312 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002313 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2314 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2315 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2316 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2317
2318 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07002319 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002320 timestamp_ms += kFrameIntervalMs;
2321 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2322 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002323 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002324 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2325 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2326 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2327 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2328
Jonathan Yubc771b72017-12-08 17:04:29 -08002329 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002330 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002331 timestamp_ms += kFrameIntervalMs;
2332 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2333 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002334 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002335 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2336 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002337 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002338 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2339
Jonathan Yubc771b72017-12-08 17:04:29 -08002340 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07002341 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002342 timestamp_ms += kFrameIntervalMs;
2343 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2344 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002345 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002346 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07002347 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2348 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2349 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2350 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2351
Jonathan Yubc771b72017-12-08 17:04:29 -08002352 // Trigger quality adapt down, expect no change (min resolution reached).
2353 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002354 timestamp_ms += kFrameIntervalMs;
2355 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2356 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002357 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
2358 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2359 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2360 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2361 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2362
2363 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002364 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002365 timestamp_ms += kFrameIntervalMs;
2366 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2367 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002368 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002369 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2370 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2371 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2372 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2373
2374 // Trigger cpu adapt up, expect upscaled resolution (640x360).
2375 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002376 timestamp_ms += kFrameIntervalMs;
2377 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2378 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002379 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2380 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2381 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2382 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2383 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2384
2385 // Trigger cpu adapt up, expect upscaled resolution (960x540).
2386 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002387 timestamp_ms += kFrameIntervalMs;
2388 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2389 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002390 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002391 last_wants = source.sink_wants();
2392 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2393 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002394 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002395 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2396
2397 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002398 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002399 timestamp_ms += kFrameIntervalMs;
2400 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2401 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002402 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002403 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2404 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002405 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002406 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2407
2408 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002409 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002410 timestamp_ms += kFrameIntervalMs;
2411 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002412 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002413 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002414 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002415 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2416 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002417 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002418 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002419
mflodmancc3d4422017-08-03 08:27:51 -07002420 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002421}
2422
mflodmancc3d4422017-08-03 08:27:51 -07002423TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002424 const int kWidth = 640;
2425 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002426
Erik Språng4c6ca302019-04-08 15:14:01 +02002427 video_stream_encoder_->OnBitrateUpdated(
2428 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002429
perkj803d97f2016-11-01 11:45:46 -07002430 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002431 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002432 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002433 }
2434
mflodmancc3d4422017-08-03 08:27:51 -07002435 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002436 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002437 video_source_.IncomingCapturedFrame(CreateFrame(
2438 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002439 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002440 }
2441
mflodmancc3d4422017-08-03 08:27:51 -07002442 video_stream_encoder_->Stop();
2443 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002444 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002445
perkj803d97f2016-11-01 11:45:46 -07002446 EXPECT_EQ(1,
2447 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2448 EXPECT_EQ(
2449 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2450}
2451
mflodmancc3d4422017-08-03 08:27:51 -07002452TEST_F(VideoStreamEncoderTest,
2453 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
Erik Språng4c6ca302019-04-08 15:14:01 +02002454 video_stream_encoder_->OnBitrateUpdated(
2455 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002456 const int kWidth = 640;
2457 const int kHeight = 360;
2458
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002459 video_stream_encoder_->SetSource(&video_source_,
2460 webrtc::DegradationPreference::DISABLED);
asaperssonf4e44af2017-04-19 02:01:06 -07002461
2462 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2463 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002464 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002465 }
2466
mflodmancc3d4422017-08-03 08:27:51 -07002467 video_stream_encoder_->Stop();
2468 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002469 stats_proxy_.reset();
2470
2471 EXPECT_EQ(0,
2472 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2473}
2474
mflodmancc3d4422017-08-03 08:27:51 -07002475TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002476 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02002477 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002478
2479 const int kDefaultFps = 30;
Erik Språng566124a2018-04-23 12:32:22 +02002480 const VideoBitrateAllocation expected_bitrate =
sprang57c2fff2017-01-16 06:24:02 -08002481 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002482 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002483
sprang57c2fff2017-01-16 06:24:02 -08002484 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
Niels Möller6bb5ab92019-01-11 11:11:10 +01002485 .Times(1);
Erik Språng610c7632019-03-06 15:37:33 +01002486 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kLowTargetBitrateBps),
Erik Språng4c6ca302019-04-08 15:14:01 +02002487 DataRate::bps(kLowTargetBitrateBps),
2488 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002489
sprang57c2fff2017-01-16 06:24:02 -08002490 video_source_.IncomingCapturedFrame(
Erik Språngd7329ca2019-02-21 21:19:53 +01002491 CreateFrame(rtc::TimeMillis(), codec_width_, codec_height_));
2492 WaitForEncodedFrame(rtc::TimeMillis());
2493 absl::optional<VideoBitrateAllocation> bitrate_allocation =
2494 fake_encoder_.GetAndResetLastBitrateAllocation();
2495 // Check that encoder has been updated too, not just allocation observer.
2496 EXPECT_EQ(bitrate_allocation->get_sum_bps(), kLowTargetBitrateBps);
Sebastian Jansson40889f32019-04-17 12:11:20 +02002497 // TODO(srte): The use of millisecs here looks like an error, but the tests
2498 // fails using seconds, this should be investigated.
2499 fake_clock_.AdvanceTime(TimeDelta::ms(1) / kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002500
2501 // Not called on second frame.
2502 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2503 .Times(0);
2504 video_source_.IncomingCapturedFrame(
Erik Språngd7329ca2019-02-21 21:19:53 +01002505 CreateFrame(rtc::TimeMillis(), codec_width_, codec_height_));
2506 WaitForEncodedFrame(rtc::TimeMillis());
Sebastian Jansson40889f32019-04-17 12:11:20 +02002507 fake_clock_.AdvanceTime(TimeDelta::ms(1) / kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002508
2509 // Called after a process interval.
2510 const int64_t kProcessIntervalMs =
2511 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang57c2fff2017-01-16 06:24:02 -08002512 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2513 .Times(1);
Erik Språngd7329ca2019-02-21 21:19:53 +01002514 const int64_t start_time_ms = rtc::TimeMillis();
2515 while (rtc::TimeMillis() - start_time_ms < kProcessIntervalMs) {
2516 video_source_.IncomingCapturedFrame(
2517 CreateFrame(rtc::TimeMillis(), codec_width_, codec_height_));
2518 WaitForEncodedFrame(rtc::TimeMillis());
Sebastian Jansson40889f32019-04-17 12:11:20 +02002519 fake_clock_.AdvanceTime(TimeDelta::ms(1) / kDefaultFps);
Erik Språngd7329ca2019-02-21 21:19:53 +01002520 }
2521
2522 // Since rates are unchanged, encoder should not be reconfigured.
2523 EXPECT_FALSE(fake_encoder_.GetAndResetLastBitrateAllocation().has_value());
sprang57c2fff2017-01-16 06:24:02 -08002524
mflodmancc3d4422017-08-03 08:27:51 -07002525 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002526}
2527
Åsa Perssonc29cb2c2019-03-25 12:06:59 +01002528TEST_F(VideoStreamEncoderTest, TemporalLayersNotDisabledIfSupported) {
2529 // 2 TLs configured, temporal layers supported by encoder.
2530 const int kNumTemporalLayers = 2;
2531 ResetEncoder("VP8", 1, kNumTemporalLayers, 1, /*screenshare*/ false);
2532 fake_encoder_.SetTemporalLayersSupported(0, true);
2533
2534 // Bitrate allocated across temporal layers.
2535 const int kTl0Bps = kTargetBitrateBps *
2536 webrtc::SimulcastRateAllocator::GetTemporalRateAllocation(
2537 kNumTemporalLayers, /*temporal_id*/ 0);
2538 const int kTl1Bps = kTargetBitrateBps *
2539 webrtc::SimulcastRateAllocator::GetTemporalRateAllocation(
2540 kNumTemporalLayers, /*temporal_id*/ 1);
2541 VideoBitrateAllocation expected_bitrate;
2542 expected_bitrate.SetBitrate(/*si*/ 0, /*ti*/ 0, kTl0Bps);
2543 expected_bitrate.SetBitrate(/*si*/ 0, /*ti*/ 1, kTl1Bps - kTl0Bps);
2544
2545 VerifyAllocatedBitrate(expected_bitrate);
2546 video_stream_encoder_->Stop();
2547}
2548
2549TEST_F(VideoStreamEncoderTest, TemporalLayersDisabledIfNotSupported) {
2550 // 2 TLs configured, temporal layers not supported by encoder.
2551 ResetEncoder("VP8", 1, /*num_temporal_layers*/ 2, 1, /*screenshare*/ false);
2552 fake_encoder_.SetTemporalLayersSupported(0, false);
2553
2554 // Temporal layers not supported by the encoder.
2555 // Total bitrate should be at ti:0.
2556 VideoBitrateAllocation expected_bitrate;
2557 expected_bitrate.SetBitrate(/*si*/ 0, /*ti*/ 0, kTargetBitrateBps);
2558
2559 VerifyAllocatedBitrate(expected_bitrate);
2560 video_stream_encoder_->Stop();
2561}
2562
2563TEST_F(VideoStreamEncoderTest, VerifyBitrateAllocationForTwoStreams) {
2564 // 2 TLs configured, temporal layers only supported for first stream.
2565 ResetEncoder("VP8", 2, /*num_temporal_layers*/ 2, 1, /*screenshare*/ false);
2566 fake_encoder_.SetTemporalLayersSupported(0, true);
2567 fake_encoder_.SetTemporalLayersSupported(1, false);
2568
2569 const int kS0Bps = 150000;
2570 const int kS0Tl0Bps =
2571 kS0Bps * webrtc::SimulcastRateAllocator::GetTemporalRateAllocation(
2572 /*num_layers*/ 2, /*temporal_id*/ 0);
2573 const int kS0Tl1Bps =
2574 kS0Bps * webrtc::SimulcastRateAllocator::GetTemporalRateAllocation(
2575 /*num_layers*/ 2, /*temporal_id*/ 1);
2576 const int kS1Bps = kTargetBitrateBps - kS0Tl1Bps;
2577 // Temporal layers not supported by si:1.
2578 VideoBitrateAllocation expected_bitrate;
2579 expected_bitrate.SetBitrate(/*si*/ 0, /*ti*/ 0, kS0Tl0Bps);
2580 expected_bitrate.SetBitrate(/*si*/ 0, /*ti*/ 1, kS0Tl1Bps - kS0Tl0Bps);
2581 expected_bitrate.SetBitrate(/*si*/ 1, /*ti*/ 0, kS1Bps);
2582
2583 VerifyAllocatedBitrate(expected_bitrate);
2584 video_stream_encoder_->Stop();
2585}
2586
Niels Möller7dc26b72017-12-06 10:27:48 +01002587TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2588 const int kFrameWidth = 1280;
2589 const int kFrameHeight = 720;
2590 const int kFramerate = 24;
2591
Erik Språng4c6ca302019-04-08 15:14:01 +02002592 video_stream_encoder_->OnBitrateUpdated(
2593 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möller7dc26b72017-12-06 10:27:48 +01002594 test::FrameForwarder source;
2595 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002596 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002597
2598 // Insert a single frame, triggering initial configuration.
2599 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2600 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2601
2602 EXPECT_EQ(
2603 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2604 kDefaultFramerate);
2605
2606 // Trigger reconfigure encoder (without resetting the entire instance).
2607 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002608 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002609 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2610 video_encoder_config.number_of_streams = 1;
2611 video_encoder_config.video_stream_factory =
2612 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2613 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002614 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002615 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2616
2617 // Detector should be updated with fps limit from codec config.
2618 EXPECT_EQ(
2619 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2620 kFramerate);
2621
2622 // Trigger overuse, max framerate should be reduced.
2623 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2624 stats.input_frame_rate = kFramerate;
2625 stats_proxy_->SetMockStats(stats);
2626 video_stream_encoder_->TriggerCpuOveruse();
2627 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2628 int adapted_framerate =
2629 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2630 EXPECT_LT(adapted_framerate, kFramerate);
2631
2632 // Trigger underuse, max framerate should go back to codec configured fps.
2633 // Set extra low fps, to make sure it's actually reset, not just incremented.
2634 stats = stats_proxy_->GetStats();
2635 stats.input_frame_rate = adapted_framerate / 2;
2636 stats_proxy_->SetMockStats(stats);
2637 video_stream_encoder_->TriggerCpuNormalUsage();
2638 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2639 EXPECT_EQ(
2640 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2641 kFramerate);
2642
2643 video_stream_encoder_->Stop();
2644}
2645
2646TEST_F(VideoStreamEncoderTest,
2647 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2648 const int kFrameWidth = 1280;
2649 const int kFrameHeight = 720;
2650 const int kLowFramerate = 15;
2651 const int kHighFramerate = 25;
2652
Erik Språng4c6ca302019-04-08 15:14:01 +02002653 video_stream_encoder_->OnBitrateUpdated(
2654 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möller7dc26b72017-12-06 10:27:48 +01002655 test::FrameForwarder source;
2656 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002657 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002658
2659 // Trigger initial configuration.
2660 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002661 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002662 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2663 video_encoder_config.number_of_streams = 1;
2664 video_encoder_config.video_stream_factory =
2665 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2666 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2667 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002668 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002669 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2670
2671 EXPECT_EQ(
2672 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2673 kLowFramerate);
2674
2675 // Trigger overuse, max framerate should be reduced.
2676 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2677 stats.input_frame_rate = kLowFramerate;
2678 stats_proxy_->SetMockStats(stats);
2679 video_stream_encoder_->TriggerCpuOveruse();
2680 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2681 int adapted_framerate =
2682 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2683 EXPECT_LT(adapted_framerate, kLowFramerate);
2684
2685 // Reconfigure the encoder with a new (higher max framerate), max fps should
2686 // still respect the adaptation.
2687 video_encoder_config.video_stream_factory =
2688 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2689 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2690 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002691 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002692 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2693
2694 EXPECT_EQ(
2695 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2696 adapted_framerate);
2697
2698 // Trigger underuse, max framerate should go back to codec configured fps.
2699 stats = stats_proxy_->GetStats();
2700 stats.input_frame_rate = adapted_framerate;
2701 stats_proxy_->SetMockStats(stats);
2702 video_stream_encoder_->TriggerCpuNormalUsage();
2703 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2704 EXPECT_EQ(
2705 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2706 kHighFramerate);
2707
2708 video_stream_encoder_->Stop();
2709}
2710
mflodmancc3d4422017-08-03 08:27:51 -07002711TEST_F(VideoStreamEncoderTest,
2712 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002713 const int kFrameWidth = 1280;
2714 const int kFrameHeight = 720;
2715 const int kFramerate = 24;
2716
Erik Språng4c6ca302019-04-08 15:14:01 +02002717 video_stream_encoder_->OnBitrateUpdated(
2718 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002719 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002720 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002721 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangfda496a2017-06-15 04:21:07 -07002722
2723 // Trigger initial configuration.
2724 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002725 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002726 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2727 video_encoder_config.number_of_streams = 1;
2728 video_encoder_config.video_stream_factory =
2729 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2730 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002731 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002732 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002733 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002734
Niels Möller7dc26b72017-12-06 10:27:48 +01002735 EXPECT_EQ(
2736 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2737 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002738
2739 // Trigger overuse, max framerate should be reduced.
2740 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2741 stats.input_frame_rate = kFramerate;
2742 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002743 video_stream_encoder_->TriggerCpuOveruse();
2744 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002745 int adapted_framerate =
2746 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002747 EXPECT_LT(adapted_framerate, kFramerate);
2748
2749 // Change degradation preference to not enable framerate scaling. Target
2750 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002751 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002752 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -07002753 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002754 EXPECT_EQ(
2755 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2756 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002757
mflodmancc3d4422017-08-03 08:27:51 -07002758 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002759}
2760
mflodmancc3d4422017-08-03 08:27:51 -07002761TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002762 const int kTooLowBitrateForFrameSizeBps = 10000;
Erik Språng610c7632019-03-06 15:37:33 +01002763 video_stream_encoder_->OnBitrateUpdated(
Erik Språng4c6ca302019-04-08 15:14:01 +02002764 DataRate::bps(kTooLowBitrateForFrameSizeBps),
2765 DataRate::bps(kTooLowBitrateForFrameSizeBps), 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002766 const int kWidth = 640;
2767 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002768
asaperssonfab67072017-04-04 05:51:49 -07002769 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002770
2771 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002772 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002773
2774 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002775 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002776
sprangc5d62e22017-04-02 23:53:04 -07002777 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002778
asaperssonfab67072017-04-04 05:51:49 -07002779 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002780 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002781 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002782
2783 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002784 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002785
sprangc5d62e22017-04-02 23:53:04 -07002786 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002787
mflodmancc3d4422017-08-03 08:27:51 -07002788 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002789}
2790
mflodmancc3d4422017-08-03 08:27:51 -07002791TEST_F(VideoStreamEncoderTest,
2792 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002793 const int kTooLowBitrateForFrameSizeBps = 10000;
Erik Språng610c7632019-03-06 15:37:33 +01002794 video_stream_encoder_->OnBitrateUpdated(
Erik Språng4c6ca302019-04-08 15:14:01 +02002795 DataRate::bps(kTooLowBitrateForFrameSizeBps),
2796 DataRate::bps(kTooLowBitrateForFrameSizeBps), 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002797 const int kWidth = 640;
2798 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002799
2800 // We expect the n initial frames to get dropped.
2801 int i;
2802 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002803 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002804 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002805 }
2806 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002807 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002808 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002809
2810 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002811 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002812
mflodmancc3d4422017-08-03 08:27:51 -07002813 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002814}
2815
mflodmancc3d4422017-08-03 08:27:51 -07002816TEST_F(VideoStreamEncoderTest,
2817 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002818 const int kWidth = 640;
2819 const int kHeight = 360;
Erik Språng610c7632019-03-06 15:37:33 +01002820 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kLowTargetBitrateBps),
Erik Språng4c6ca302019-04-08 15:14:01 +02002821 DataRate::bps(kLowTargetBitrateBps),
2822 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002823
2824 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002825 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002826 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason2bc68642017-02-07 07:02:22 -08002827
asaperssonfab67072017-04-04 05:51:49 -07002828 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002829 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002830 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002831
mflodmancc3d4422017-08-03 08:27:51 -07002832 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002833}
2834
mflodmancc3d4422017-08-03 08:27:51 -07002835TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002836 const int kWidth = 640;
2837 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002838 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02002839
2840 VideoEncoderConfig video_encoder_config;
2841 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
2842 // Make format different, to force recreation of encoder.
2843 video_encoder_config.video_format.parameters["foo"] = "foo";
2844 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002845 kMaxPayloadLength);
Erik Språng610c7632019-03-06 15:37:33 +01002846 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kLowTargetBitrateBps),
Erik Språng4c6ca302019-04-08 15:14:01 +02002847 DataRate::bps(kLowTargetBitrateBps),
2848 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002849
kthelgasonb83797b2017-02-14 11:57:25 -08002850 // Force quality scaler reconfiguration by resetting the source.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002851 video_stream_encoder_->SetSource(&video_source_,
2852 webrtc::DegradationPreference::BALANCED);
kthelgasonad9010c2017-02-14 00:46:51 -08002853
asaperssonfab67072017-04-04 05:51:49 -07002854 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002855 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002856 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002857
mflodmancc3d4422017-08-03 08:27:51 -07002858 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002859 fake_encoder_.SetQualityScaling(true);
2860}
2861
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002862TEST_F(VideoStreamEncoderTest, InitialFrameDropActivatesWhenBWEstimateReady) {
2863 webrtc::test::ScopedFieldTrials field_trials(
2864 "WebRTC-InitialFramedrop/Enabled/");
2865 // Reset encoder for field trials to take effect.
2866 ConfigureEncoder(video_encoder_config_.Copy());
2867 const int kTooLowBitrateForFrameSizeBps = 10000;
2868 const int kWidth = 640;
2869 const int kHeight = 360;
2870
Erik Språng4c6ca302019-04-08 15:14:01 +02002871 video_stream_encoder_->OnBitrateUpdated(
2872 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002873 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2874 // Frame should not be dropped.
2875 WaitForEncodedFrame(1);
2876
Erik Språng610c7632019-03-06 15:37:33 +01002877 video_stream_encoder_->OnBitrateUpdated(
Erik Språng4c6ca302019-04-08 15:14:01 +02002878 DataRate::bps(kTooLowBitrateForFrameSizeBps),
2879 DataRate::bps(kTooLowBitrateForFrameSizeBps), 0, 0);
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002880 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
2881 // Expect to drop this frame, the wait should time out.
2882 ExpectDroppedFrame();
2883
2884 // Expect the sink_wants to specify a scaled frame.
2885 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
2886 video_stream_encoder_->Stop();
2887}
2888
mflodmancc3d4422017-08-03 08:27:51 -07002889TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002890 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2891 const int kTooSmallWidth = 10;
2892 const int kTooSmallHeight = 10;
Erik Språng4c6ca302019-04-08 15:14:01 +02002893 video_stream_encoder_->OnBitrateUpdated(
2894 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002895
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002896 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002897 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002898 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002899 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002900 VerifyNoLimitation(source.sink_wants());
2901 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2902
2903 // Trigger adapt down, too small frame, expect no change.
2904 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002905 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002906 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002907 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002908 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2909 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2910
mflodmancc3d4422017-08-03 08:27:51 -07002911 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002912}
2913
mflodmancc3d4422017-08-03 08:27:51 -07002914TEST_F(VideoStreamEncoderTest,
2915 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002916 const int kTooSmallWidth = 10;
2917 const int kTooSmallHeight = 10;
2918 const int kFpsLimit = 7;
Erik Språng4c6ca302019-04-08 15:14:01 +02002919 video_stream_encoder_->OnBitrateUpdated(
2920 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002921
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002922 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002923 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002924 video_stream_encoder_->SetSource(&source,
2925 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002926 VerifyNoLimitation(source.sink_wants());
2927 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2928 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2929
2930 // Trigger adapt down, expect limited framerate.
2931 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002932 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002933 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002934 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2935 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2936 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2937 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2938
2939 // Trigger adapt down, too small frame, expect no change.
2940 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002941 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002942 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002943 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2944 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2945 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2946 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2947
mflodmancc3d4422017-08-03 08:27:51 -07002948 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002949}
2950
mflodmancc3d4422017-08-03 08:27:51 -07002951TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002952 fake_encoder_.ForceInitEncodeFailure(true);
Erik Språng4c6ca302019-04-08 15:14:01 +02002953 video_stream_encoder_->OnBitrateUpdated(
2954 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möllerf1338562018-04-26 09:51:47 +02002955 ResetEncoder("VP8", 2, 1, 1, false);
asapersson02465b82017-04-10 01:12:52 -07002956 const int kFrameWidth = 1280;
2957 const int kFrameHeight = 720;
2958 video_source_.IncomingCapturedFrame(
2959 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002960 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002961 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002962}
2963
sprangb1ca0732017-02-01 08:38:12 -08002964// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002965TEST_F(VideoStreamEncoderTest,
2966 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
Erik Språng4c6ca302019-04-08 15:14:01 +02002967 video_stream_encoder_->OnBitrateUpdated(
2968 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002969
2970 const int kFrameWidth = 1280;
2971 const int kFrameHeight = 720;
2972 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002973 // requested by
2974 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002975 video_source_.set_adaptation_enabled(true);
2976
2977 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002978 CreateFrame(1 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002979 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002980
2981 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002982 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002983 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002984 CreateFrame(2 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002985 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002986
asaperssonfab67072017-04-04 05:51:49 -07002987 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002988 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002989 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002990 CreateFrame(3 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002991 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002992
mflodmancc3d4422017-08-03 08:27:51 -07002993 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002994}
sprangfe627f32017-03-29 08:24:59 -07002995
mflodmancc3d4422017-08-03 08:27:51 -07002996TEST_F(VideoStreamEncoderTest,
2997 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002998 const int kFrameWidth = 1280;
2999 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07003000
Erik Språng4c6ca302019-04-08 15:14:01 +02003001 video_stream_encoder_->OnBitrateUpdated(
3002 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -07003003 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003004 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07003005 video_source_.set_adaptation_enabled(true);
3006
sprang4847ae62017-06-27 07:06:52 -07003007 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07003008
3009 video_source_.IncomingCapturedFrame(
3010 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003011 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07003012
3013 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07003014 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07003015
3016 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07003017 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07003018 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07003019 video_source_.IncomingCapturedFrame(
3020 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003021 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07003022 }
3023
3024 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07003025 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07003026 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07003027 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07003028 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07003029 video_source_.IncomingCapturedFrame(
3030 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003031 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07003032 ++num_frames_dropped;
3033 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01003034 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07003035 }
3036 }
3037
sprang4847ae62017-06-27 07:06:52 -07003038 // Add some slack to account for frames dropped by the frame dropper.
3039 const int kErrorMargin = 1;
3040 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07003041 kErrorMargin);
3042
3043 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07003044 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07003045 num_frames_dropped = 0;
Åsa Persson8c1bf952018-09-13 10:42:19 +02003046 for (int i = 0; i <= max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07003047 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07003048 video_source_.IncomingCapturedFrame(
3049 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003050 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07003051 ++num_frames_dropped;
3052 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01003053 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07003054 }
3055 }
sprang4847ae62017-06-27 07:06:52 -07003056 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07003057 kErrorMargin);
3058
3059 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07003060 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07003061 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07003062 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07003063 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07003064 video_source_.IncomingCapturedFrame(
3065 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003066 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07003067 ++num_frames_dropped;
3068 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01003069 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07003070 }
3071 }
sprang4847ae62017-06-27 07:06:52 -07003072 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07003073 kErrorMargin);
3074
3075 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07003076 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07003077 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07003078 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07003079 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07003080 video_source_.IncomingCapturedFrame(
3081 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003082 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07003083 ++num_frames_dropped;
3084 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01003085 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07003086 }
3087 }
3088 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
3089
mflodmancc3d4422017-08-03 08:27:51 -07003090 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07003091}
3092
mflodmancc3d4422017-08-03 08:27:51 -07003093TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07003094 const int kFramerateFps = 5;
3095 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07003096 const int kFrameWidth = 1280;
3097 const int kFrameHeight = 720;
3098
sprang4847ae62017-06-27 07:06:52 -07003099 // Reconfigure encoder with two temporal layers and screensharing, which will
3100 // disable frame dropping and make testing easier.
Niels Möllerf1338562018-04-26 09:51:47 +02003101 ResetEncoder("VP8", 1, 2, 1, true);
sprang4847ae62017-06-27 07:06:52 -07003102
Erik Språng4c6ca302019-04-08 15:14:01 +02003103 video_stream_encoder_->OnBitrateUpdated(
3104 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -07003105 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003106 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07003107 video_source_.set_adaptation_enabled(true);
3108
sprang4847ae62017-06-27 07:06:52 -07003109 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07003110
3111 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08003112 rtc::VideoSinkWants last_wants;
3113 do {
3114 last_wants = video_source_.sink_wants();
3115
sprangc5d62e22017-04-02 23:53:04 -07003116 // Insert frames to get a new fps estimate...
3117 for (int j = 0; j < kFramerateFps; ++j) {
3118 video_source_.IncomingCapturedFrame(
3119 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08003120 if (video_source_.last_sent_width()) {
3121 sink_.WaitForEncodedFrame(timestamp_ms);
3122 }
sprangc5d62e22017-04-02 23:53:04 -07003123 timestamp_ms += kFrameIntervalMs;
Sebastian Jansson40889f32019-04-17 12:11:20 +02003124 fake_clock_.AdvanceTime(TimeDelta::ms(kFrameIntervalMs));
sprangc5d62e22017-04-02 23:53:04 -07003125 }
3126 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07003127 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08003128 } while (video_source_.sink_wants().max_framerate_fps <
3129 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07003130
Jonathan Yubc771b72017-12-08 17:04:29 -08003131 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07003132
mflodmancc3d4422017-08-03 08:27:51 -07003133 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07003134}
asaperssonf7e294d2017-06-13 23:25:22 -07003135
mflodmancc3d4422017-08-03 08:27:51 -07003136TEST_F(VideoStreamEncoderTest,
3137 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07003138 const int kWidth = 1280;
3139 const int kHeight = 720;
3140 const int64_t kFrameIntervalMs = 150;
3141 int64_t timestamp_ms = kFrameIntervalMs;
Erik Språng4c6ca302019-04-08 15:14:01 +02003142 video_stream_encoder_->OnBitrateUpdated(
3143 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07003144
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003145 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07003146 AdaptingFrameForwarder source;
3147 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003148 video_stream_encoder_->SetSource(&source,
3149 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07003150 timestamp_ms += kFrameIntervalMs;
3151 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003152 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003153 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003154 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3155 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3156 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3157
3158 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003159 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003160 timestamp_ms += kFrameIntervalMs;
3161 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003162 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003163 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
3164 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3165 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3166 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3167
3168 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003169 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003170 timestamp_ms += kFrameIntervalMs;
3171 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003172 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003173 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
3174 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3175 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3176 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3177
3178 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003179 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003180 timestamp_ms += kFrameIntervalMs;
3181 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003182 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003183 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
3184 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3185 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3186 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3187
3188 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003189 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003190 timestamp_ms += kFrameIntervalMs;
3191 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003192 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003193 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
3194 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3195 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3196 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3197
3198 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07003199 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003200 timestamp_ms += kFrameIntervalMs;
3201 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003202 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003203 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
3204 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3205 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3206 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3207
3208 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07003209 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003210 timestamp_ms += kFrameIntervalMs;
3211 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003212 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003213 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
3214 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3215 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3216 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3217
3218 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07003219 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003220 timestamp_ms += kFrameIntervalMs;
3221 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003222 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003223 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
3224 rtc::VideoSinkWants last_wants = source.sink_wants();
3225 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3226 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3227 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3228
3229 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003230 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003231 timestamp_ms += kFrameIntervalMs;
3232 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003233 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003234 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
3235 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3236 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3237 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3238
3239 // Trigger adapt down, expect expect increased fps (320x180@10fps).
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);
asaperssonf7e294d2017-06-13 23:25:22 -07003244 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
3245 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3246 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3247 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3248
3249 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07003250 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003251 timestamp_ms += kFrameIntervalMs;
3252 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003253 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003254 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3255 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3256 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3257 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3258
3259 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003260 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003261 timestamp_ms += kFrameIntervalMs;
3262 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003263 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003264 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
3265 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3266 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3267 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3268
3269 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003270 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003271 timestamp_ms += kFrameIntervalMs;
3272 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003273 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003274 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3275 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3276 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3277 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3278
3279 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003280 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003281 timestamp_ms += kFrameIntervalMs;
3282 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003283 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003284 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
3285 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3286 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3287 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3288
3289 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003290 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003291 timestamp_ms += kFrameIntervalMs;
3292 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003293 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003294 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3295 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3296 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3297 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3298
3299 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003300 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003301 timestamp_ms += kFrameIntervalMs;
3302 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003303 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003304 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02003305 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003306 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3307 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3308 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3309
3310 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003311 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003312 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003313 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3314
mflodmancc3d4422017-08-03 08:27:51 -07003315 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003316}
3317
mflodmancc3d4422017-08-03 08:27:51 -07003318TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07003319 const int kWidth = 1280;
3320 const int kHeight = 720;
3321 const int64_t kFrameIntervalMs = 150;
3322 int64_t timestamp_ms = kFrameIntervalMs;
Erik Språng4c6ca302019-04-08 15:14:01 +02003323 video_stream_encoder_->OnBitrateUpdated(
3324 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07003325
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003326 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07003327 AdaptingFrameForwarder source;
3328 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003329 video_stream_encoder_->SetSource(&source,
3330 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07003331 timestamp_ms += kFrameIntervalMs;
3332 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003333 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003334 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003335 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3336 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3337 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3338 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3339 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3340 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3341
3342 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003343 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003344 timestamp_ms += kFrameIntervalMs;
3345 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003346 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003347 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
3348 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3349 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3350 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3351 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3352 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3353 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3354
3355 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003356 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003357 timestamp_ms += kFrameIntervalMs;
3358 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003359 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003360 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
3361 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3362 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3363 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3364 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3365 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3366 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3367
3368 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003369 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003370 timestamp_ms += kFrameIntervalMs;
3371 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003372 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003373 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
3374 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3375 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3376 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3377 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3378 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3379 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3380
3381 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003382 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003383 timestamp_ms += kFrameIntervalMs;
3384 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003385 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003386 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
3387 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3388 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3389 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3390 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3391 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3392 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3393
3394 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003395 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003396 timestamp_ms += kFrameIntervalMs;
3397 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003398 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003399 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3400 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3401 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3402 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3403 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3404 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3405 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3406
3407 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003408 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003409 timestamp_ms += kFrameIntervalMs;
3410 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003411 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003412 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02003413 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003414 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3415 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3416 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3417 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3418 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3419 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3420
3421 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003422 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003423 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003424 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3425 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3426
mflodmancc3d4422017-08-03 08:27:51 -07003427 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003428}
3429
mflodmancc3d4422017-08-03 08:27:51 -07003430TEST_F(VideoStreamEncoderTest,
3431 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07003432 const int kWidth = 640;
3433 const int kHeight = 360;
3434 const int kFpsLimit = 15;
3435 const int64_t kFrameIntervalMs = 150;
3436 int64_t timestamp_ms = kFrameIntervalMs;
Erik Språng4c6ca302019-04-08 15:14:01 +02003437 video_stream_encoder_->OnBitrateUpdated(
3438 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07003439
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003440 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07003441 AdaptingFrameForwarder source;
3442 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003443 video_stream_encoder_->SetSource(&source,
3444 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07003445 timestamp_ms += kFrameIntervalMs;
3446 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003447 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003448 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003449 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3450 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3451 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3452 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3453 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3454 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3455
3456 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003457 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003458 timestamp_ms += kFrameIntervalMs;
3459 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003460 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003461 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
3462 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3463 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3464 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3465 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3466 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3467 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3468
3469 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003470 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003471 timestamp_ms += kFrameIntervalMs;
3472 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003473 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003474 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
3475 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3476 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3477 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3478 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3479 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3480 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3481
3482 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003483 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003484 timestamp_ms += kFrameIntervalMs;
3485 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003486 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003487 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3488 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3489 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3490 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3491 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3492 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3493 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3494
3495 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003496 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003497 timestamp_ms += kFrameIntervalMs;
3498 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003499 WaitForEncodedFrame(timestamp_ms);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003500 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003501 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3502 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3503 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3504 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3505 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3506 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3507
3508 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003509 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003510 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003511 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3512 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3513
mflodmancc3d4422017-08-03 08:27:51 -07003514 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003515}
3516
mflodmancc3d4422017-08-03 08:27:51 -07003517TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003518 const int kFrameWidth = 1920;
3519 const int kFrameHeight = 1080;
3520 // 3/4 of 1920.
3521 const int kAdaptedFrameWidth = 1440;
3522 // 3/4 of 1080 rounded down to multiple of 4.
3523 const int kAdaptedFrameHeight = 808;
3524 const int kFramerate = 24;
3525
Erik Språng4c6ca302019-04-08 15:14:01 +02003526 video_stream_encoder_->OnBitrateUpdated(
3527 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003528 // Trigger reconfigure encoder (without resetting the entire instance).
3529 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02003530 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07003531 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3532 video_encoder_config.number_of_streams = 1;
3533 video_encoder_config.video_stream_factory =
3534 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003535 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02003536 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07003537 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003538
3539 video_source_.set_adaptation_enabled(true);
3540
3541 video_source_.IncomingCapturedFrame(
3542 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003543 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003544
3545 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003546 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003547 video_source_.IncomingCapturedFrame(
3548 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003549 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003550
mflodmancc3d4422017-08-03 08:27:51 -07003551 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003552}
3553
mflodmancc3d4422017-08-03 08:27:51 -07003554TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003555 const int kFrameWidth = 1280;
3556 const int kFrameHeight = 720;
3557 const int kLowFps = 2;
3558 const int kHighFps = 30;
3559
Erik Språng4c6ca302019-04-08 15:14:01 +02003560 video_stream_encoder_->OnBitrateUpdated(
3561 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003562
3563 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3564 max_framerate_ = kLowFps;
3565
3566 // Insert 2 seconds of 2fps video.
3567 for (int i = 0; i < kLowFps * 2; ++i) {
3568 video_source_.IncomingCapturedFrame(
3569 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3570 WaitForEncodedFrame(timestamp_ms);
3571 timestamp_ms += 1000 / kLowFps;
3572 }
3573
3574 // Make sure encoder is updated with new target.
Erik Språng4c6ca302019-04-08 15:14:01 +02003575 video_stream_encoder_->OnBitrateUpdated(
3576 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003577 video_source_.IncomingCapturedFrame(
3578 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3579 WaitForEncodedFrame(timestamp_ms);
3580 timestamp_ms += 1000 / kLowFps;
3581
3582 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3583
3584 // Insert 30fps frames for just a little more than the forced update period.
3585 const int kVcmTimerIntervalFrames =
3586 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3587 const int kFrameIntervalMs = 1000 / kHighFps;
3588 max_framerate_ = kHighFps;
3589 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3590 video_source_.IncomingCapturedFrame(
3591 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3592 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3593 // be dropped if the encoder hans't been updated with the new higher target
3594 // framerate yet, causing it to overshoot the target bitrate and then
3595 // suffering the wrath of the media optimizer.
3596 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3597 timestamp_ms += kFrameIntervalMs;
3598 }
3599
3600 // Don expect correct measurement just yet, but it should be higher than
3601 // before.
3602 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3603
mflodmancc3d4422017-08-03 08:27:51 -07003604 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003605}
3606
mflodmancc3d4422017-08-03 08:27:51 -07003607TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003608 const int kFrameWidth = 1280;
3609 const int kFrameHeight = 720;
3610 const int kTargetBitrateBps = 1000000;
3611
3612 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02003613 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
Erik Språng4c6ca302019-04-08 15:14:01 +02003614 video_stream_encoder_->OnBitrateUpdated(
3615 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -07003616 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003617
3618 // Insert a first video frame, causes another bitrate update.
3619 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3620 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3621 video_source_.IncomingCapturedFrame(
3622 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3623 WaitForEncodedFrame(timestamp_ms);
3624
3625 // Next, simulate video suspension due to pacer queue overrun.
Erik Språng4c6ca302019-04-08 15:14:01 +02003626 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(0), DataRate::bps(0), 0,
Erik Språng610c7632019-03-06 15:37:33 +01003627 1);
sprang4847ae62017-06-27 07:06:52 -07003628
3629 // Skip ahead until a new periodic parameter update should have occured.
3630 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
Sebastian Jansson40889f32019-04-17 12:11:20 +02003631 fake_clock_.AdvanceTime(
3632 TimeDelta::ms(vcm::VCMProcessTimer::kDefaultProcessIntervalMs));
sprang4847ae62017-06-27 07:06:52 -07003633
3634 // Bitrate observer should not be called.
3635 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3636 video_source_.IncomingCapturedFrame(
3637 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3638 ExpectDroppedFrame();
3639
mflodmancc3d4422017-08-03 08:27:51 -07003640 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003641}
ilnik6b826ef2017-06-16 06:53:48 -07003642
Niels Möller4db138e2018-04-19 09:04:13 +02003643TEST_F(VideoStreamEncoderTest,
3644 DefaultCpuAdaptationThresholdsForSoftwareEncoder) {
3645 const int kFrameWidth = 1280;
3646 const int kFrameHeight = 720;
3647 const CpuOveruseOptions default_options;
Erik Språng4c6ca302019-04-08 15:14:01 +02003648 video_stream_encoder_->OnBitrateUpdated(
3649 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möller4db138e2018-04-19 09:04:13 +02003650 video_source_.IncomingCapturedFrame(
3651 CreateFrame(1, kFrameWidth, kFrameHeight));
3652 WaitForEncodedFrame(1);
3653 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3654 .low_encode_usage_threshold_percent,
3655 default_options.low_encode_usage_threshold_percent);
3656 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3657 .high_encode_usage_threshold_percent,
3658 default_options.high_encode_usage_threshold_percent);
3659 video_stream_encoder_->Stop();
3660}
3661
3662TEST_F(VideoStreamEncoderTest,
3663 HigherCpuAdaptationThresholdsForHardwareEncoder) {
3664 const int kFrameWidth = 1280;
3665 const int kFrameHeight = 720;
3666 CpuOveruseOptions hardware_options;
3667 hardware_options.low_encode_usage_threshold_percent = 150;
3668 hardware_options.high_encode_usage_threshold_percent = 200;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +01003669 fake_encoder_.SetIsHardwareAccelerated(true);
Niels Möller4db138e2018-04-19 09:04:13 +02003670
Erik Språng4c6ca302019-04-08 15:14:01 +02003671 video_stream_encoder_->OnBitrateUpdated(
3672 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möller4db138e2018-04-19 09:04:13 +02003673 video_source_.IncomingCapturedFrame(
3674 CreateFrame(1, kFrameWidth, kFrameHeight));
3675 WaitForEncodedFrame(1);
3676 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3677 .low_encode_usage_threshold_percent,
3678 hardware_options.low_encode_usage_threshold_percent);
3679 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3680 .high_encode_usage_threshold_percent,
3681 hardware_options.high_encode_usage_threshold_percent);
3682 video_stream_encoder_->Stop();
3683}
3684
Niels Möller6bb5ab92019-01-11 11:11:10 +01003685TEST_F(VideoStreamEncoderTest, DropsFramesWhenEncoderOvershoots) {
3686 const int kFrameWidth = 320;
3687 const int kFrameHeight = 240;
3688 const int kFps = 30;
3689 const int kTargetBitrateBps = 120000;
3690 const int kNumFramesInRun = kFps * 5; // Runs of five seconds.
3691
Erik Språng4c6ca302019-04-08 15:14:01 +02003692 video_stream_encoder_->OnBitrateUpdated(
3693 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003694
3695 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3696 max_framerate_ = kFps;
3697
3698 // Insert 3 seconds of video, verify number of drops with normal bitrate.
3699 fake_encoder_.SimulateOvershoot(1.0);
3700 int num_dropped = 0;
3701 for (int i = 0; i < kNumFramesInRun; ++i) {
3702 video_source_.IncomingCapturedFrame(
3703 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3704 // Wait up to two frame durations for a frame to arrive.
3705 if (!TimedWaitForEncodedFrame(timestamp_ms, 2 * 1000 / kFps)) {
3706 ++num_dropped;
3707 }
3708 timestamp_ms += 1000 / kFps;
3709 }
3710
Erik Språnga8d48ab2019-02-08 14:17:40 +01003711 // Framerate should be measured to be near the expected target rate.
3712 EXPECT_NEAR(fake_encoder_.GetLastFramerate(), kFps, 1);
3713
3714 // Frame drops should be within 5% of expected 0%.
3715 EXPECT_NEAR(num_dropped, 0, 5 * kNumFramesInRun / 100);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003716
3717 // Make encoder produce frames at double the expected bitrate during 3 seconds
3718 // of video, verify number of drops. Rate needs to be slightly changed in
3719 // order to force the rate to be reconfigured.
Erik Språng7ca375c2019-02-06 16:20:17 +01003720 double overshoot_factor = 2.0;
3721 if (RateControlSettings::ParseFromFieldTrials().UseEncoderBitrateAdjuster()) {
3722 // With bitrate adjuster, when need to overshoot even more to trigger
3723 // frame dropping.
3724 overshoot_factor *= 2;
3725 }
3726 fake_encoder_.SimulateOvershoot(overshoot_factor);
Erik Språng610c7632019-03-06 15:37:33 +01003727 video_stream_encoder_->OnBitrateUpdated(
Erik Språng4c6ca302019-04-08 15:14:01 +02003728 DataRate::bps(kTargetBitrateBps + 1000),
3729 DataRate::bps(kTargetBitrateBps + 1000), 0, 0);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003730 num_dropped = 0;
3731 for (int i = 0; i < kNumFramesInRun; ++i) {
3732 video_source_.IncomingCapturedFrame(
3733 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3734 // Wait up to two frame durations for a frame to arrive.
3735 if (!TimedWaitForEncodedFrame(timestamp_ms, 2 * 1000 / kFps)) {
3736 ++num_dropped;
3737 }
3738 timestamp_ms += 1000 / kFps;
3739 }
3740
Erik Språng4c6ca302019-04-08 15:14:01 +02003741 video_stream_encoder_->OnBitrateUpdated(
3742 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Erik Språnga8d48ab2019-02-08 14:17:40 +01003743
3744 // Target framerate should be still be near the expected target, despite
3745 // the frame drops.
3746 EXPECT_NEAR(fake_encoder_.GetLastFramerate(), kFps, 1);
3747
3748 // Frame drops should be within 5% of expected 50%.
3749 EXPECT_NEAR(num_dropped, kNumFramesInRun / 2, 5 * kNumFramesInRun / 100);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003750
3751 video_stream_encoder_->Stop();
3752}
3753
3754TEST_F(VideoStreamEncoderTest, ConfiguresCorrectFrameRate) {
3755 const int kFrameWidth = 320;
3756 const int kFrameHeight = 240;
3757 const int kActualInputFps = 24;
3758 const int kTargetBitrateBps = 120000;
3759
3760 ASSERT_GT(max_framerate_, kActualInputFps);
3761
3762 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3763 max_framerate_ = kActualInputFps;
Erik Språng4c6ca302019-04-08 15:14:01 +02003764 video_stream_encoder_->OnBitrateUpdated(
3765 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003766
3767 // Insert 3 seconds of video, with an input fps lower than configured max.
3768 for (int i = 0; i < kActualInputFps * 3; ++i) {
3769 video_source_.IncomingCapturedFrame(
3770 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3771 // Wait up to two frame durations for a frame to arrive.
3772 WaitForEncodedFrame(timestamp_ms);
3773 timestamp_ms += 1000 / kActualInputFps;
3774 }
3775
3776 EXPECT_NEAR(kActualInputFps, fake_encoder_.GetLastFramerate(), 1);
3777
3778 video_stream_encoder_->Stop();
3779}
3780
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01003781TEST_F(VideoStreamEncoderTest, AccumulatesUpdateRectOnDroppedFrames) {
3782 VideoFrame::UpdateRect rect;
Erik Språng4c6ca302019-04-08 15:14:01 +02003783 video_stream_encoder_->OnBitrateUpdated(
3784 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01003785
3786 fake_encoder_.BlockNextEncode();
3787 video_source_.IncomingCapturedFrame(
3788 CreateFrameWithUpdatedPixel(1, nullptr, 0));
3789 WaitForEncodedFrame(1);
3790 // On the very first frame full update should be forced.
3791 rect = fake_encoder_.GetLastUpdateRect();
3792 EXPECT_EQ(rect.offset_x, 0);
3793 EXPECT_EQ(rect.offset_y, 0);
3794 EXPECT_EQ(rect.height, codec_height_);
3795 EXPECT_EQ(rect.width, codec_width_);
3796 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
3797 // call to ContinueEncode.
3798 video_source_.IncomingCapturedFrame(
3799 CreateFrameWithUpdatedPixel(2, nullptr, 1));
3800 ExpectDroppedFrame();
3801 video_source_.IncomingCapturedFrame(
3802 CreateFrameWithUpdatedPixel(3, nullptr, 10));
3803 ExpectDroppedFrame();
3804 fake_encoder_.ContinueEncode();
3805 WaitForEncodedFrame(3);
3806 // Updates to pixels 1 and 10 should be accumulated to one 10x1 rect.
3807 rect = fake_encoder_.GetLastUpdateRect();
3808 EXPECT_EQ(rect.offset_x, 1);
3809 EXPECT_EQ(rect.offset_y, 0);
3810 EXPECT_EQ(rect.width, 10);
3811 EXPECT_EQ(rect.height, 1);
3812
3813 video_source_.IncomingCapturedFrame(
3814 CreateFrameWithUpdatedPixel(4, nullptr, 0));
3815 WaitForEncodedFrame(4);
3816 // Previous frame was encoded, so no accumulation should happen.
3817 rect = fake_encoder_.GetLastUpdateRect();
3818 EXPECT_EQ(rect.offset_x, 0);
3819 EXPECT_EQ(rect.offset_y, 0);
3820 EXPECT_EQ(rect.width, 1);
3821 EXPECT_EQ(rect.height, 1);
3822
3823 video_stream_encoder_->Stop();
3824}
3825
Erik Språngd7329ca2019-02-21 21:19:53 +01003826TEST_F(VideoStreamEncoderTest, SetsFrameTypes) {
Erik Språng4c6ca302019-04-08 15:14:01 +02003827 video_stream_encoder_->OnBitrateUpdated(
3828 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Erik Språngd7329ca2019-02-21 21:19:53 +01003829
3830 // First frame is always keyframe.
3831 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
3832 WaitForEncodedFrame(1);
Niels Möller8f7ce222019-03-21 15:43:58 +01003833 EXPECT_THAT(
3834 fake_encoder_.LastFrameTypes(),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02003835 ::testing::ElementsAre(VideoFrameType{VideoFrameType::kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003836
3837 // Insert delta frame.
3838 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
3839 WaitForEncodedFrame(2);
Niels Möller8f7ce222019-03-21 15:43:58 +01003840 EXPECT_THAT(
3841 fake_encoder_.LastFrameTypes(),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02003842 ::testing::ElementsAre(VideoFrameType{VideoFrameType::kVideoFrameDelta}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003843
3844 // Request next frame be a key-frame.
3845 video_stream_encoder_->SendKeyFrame();
3846 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
3847 WaitForEncodedFrame(3);
Niels Möller8f7ce222019-03-21 15:43:58 +01003848 EXPECT_THAT(
3849 fake_encoder_.LastFrameTypes(),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02003850 ::testing::ElementsAre(VideoFrameType{VideoFrameType::kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003851
3852 video_stream_encoder_->Stop();
3853}
3854
3855TEST_F(VideoStreamEncoderTest, SetsFrameTypesSimulcast) {
3856 // Setup simulcast with three streams.
3857 ResetEncoder("VP8", 3, 1, 1, false);
Erik Språng610c7632019-03-06 15:37:33 +01003858 video_stream_encoder_->OnBitrateUpdated(
Erik Språng4c6ca302019-04-08 15:14:01 +02003859 DataRate::bps(kSimulcastTargetBitrateBps),
3860 DataRate::bps(kSimulcastTargetBitrateBps), 0, 0);
Erik Språngd7329ca2019-02-21 21:19:53 +01003861 // Wait for all three layers before triggering event.
3862 sink_.SetNumExpectedLayers(3);
3863
3864 // First frame is always keyframe.
3865 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
3866 WaitForEncodedFrame(1);
3867 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02003868 ::testing::ElementsAreArray({VideoFrameType::kVideoFrameKey,
3869 VideoFrameType::kVideoFrameKey,
3870 VideoFrameType::kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003871
3872 // Insert delta frame.
3873 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
3874 WaitForEncodedFrame(2);
3875 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02003876 ::testing::ElementsAreArray({VideoFrameType::kVideoFrameDelta,
3877 VideoFrameType::kVideoFrameDelta,
3878 VideoFrameType::kVideoFrameDelta}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003879
3880 // Request next frame be a key-frame.
3881 // Only first stream is configured to produce key-frame.
3882 video_stream_encoder_->SendKeyFrame();
3883 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
3884 WaitForEncodedFrame(3);
Sergey Silkine62a08a2019-05-13 13:45:39 +02003885
3886 // TODO(webrtc:10615): Map keyframe request to spatial layer. Currently
3887 // keyframe request on any layer triggers keyframe on all layers.
Erik Språngd7329ca2019-02-21 21:19:53 +01003888 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02003889 ::testing::ElementsAreArray({VideoFrameType::kVideoFrameKey,
Sergey Silkine62a08a2019-05-13 13:45:39 +02003890 VideoFrameType::kVideoFrameKey,
3891 VideoFrameType::kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003892
3893 video_stream_encoder_->Stop();
3894}
3895
3896TEST_F(VideoStreamEncoderTest, RequestKeyframeInternalSource) {
3897 // Configure internal source factory and setup test again.
3898 encoder_factory_.SetHasInternalSource(true);
3899 ResetEncoder("VP8", 1, 1, 1, false);
Erik Språng4c6ca302019-04-08 15:14:01 +02003900 video_stream_encoder_->OnBitrateUpdated(
3901 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Erik Språngd7329ca2019-02-21 21:19:53 +01003902
3903 // Call encoder directly, simulating internal source where encoded frame
3904 // callback in VideoStreamEncoder is called despite no OnFrame().
3905 fake_encoder_.InjectFrame(CreateFrame(1, nullptr), true);
3906 EXPECT_TRUE(WaitForFrame(kDefaultTimeoutMs));
Niels Möller8f7ce222019-03-21 15:43:58 +01003907 EXPECT_THAT(
3908 fake_encoder_.LastFrameTypes(),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02003909 ::testing::ElementsAre(VideoFrameType{VideoFrameType::kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003910
Niels Möller8f7ce222019-03-21 15:43:58 +01003911 const std::vector<VideoFrameType> kDeltaFrame = {
3912 VideoFrameType::kVideoFrameDelta};
Erik Språngd7329ca2019-02-21 21:19:53 +01003913 // Need to set timestamp manually since manually for injected frame.
3914 VideoFrame frame = CreateFrame(101, nullptr);
3915 frame.set_timestamp(101);
3916 fake_encoder_.InjectFrame(frame, false);
3917 EXPECT_TRUE(WaitForFrame(kDefaultTimeoutMs));
Niels Möller8f7ce222019-03-21 15:43:58 +01003918 EXPECT_THAT(
3919 fake_encoder_.LastFrameTypes(),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02003920 ::testing::ElementsAre(VideoFrameType{VideoFrameType::kVideoFrameDelta}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003921
3922 // Request key-frame. The forces a dummy frame down into the encoder.
3923 fake_encoder_.ExpectNullFrame();
3924 video_stream_encoder_->SendKeyFrame();
3925 EXPECT_TRUE(WaitForFrame(kDefaultTimeoutMs));
Niels Möller8f7ce222019-03-21 15:43:58 +01003926 EXPECT_THAT(
3927 fake_encoder_.LastFrameTypes(),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02003928 ::testing::ElementsAre(VideoFrameType{VideoFrameType::kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003929
3930 video_stream_encoder_->Stop();
3931}
Erik Språngb7cb7b52019-02-26 15:52:33 +01003932
3933TEST_F(VideoStreamEncoderTest, AdjustsTimestampInternalSource) {
3934 // Configure internal source factory and setup test again.
3935 encoder_factory_.SetHasInternalSource(true);
3936 ResetEncoder("VP8", 1, 1, 1, false);
Erik Språng4c6ca302019-04-08 15:14:01 +02003937 video_stream_encoder_->OnBitrateUpdated(
3938 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Erik Språngb7cb7b52019-02-26 15:52:33 +01003939
3940 int64_t timestamp = 1;
3941 EncodedImage image;
Niels Möller4d504c72019-06-18 15:56:56 +02003942 image.SetEncodedData(
3943 EncodedImageBuffer::Create(kTargetBitrateBps / kDefaultFramerate / 8));
Erik Språngb7cb7b52019-02-26 15:52:33 +01003944 image.capture_time_ms_ = ++timestamp;
3945 image.SetTimestamp(static_cast<uint32_t>(timestamp * 90));
3946 const int64_t kEncodeFinishDelayMs = 10;
3947 image.timing_.encode_start_ms = timestamp;
3948 image.timing_.encode_finish_ms = timestamp + kEncodeFinishDelayMs;
3949 fake_encoder_.InjectEncodedImage(image);
3950 // Wait for frame without incrementing clock.
3951 EXPECT_TRUE(sink_.WaitForFrame(kDefaultTimeoutMs));
3952 // Frame is captured kEncodeFinishDelayMs before it's encoded, so restored
3953 // capture timestamp should be kEncodeFinishDelayMs in the past.
3954 EXPECT_EQ(sink_.GetLastCaptureTimeMs(),
3955 fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec -
3956 kEncodeFinishDelayMs);
3957
3958 video_stream_encoder_->Stop();
3959}
Mirta Dvornicic28f0eb22019-05-28 16:30:16 +02003960
3961TEST_F(VideoStreamEncoderTest, DoesNotRewriteH264BitstreamWithOptimalSps) {
3962 // Configure internal source factory and setup test again.
3963 encoder_factory_.SetHasInternalSource(true);
3964 ResetEncoder("H264", 1, 1, 1, false);
3965
3966 EncodedImage image(optimal_sps, sizeof(optimal_sps), sizeof(optimal_sps));
3967 image._frameType = VideoFrameType::kVideoFrameKey;
3968
3969 CodecSpecificInfo codec_specific_info;
3970 codec_specific_info.codecType = kVideoCodecH264;
3971
3972 RTPFragmentationHeader fragmentation;
3973 fragmentation.VerifyAndAllocateFragmentationHeader(1);
3974 fragmentation.fragmentationOffset[0] = 4;
3975 fragmentation.fragmentationLength[0] = sizeof(optimal_sps) - 4;
3976
3977 fake_encoder_.InjectEncodedImage(image, &codec_specific_info, &fragmentation);
3978 EXPECT_TRUE(sink_.WaitForFrame(kDefaultTimeoutMs));
3979
3980 EXPECT_THAT(sink_.GetLastEncodedImageData(),
3981 testing::ElementsAreArray(optimal_sps));
3982 RTPFragmentationHeader last_fragmentation = sink_.GetLastFragmentation();
3983 ASSERT_THAT(last_fragmentation.fragmentationVectorSize, 1U);
3984 EXPECT_EQ(last_fragmentation.fragmentationOffset[0], 4U);
3985 EXPECT_EQ(last_fragmentation.fragmentationLength[0], sizeof(optimal_sps) - 4);
3986
3987 video_stream_encoder_->Stop();
3988}
3989
3990TEST_F(VideoStreamEncoderTest, RewritesH264BitstreamWithNonOptimalSps) {
3991 uint8_t original_sps[] = {0, 0, 0, 1, H264::NaluType::kSps,
3992 0x00, 0x00, 0x03, 0x03, 0xF4,
3993 0x05, 0x03, 0xC7, 0xC0};
3994
3995 // Configure internal source factory and setup test again.
3996 encoder_factory_.SetHasInternalSource(true);
3997 ResetEncoder("H264", 1, 1, 1, false);
3998
3999 EncodedImage image(original_sps, sizeof(original_sps), sizeof(original_sps));
4000 image._frameType = VideoFrameType::kVideoFrameKey;
4001
4002 CodecSpecificInfo codec_specific_info;
4003 codec_specific_info.codecType = kVideoCodecH264;
4004
4005 RTPFragmentationHeader fragmentation;
4006 fragmentation.VerifyAndAllocateFragmentationHeader(1);
4007 fragmentation.fragmentationOffset[0] = 4;
4008 fragmentation.fragmentationLength[0] = sizeof(original_sps) - 4;
4009
4010 fake_encoder_.InjectEncodedImage(image, &codec_specific_info, &fragmentation);
4011 EXPECT_TRUE(sink_.WaitForFrame(kDefaultTimeoutMs));
4012
4013 EXPECT_THAT(sink_.GetLastEncodedImageData(),
4014 testing::ElementsAreArray(optimal_sps));
4015 RTPFragmentationHeader last_fragmentation = sink_.GetLastFragmentation();
4016 ASSERT_THAT(last_fragmentation.fragmentationVectorSize, 1U);
4017 EXPECT_EQ(last_fragmentation.fragmentationOffset[0], 4U);
4018 EXPECT_EQ(last_fragmentation.fragmentationLength[0], sizeof(optimal_sps) - 4);
4019
4020 video_stream_encoder_->Stop();
4021}
4022
Ilya Nikolaevskiyba96e2f2019-06-04 15:15:14 +02004023TEST_F(VideoStreamEncoderTest, CopiesVideoFrameMetadataAfterDownscale) {
4024 const int kFrameWidth = 1280;
4025 const int kFrameHeight = 720;
4026 const int kTargetBitrateBps = 300000; // To low for HD resolution.
4027
4028 video_stream_encoder_->OnBitrateUpdated(
4029 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
4030 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
4031
4032 // Insert a first video frame. It should be dropped because of downscale in
4033 // resolution.
4034 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
4035 VideoFrame frame = CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight);
4036 frame.set_rotation(kVideoRotation_270);
4037 video_source_.IncomingCapturedFrame(frame);
4038
4039 ExpectDroppedFrame();
4040
4041 // Second frame is downscaled.
4042 timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
4043 frame = CreateFrame(timestamp_ms, kFrameWidth / 2, kFrameHeight / 2);
4044 frame.set_rotation(kVideoRotation_90);
4045 video_source_.IncomingCapturedFrame(frame);
4046
4047 WaitForEncodedFrame(timestamp_ms);
4048 sink_.CheckLastFrameRotationMatches(kVideoRotation_90);
4049
4050 // Insert another frame, also downscaled.
4051 timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
4052 frame = CreateFrame(timestamp_ms, kFrameWidth / 2, kFrameHeight / 2);
4053 frame.set_rotation(kVideoRotation_180);
4054 video_source_.IncomingCapturedFrame(frame);
4055
4056 WaitForEncodedFrame(timestamp_ms);
4057 sink_.CheckLastFrameRotationMatches(kVideoRotation_180);
4058
4059 video_stream_encoder_->Stop();
4060}
4061
perkj26091b12016-09-01 01:17:40 -07004062} // namespace webrtc