blob: 6407bcb34a3515f6e507999281c3bffec8262a96 [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
sprangfe627f32017-03-29 08:24:59 -070011#include <algorithm>
perkj803d97f2016-11-01 11:45:46 -070012#include <limits>
Per512ecb32016-09-23 15:52:06 +020013#include <utility>
14
nisseaf916892017-01-10 07:44:26 -080015#include "webrtc/api/video/i420_buffer.h"
sprangb1ca0732017-02-01 08:38:12 -080016#include "webrtc/media/base/videoadapter.h"
sprangfe627f32017-03-29 08:24:59 -070017#include "webrtc/modules/video_coding/codecs/vp8/temporal_layers.h"
sprang57c2fff2017-01-16 06:24:02 -080018#include "webrtc/modules/video_coding/utility/default_video_bitrate_allocator.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020019#include "webrtc/rtc_base/fakeclock.h"
20#include "webrtc/rtc_base/logging.h"
perkj803d97f2016-11-01 11:45:46 -070021#include "webrtc/system_wrappers/include/metrics_default.h"
sprang57c2fff2017-01-16 06:24:02 -080022#include "webrtc/system_wrappers/include/sleep.h"
perkj26091b12016-09-01 01:17:40 -070023#include "webrtc/test/encoder_settings.h"
24#include "webrtc/test/fake_encoder.h"
perkja49cbd32016-09-16 07:53:41 -070025#include "webrtc/test/frame_generator.h"
sprang57c2fff2017-01-16 06:24:02 -080026#include "webrtc/test/gmock.h"
kwibergac9f8762016-09-30 22:29:43 -070027#include "webrtc/test/gtest.h"
perkj26091b12016-09-01 01:17:40 -070028#include "webrtc/video/send_statistics_proxy.h"
mflodmancc3d4422017-08-03 08:27:51 -070029#include "webrtc/video/video_stream_encoder.h"
perkj26091b12016-09-01 01:17:40 -070030
kthelgason33ce8892016-12-09 03:53:59 -080031namespace {
kthelgason33ce8892016-12-09 03:53:59 -080032const int kMinPixelsPerFrame = 320 * 180;
sprangc5d62e22017-04-02 23:53:04 -070033const int kMinFramerateFps = 2;
34const int64_t kFrameTimeoutMs = 100;
35} // namespace
kthelgason33ce8892016-12-09 03:53:59 -080036
perkj26091b12016-09-01 01:17:40 -070037namespace webrtc {
38
kthelgason876222f2016-11-29 01:44:11 -080039using DegredationPreference = VideoSendStream::DegradationPreference;
sprangb1ca0732017-02-01 08:38:12 -080040using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080041using ::testing::_;
42using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080043
perkj803d97f2016-11-01 11:45:46 -070044namespace {
asapersson5f7226f2016-11-25 04:37:00 -080045const size_t kMaxPayloadLength = 1440;
kthelgason2bc68642017-02-07 07:02:22 -080046const int kTargetBitrateBps = 1000000;
47const int kLowTargetBitrateBps = kTargetBitrateBps / 10;
48const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070049const int kDefaultFramerate = 30;
asapersson5f7226f2016-11-25 04:37:00 -080050
perkj803d97f2016-11-01 11:45:46 -070051class TestBuffer : public webrtc::I420Buffer {
52 public:
53 TestBuffer(rtc::Event* event, int width, int height)
54 : I420Buffer(width, height), event_(event) {}
55
56 private:
57 friend class rtc::RefCountedObject<TestBuffer>;
58 ~TestBuffer() override {
59 if (event_)
60 event_->Set();
61 }
62 rtc::Event* const event_;
63};
64
sprangfda496a2017-06-15 04:21:07 -070065class CpuOveruseDetectorProxy : public OveruseFrameDetector {
66 public:
67 CpuOveruseDetectorProxy(const CpuOveruseOptions& options,
68 AdaptationObserverInterface* overuse_observer,
69 EncodedFrameObserver* encoder_timing_,
70 CpuOveruseMetricsObserver* metrics_observer)
71 : OveruseFrameDetector(options,
72 overuse_observer,
73 encoder_timing_,
74 metrics_observer),
75 last_target_framerate_fps_(-1) {}
76 virtual ~CpuOveruseDetectorProxy() {}
77
78 void OnTargetFramerateUpdated(int framerate_fps) override {
79 rtc::CritScope cs(&lock_);
80 last_target_framerate_fps_ = framerate_fps;
81 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
82 }
83
84 int GetLastTargetFramerate() {
85 rtc::CritScope cs(&lock_);
86 return last_target_framerate_fps_;
87 }
88
89 private:
90 rtc::CriticalSection lock_;
91 int last_target_framerate_fps_ GUARDED_BY(lock_);
92};
93
mflodmancc3d4422017-08-03 08:27:51 -070094class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -070095 public:
mflodmancc3d4422017-08-03 08:27:51 -070096 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
kthelgason876222f2016-11-29 01:44:11 -080097 const VideoSendStream::Config::EncoderSettings& settings)
mflodmancc3d4422017-08-03 08:27:51 -070098 : VideoStreamEncoder(
99 1 /* number_of_cores */,
100 stats_proxy,
101 settings,
102 nullptr /* pre_encode_callback */,
103 nullptr /* encoder_timing */,
104 std::unique_ptr<OveruseFrameDetector>(
105 overuse_detector_proxy_ = new CpuOveruseDetectorProxy(
106 GetCpuOveruseOptions(settings.full_overuse_time),
107 this,
108 nullptr,
109 stats_proxy))) {}
perkj803d97f2016-11-01 11:45:46 -0700110
sprangb1ca0732017-02-01 08:38:12 -0800111 void PostTaskAndWait(bool down, AdaptReason reason) {
perkj803d97f2016-11-01 11:45:46 -0700112 rtc::Event event(false, false);
kthelgason876222f2016-11-29 01:44:11 -0800113 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800114 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700115 event.Set();
116 });
perkj070ba852017-02-16 15:46:27 -0800117 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700118 }
119
kthelgason2fc52542017-03-03 00:24:41 -0800120 // This is used as a synchronisation mechanism, to make sure that the
121 // encoder queue is not blocked before we start sending it frames.
122 void WaitUntilTaskQueueIsIdle() {
123 rtc::Event event(false, false);
124 encoder_queue()->PostTask([&event] {
125 event.Set();
126 });
127 ASSERT_TRUE(event.Wait(5000));
128 }
129
sprangb1ca0732017-02-01 08:38:12 -0800130 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800131
sprangb1ca0732017-02-01 08:38:12 -0800132 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800133
sprangb1ca0732017-02-01 08:38:12 -0800134 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800135
sprangb1ca0732017-02-01 08:38:12 -0800136 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700137
138 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700139};
140
asapersson5f7226f2016-11-25 04:37:00 -0800141class VideoStreamFactory
142 : public VideoEncoderConfig::VideoStreamFactoryInterface {
143 public:
sprangfda496a2017-06-15 04:21:07 -0700144 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
145 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800146 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700147 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800148 }
149
150 private:
151 std::vector<VideoStream> CreateEncoderStreams(
152 int width,
153 int height,
154 const VideoEncoderConfig& encoder_config) override {
155 std::vector<VideoStream> streams =
156 test::CreateVideoStreams(width, height, encoder_config);
157 for (VideoStream& stream : streams) {
158 stream.temporal_layer_thresholds_bps.resize(num_temporal_layers_ - 1);
sprangfda496a2017-06-15 04:21:07 -0700159 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800160 }
161 return streams;
162 }
sprangfda496a2017-06-15 04:21:07 -0700163
asapersson5f7226f2016-11-25 04:37:00 -0800164 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700165 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800166};
167
ilnik6b826ef2017-06-16 06:53:48 -0700168
sprangb1ca0732017-02-01 08:38:12 -0800169class AdaptingFrameForwarder : public test::FrameForwarder {
170 public:
171 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700172 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800173
174 void set_adaptation_enabled(bool enabled) {
175 rtc::CritScope cs(&crit_);
176 adaptation_enabled_ = enabled;
177 }
178
asaperssonfab67072017-04-04 05:51:49 -0700179 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800180 rtc::CritScope cs(&crit_);
181 return adaptation_enabled_;
182 }
183
asapersson09f05612017-05-15 23:40:18 -0700184 rtc::VideoSinkWants last_wants() const {
185 rtc::CritScope cs(&crit_);
186 return last_wants_;
187 }
188
sprangb1ca0732017-02-01 08:38:12 -0800189 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
190 int cropped_width = 0;
191 int cropped_height = 0;
192 int out_width = 0;
193 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700194 if (adaption_enabled()) {
195 if (adapter_.AdaptFrameResolution(
196 video_frame.width(), video_frame.height(),
197 video_frame.timestamp_us() * 1000, &cropped_width,
198 &cropped_height, &out_width, &out_height)) {
199 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
200 nullptr, out_width, out_height),
201 99, 99, kVideoRotation_0);
202 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
203 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
204 }
sprangb1ca0732017-02-01 08:38:12 -0800205 } else {
206 test::FrameForwarder::IncomingCapturedFrame(video_frame);
207 }
208 }
209
210 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
211 const rtc::VideoSinkWants& wants) override {
212 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700213 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700214 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
215 wants.max_pixel_count,
216 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800217 test::FrameForwarder::AddOrUpdateSink(sink, wants);
218 }
sprangb1ca0732017-02-01 08:38:12 -0800219 cricket::VideoAdapter adapter_;
220 bool adaptation_enabled_ GUARDED_BY(crit_);
asapersson09f05612017-05-15 23:40:18 -0700221 rtc::VideoSinkWants last_wants_ GUARDED_BY(crit_);
sprangb1ca0732017-02-01 08:38:12 -0800222};
sprangc5d62e22017-04-02 23:53:04 -0700223
224class MockableSendStatisticsProxy : public SendStatisticsProxy {
225 public:
226 MockableSendStatisticsProxy(Clock* clock,
227 const VideoSendStream::Config& config,
228 VideoEncoderConfig::ContentType content_type)
229 : SendStatisticsProxy(clock, config, content_type) {}
230
231 VideoSendStream::Stats GetStats() override {
232 rtc::CritScope cs(&lock_);
233 if (mock_stats_)
234 return *mock_stats_;
235 return SendStatisticsProxy::GetStats();
236 }
237
238 void SetMockStats(const VideoSendStream::Stats& stats) {
239 rtc::CritScope cs(&lock_);
240 mock_stats_.emplace(stats);
241 }
242
243 void ResetMockStats() {
244 rtc::CritScope cs(&lock_);
245 mock_stats_.reset();
246 }
247
248 private:
249 rtc::CriticalSection lock_;
250 rtc::Optional<VideoSendStream::Stats> mock_stats_ GUARDED_BY(lock_);
251};
252
sprang4847ae62017-06-27 07:06:52 -0700253class MockBitrateObserver : public VideoBitrateAllocationObserver {
254 public:
255 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const BitrateAllocation&));
256};
257
perkj803d97f2016-11-01 11:45:46 -0700258} // namespace
259
mflodmancc3d4422017-08-03 08:27:51 -0700260class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700261 public:
262 static const int kDefaultTimeoutMs = 30 * 1000;
263
mflodmancc3d4422017-08-03 08:27:51 -0700264 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700265 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700266 codec_width_(320),
267 codec_height_(240),
sprang4847ae62017-06-27 07:06:52 -0700268 max_framerate_(30),
perkj26091b12016-09-01 01:17:40 -0700269 fake_encoder_(),
sprangc5d62e22017-04-02 23:53:04 -0700270 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700271 Clock::GetRealTimeClock(),
272 video_send_config_,
273 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700274 sink_(&fake_encoder_) {}
275
276 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700277 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700278 video_send_config_ = VideoSendStream::Config(nullptr);
279 video_send_config_.encoder_settings.encoder = &fake_encoder_;
280 video_send_config_.encoder_settings.payload_name = "FAKE";
281 video_send_config_.encoder_settings.payload_type = 125;
282
Per512ecb32016-09-23 15:52:06 +0200283 VideoEncoderConfig video_encoder_config;
perkjfa10b552016-10-02 23:45:26 -0700284 test::FillEncoderConfiguration(1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700285 video_encoder_config.video_stream_factory =
286 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100287 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700288
289 // Framerate limit is specified by the VideoStreamFactory.
290 std::vector<VideoStream> streams =
291 video_encoder_config.video_stream_factory->CreateEncoderStreams(
292 codec_width_, codec_height_, video_encoder_config);
293 max_framerate_ = streams[0].max_framerate;
294 fake_clock_.SetTimeMicros(1234);
295
asapersson5f7226f2016-11-25 04:37:00 -0800296 ConfigureEncoder(std::move(video_encoder_config), true /* nack_enabled */);
297 }
298
299 void ConfigureEncoder(VideoEncoderConfig video_encoder_config,
300 bool nack_enabled) {
mflodmancc3d4422017-08-03 08:27:51 -0700301 if (video_stream_encoder_)
302 video_stream_encoder_->Stop();
303 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700304 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700305 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
306 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -0700307 &video_source_,
308 VideoSendStream::DegradationPreference::kMaintainFramerate);
mflodmancc3d4422017-08-03 08:27:51 -0700309 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
310 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
311 kMaxPayloadLength, nack_enabled);
312 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800313 }
314
315 void ResetEncoder(const std::string& payload_name,
316 size_t num_streams,
317 size_t num_temporal_layers,
sprang4847ae62017-06-27 07:06:52 -0700318 bool nack_enabled,
319 bool screenshare) {
asapersson5f7226f2016-11-25 04:37:00 -0800320 video_send_config_.encoder_settings.payload_name = payload_name;
321
322 VideoEncoderConfig video_encoder_config;
323 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800324 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800325 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700326 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
327 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700328 video_encoder_config.content_type =
329 screenshare ? VideoEncoderConfig::ContentType::kScreen
330 : VideoEncoderConfig::ContentType::kRealtimeVideo;
asapersson5f7226f2016-11-25 04:37:00 -0800331 ConfigureEncoder(std::move(video_encoder_config), nack_enabled);
perkj26091b12016-09-01 01:17:40 -0700332 }
333
sprang57c2fff2017-01-16 06:24:02 -0800334 VideoFrame CreateFrame(int64_t ntp_time_ms,
335 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200336 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
337 destruction_event, codec_width_, codec_height_),
338 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800339 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700340 return frame;
341 }
342
sprang57c2fff2017-01-16 06:24:02 -0800343 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700344 VideoFrame frame(
345 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
346 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800347 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700348 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700349 return frame;
350 }
351
asapersson02465b82017-04-10 01:12:52 -0700352 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700353 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700354 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
355 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700356 }
357
asapersson09f05612017-05-15 23:40:18 -0700358 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
359 const rtc::VideoSinkWants& wants2) {
360 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
361 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
362 }
363
364 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
365 const rtc::VideoSinkWants& wants2) {
366 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
367 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
368 EXPECT_GT(wants1.max_pixel_count, 0);
369 }
370
371 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
372 const rtc::VideoSinkWants& wants2) {
373 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
374 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
375 }
376
asaperssonf7e294d2017-06-13 23:25:22 -0700377 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
378 const rtc::VideoSinkWants& wants2) {
379 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
380 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
381 }
382
383 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
384 const rtc::VideoSinkWants& wants2) {
385 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
386 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
387 }
388
389 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
390 const rtc::VideoSinkWants& wants2) {
391 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
392 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
393 }
394
395 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
396 const rtc::VideoSinkWants& wants2) {
397 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
398 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
399 EXPECT_GT(wants1.max_pixel_count, 0);
400 }
401
402 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
403 const rtc::VideoSinkWants& wants2) {
404 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
405 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
406 }
407
asapersson09f05612017-05-15 23:40:18 -0700408 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
409 int pixel_count) {
410 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700411 EXPECT_LT(wants.max_pixel_count, pixel_count);
412 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700413 }
414
415 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
416 EXPECT_LT(wants.max_framerate_fps, fps);
417 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
418 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700419 }
420
asaperssonf7e294d2017-06-13 23:25:22 -0700421 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
422 int expected_fps) {
423 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
424 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
425 EXPECT_FALSE(wants.target_pixel_count);
426 }
427
sprang4847ae62017-06-27 07:06:52 -0700428 void WaitForEncodedFrame(int64_t expected_ntp_time) {
429 sink_.WaitForEncodedFrame(expected_ntp_time);
430 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
431 }
432
433 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
434 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
435 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
436 return ok;
437 }
438
439 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
440 sink_.WaitForEncodedFrame(expected_width, expected_height);
441 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
442 }
443
444 void ExpectDroppedFrame() {
445 sink_.ExpectDroppedFrame();
446 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
447 }
448
449 bool WaitForFrame(int64_t timeout_ms) {
450 bool ok = sink_.WaitForFrame(timeout_ms);
451 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
452 return ok;
453 }
454
perkj26091b12016-09-01 01:17:40 -0700455 class TestEncoder : public test::FakeEncoder {
456 public:
457 TestEncoder()
458 : FakeEncoder(Clock::GetRealTimeClock()),
459 continue_encode_event_(false, false) {}
460
asaperssonfab67072017-04-04 05:51:49 -0700461 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800462 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700463 return config_;
464 }
465
466 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800467 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700468 block_next_encode_ = true;
469 }
470
kthelgason876222f2016-11-29 01:44:11 -0800471 VideoEncoder::ScalingSettings GetScalingSettings() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800472 rtc::CritScope lock(&local_crit_sect_);
kthelgasonad9010c2017-02-14 00:46:51 -0800473 if (quality_scaling_)
asapersson142fcc92017-08-17 08:58:54 -0700474 return VideoEncoder::ScalingSettings(true, 1, 2, kMinPixelsPerFrame);
kthelgasonad9010c2017-02-14 00:46:51 -0800475 return VideoEncoder::ScalingSettings(false);
kthelgason876222f2016-11-29 01:44:11 -0800476 }
477
perkjfa10b552016-10-02 23:45:26 -0700478 void ContinueEncode() { continue_encode_event_.Set(); }
479
480 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
481 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800482 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700483 EXPECT_EQ(timestamp_, timestamp);
484 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
485 }
486
kthelgason2fc52542017-03-03 00:24:41 -0800487 void SetQualityScaling(bool b) {
488 rtc::CritScope lock(&local_crit_sect_);
489 quality_scaling_ = b;
490 }
kthelgasonad9010c2017-02-14 00:46:51 -0800491
sprangfe627f32017-03-29 08:24:59 -0700492 void ForceInitEncodeFailure(bool force_failure) {
493 rtc::CritScope lock(&local_crit_sect_);
494 force_init_encode_failed_ = force_failure;
495 }
496
perkjfa10b552016-10-02 23:45:26 -0700497 private:
perkj26091b12016-09-01 01:17:40 -0700498 int32_t Encode(const VideoFrame& input_image,
499 const CodecSpecificInfo* codec_specific_info,
500 const std::vector<FrameType>* frame_types) override {
501 bool block_encode;
502 {
brandtre78d2662017-01-16 05:57:16 -0800503 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700504 EXPECT_GT(input_image.timestamp(), timestamp_);
505 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
506 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
507
508 timestamp_ = input_image.timestamp();
509 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700510 last_input_width_ = input_image.width();
511 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700512 block_encode = block_next_encode_;
513 block_next_encode_ = false;
514 }
515 int32_t result =
516 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
517 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700518 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700519 return result;
520 }
521
sprangfe627f32017-03-29 08:24:59 -0700522 int32_t InitEncode(const VideoCodec* config,
523 int32_t number_of_cores,
524 size_t max_payload_size) override {
525 int res =
526 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
527 rtc::CritScope lock(&local_crit_sect_);
528 if (config->codecType == kVideoCodecVP8 && config->VP8().tl_factory) {
529 // Simulate setting up temporal layers, in order to validate the life
530 // cycle of these objects.
531 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
532 int num_temporal_layers =
533 std::max<int>(1, config->VP8().numberOfTemporalLayers);
534 for (int i = 0; i < num_streams; ++i) {
535 allocated_temporal_layers_.emplace_back(
536 config->VP8().tl_factory->Create(i, num_temporal_layers, 42));
537 }
538 }
539 if (force_init_encode_failed_)
540 return -1;
541 return res;
542 }
543
brandtre78d2662017-01-16 05:57:16 -0800544 rtc::CriticalSection local_crit_sect_;
sprangfe627f32017-03-29 08:24:59 -0700545 bool block_next_encode_ GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700546 rtc::Event continue_encode_event_;
sprangfe627f32017-03-29 08:24:59 -0700547 uint32_t timestamp_ GUARDED_BY(local_crit_sect_) = 0;
548 int64_t ntp_time_ms_ GUARDED_BY(local_crit_sect_) = 0;
549 int last_input_width_ GUARDED_BY(local_crit_sect_) = 0;
550 int last_input_height_ GUARDED_BY(local_crit_sect_) = 0;
551 bool quality_scaling_ GUARDED_BY(local_crit_sect_) = true;
552 std::vector<std::unique_ptr<TemporalLayers>> allocated_temporal_layers_
553 GUARDED_BY(local_crit_sect_);
554 bool force_init_encode_failed_ GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700555 };
556
mflodmancc3d4422017-08-03 08:27:51 -0700557 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700558 public:
559 explicit TestSink(TestEncoder* test_encoder)
560 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
561
perkj26091b12016-09-01 01:17:40 -0700562 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700563 EXPECT_TRUE(
564 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
565 }
566
567 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
568 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700569 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700570 if (!encoded_frame_event_.Wait(timeout_ms))
571 return false;
perkj26091b12016-09-01 01:17:40 -0700572 {
573 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800574 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700575 }
576 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700577 return true;
perkj26091b12016-09-01 01:17:40 -0700578 }
579
sprangb1ca0732017-02-01 08:38:12 -0800580 void WaitForEncodedFrame(uint32_t expected_width,
581 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700582 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
583 CheckLastFrameSizeMathces(expected_width, expected_height);
584 }
585
586 void CheckLastFrameSizeMathces(uint32_t expected_width,
587 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800588 uint32_t width = 0;
589 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800590 {
591 rtc::CritScope lock(&crit_);
592 width = last_width_;
593 height = last_height_;
594 }
595 EXPECT_EQ(expected_height, height);
596 EXPECT_EQ(expected_width, width);
597 }
598
kthelgason2fc52542017-03-03 00:24:41 -0800599 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800600
sprangc5d62e22017-04-02 23:53:04 -0700601 bool WaitForFrame(int64_t timeout_ms) {
602 return encoded_frame_event_.Wait(timeout_ms);
603 }
604
perkj26091b12016-09-01 01:17:40 -0700605 void SetExpectNoFrames() {
606 rtc::CritScope lock(&crit_);
607 expect_frames_ = false;
608 }
609
asaperssonfab67072017-04-04 05:51:49 -0700610 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200611 rtc::CritScope lock(&crit_);
612 return number_of_reconfigurations_;
613 }
614
asaperssonfab67072017-04-04 05:51:49 -0700615 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200616 rtc::CritScope lock(&crit_);
617 return min_transmit_bitrate_bps_;
618 }
619
perkj26091b12016-09-01 01:17:40 -0700620 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700621 Result OnEncodedImage(
622 const EncodedImage& encoded_image,
623 const CodecSpecificInfo* codec_specific_info,
624 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200625 rtc::CritScope lock(&crit_);
626 EXPECT_TRUE(expect_frames_);
sprangb1ca0732017-02-01 08:38:12 -0800627 last_timestamp_ = encoded_image._timeStamp;
628 last_width_ = encoded_image._encodedWidth;
629 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200630 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800631 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200632 }
633
634 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
635 int min_transmit_bitrate_bps) override {
636 rtc::CriticalSection crit_;
637 ++number_of_reconfigurations_;
638 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
639 }
640
perkj26091b12016-09-01 01:17:40 -0700641 rtc::CriticalSection crit_;
642 TestEncoder* test_encoder_;
643 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800644 uint32_t last_timestamp_ = 0;
645 uint32_t last_height_ = 0;
646 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700647 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200648 int number_of_reconfigurations_ = 0;
649 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700650 };
651
652 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100653 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200654 int codec_width_;
655 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700656 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700657 TestEncoder fake_encoder_;
sprangc5d62e22017-04-02 23:53:04 -0700658 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700659 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800660 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700661 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700662 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700663};
664
mflodmancc3d4422017-08-03 08:27:51 -0700665TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
666 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700667 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700668 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700669 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700670 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700671 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700672}
673
mflodmancc3d4422017-08-03 08:27:51 -0700674TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700675 // Dropped since no target bitrate has been set.
676 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700677 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
678 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700679
mflodmancc3d4422017-08-03 08:27:51 -0700680 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700681
perkja49cbd32016-09-16 07:53:41 -0700682 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700683 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700684 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700685}
686
mflodmancc3d4422017-08-03 08:27:51 -0700687TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
688 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700689 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700690 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700691
mflodmancc3d4422017-08-03 08:27:51 -0700692 video_stream_encoder_->OnBitrateUpdated(0, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700693 // Dropped since bitrate is zero.
perkja49cbd32016-09-16 07:53:41 -0700694 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkj26091b12016-09-01 01:17:40 -0700695
mflodmancc3d4422017-08-03 08:27:51 -0700696 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700697 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700698 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700699 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700700}
701
mflodmancc3d4422017-08-03 08:27:51 -0700702TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
703 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700704 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700705 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700706
707 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700708 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700709
perkja49cbd32016-09-16 07:53:41 -0700710 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700711 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700712 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700713}
714
mflodmancc3d4422017-08-03 08:27:51 -0700715TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
716 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700717
perkja49cbd32016-09-16 07:53:41 -0700718 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700719 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700720
mflodmancc3d4422017-08-03 08:27:51 -0700721 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700722 sink_.SetExpectNoFrames();
723 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700724 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
725 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700726}
727
mflodmancc3d4422017-08-03 08:27:51 -0700728TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
729 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700730
731 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700732 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700733 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700734 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
735 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700736 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
737 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700738 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700739 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700740
mflodmancc3d4422017-08-03 08:27:51 -0700741 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700742}
743
mflodmancc3d4422017-08-03 08:27:51 -0700744TEST_F(VideoStreamEncoderTest,
745 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
746 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100747 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200748
749 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200750 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700751 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100752 // The encoder will have been configured once when the first frame is
753 // received.
754 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200755
756 VideoEncoderConfig video_encoder_config;
perkjfa10b552016-10-02 23:45:26 -0700757 test::FillEncoderConfiguration(1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200758 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -0700759 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
760 kMaxPayloadLength,
761 true /* nack_enabled */);
Per512ecb32016-09-23 15:52:06 +0200762
763 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200764 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700765 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100766 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700767 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700768
mflodmancc3d4422017-08-03 08:27:51 -0700769 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -0700770}
771
mflodmancc3d4422017-08-03 08:27:51 -0700772TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
773 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkjfa10b552016-10-02 23:45:26 -0700774
775 // Capture a frame and wait for it to synchronize with the encoder thread.
776 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700777 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100778 // The encoder will have been configured once.
779 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700780 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
781 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
782
783 codec_width_ *= 2;
784 codec_height_ *= 2;
785 // Capture a frame with a higher resolution and wait for it to synchronize
786 // with the encoder thread.
787 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700788 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700789 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
790 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100791 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700792
mflodmancc3d4422017-08-03 08:27:51 -0700793 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -0700794}
795
mflodmancc3d4422017-08-03 08:27:51 -0700796TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOffFor1S1TLWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800797 const bool kNackEnabled = true;
798 const size_t kNumStreams = 1;
799 const size_t kNumTl = 1;
emircan7b532db2017-08-17 18:20:40 -0700800 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700801 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800802
803 // Capture a frame and wait for it to synchronize with the encoder thread.
804 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700805 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800806 // The encoder have been configured once when the first frame is received.
807 EXPECT_EQ(1, sink_.number_of_reconfigurations());
808 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
809 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
810 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
811 // Resilience is off for no temporal layers with nack on.
812 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700813 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800814}
815
mflodmancc3d4422017-08-03 08:27:51 -0700816TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOffFor2S1TlWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800817 const bool kNackEnabled = true;
818 const size_t kNumStreams = 2;
819 const size_t kNumTl = 1;
emircan7b532db2017-08-17 18:20:40 -0700820 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700821 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800822
823 // Capture a frame and wait for it to synchronize with the encoder thread.
824 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700825 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800826 // The encoder have been configured once when the first frame is received.
827 EXPECT_EQ(1, sink_.number_of_reconfigurations());
828 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
829 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
830 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
831 // Resilience is off for no temporal layers and >1 streams with nack on.
832 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700833 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800834}
835
mflodmancc3d4422017-08-03 08:27:51 -0700836TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOnFor1S1TLWithNackDisabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800837 const bool kNackEnabled = false;
838 const size_t kNumStreams = 1;
839 const size_t kNumTl = 1;
emircan7b532db2017-08-17 18:20:40 -0700840 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700841 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800842
843 // Capture a frame and wait for it to synchronize with the encoder thread.
844 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700845 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800846 // The encoder have been configured once when the first frame is received.
847 EXPECT_EQ(1, sink_.number_of_reconfigurations());
848 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
849 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
850 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
851 // Resilience is on for no temporal layers with nack off.
852 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700853 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800854}
855
mflodmancc3d4422017-08-03 08:27:51 -0700856TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOnFor1S2TlWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800857 const bool kNackEnabled = true;
858 const size_t kNumStreams = 1;
859 const size_t kNumTl = 2;
emircan7b532db2017-08-17 18:20:40 -0700860 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700861 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800862
863 // Capture a frame and wait for it to synchronize with the encoder thread.
864 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700865 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800866 // The encoder have been configured once when the first frame is received.
867 EXPECT_EQ(1, sink_.number_of_reconfigurations());
868 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
869 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
870 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
871 // Resilience is on for temporal layers.
872 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700873 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800874}
875
mflodmancc3d4422017-08-03 08:27:51 -0700876TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -0700877 EXPECT_TRUE(video_source_.has_sinks());
878 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700879 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -0700880 &new_video_source,
881 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -0700882 EXPECT_FALSE(video_source_.has_sinks());
883 EXPECT_TRUE(new_video_source.has_sinks());
884
mflodmancc3d4422017-08-03 08:27:51 -0700885 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700886}
887
mflodmancc3d4422017-08-03 08:27:51 -0700888TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -0700889 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700890 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -0700891 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700892 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700893}
894
mflodmancc3d4422017-08-03 08:27:51 -0700895TEST_F(VideoStreamEncoderTest, SinkWantsFromOveruseDetector) {
896 const int kMaxDowngrades = VideoStreamEncoder::kMaxCpuResolutionDowngrades;
897 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -0700898
asapersson02465b82017-04-10 01:12:52 -0700899 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700900
901 int frame_width = 1280;
902 int frame_height = 720;
903
mflodmancc3d4422017-08-03 08:27:51 -0700904 // Trigger CPU overuse kMaxCpuDowngrades times. Every time, VideoStreamEncoder
905 // should request lower resolution.
asaperssond0de2952017-04-21 01:47:31 -0700906 for (int i = 1; i <= kMaxDowngrades; ++i) {
perkj803d97f2016-11-01 11:45:46 -0700907 video_source_.IncomingCapturedFrame(
908 CreateFrame(i, frame_width, frame_height));
sprang4847ae62017-06-27 07:06:52 -0700909 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -0700910
mflodmancc3d4422017-08-03 08:27:51 -0700911 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700912
sprang84a37592017-02-10 07:04:27 -0800913 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700914 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
perkj803d97f2016-11-01 11:45:46 -0700915 frame_width * frame_height);
asaperssond0de2952017-04-21 01:47:31 -0700916 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
917 EXPECT_EQ(i, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -0700918
919 frame_width /= 2;
920 frame_height /= 2;
921 }
922
kthelgason876222f2016-11-29 01:44:11 -0800923 // Trigger CPU overuse one more time. This should not trigger a request for
perkj803d97f2016-11-01 11:45:46 -0700924 // lower resolution.
925 rtc::VideoSinkWants current_wants = video_source_.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -0700926 video_source_.IncomingCapturedFrame(
927 CreateFrame(kMaxDowngrades + 1, frame_width, frame_height));
sprang4847ae62017-06-27 07:06:52 -0700928 WaitForEncodedFrame(kMaxDowngrades + 1);
mflodmancc3d4422017-08-03 08:27:51 -0700929 video_stream_encoder_->TriggerCpuOveruse();
sprang84a37592017-02-10 07:04:27 -0800930 EXPECT_EQ(video_source_.sink_wants().target_pixel_count,
931 current_wants.target_pixel_count);
perkj803d97f2016-11-01 11:45:46 -0700932 EXPECT_EQ(video_source_.sink_wants().max_pixel_count,
933 current_wants.max_pixel_count);
asaperssond0de2952017-04-21 01:47:31 -0700934 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
935 EXPECT_EQ(kMaxDowngrades,
936 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -0700937
938 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -0700939 video_stream_encoder_->TriggerCpuNormalUsage();
sprang84a37592017-02-10 07:04:27 -0800940 EXPECT_EQ(frame_width * frame_height * 5 / 3,
941 video_source_.sink_wants().target_pixel_count.value_or(0));
942 EXPECT_EQ(frame_width * frame_height * 4,
sprangc5d62e22017-04-02 23:53:04 -0700943 video_source_.sink_wants().max_pixel_count);
asaperssond0de2952017-04-21 01:47:31 -0700944 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
945 EXPECT_EQ(kMaxDowngrades + 1,
946 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -0700947
mflodmancc3d4422017-08-03 08:27:51 -0700948 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700949}
950
mflodmancc3d4422017-08-03 08:27:51 -0700951TEST_F(VideoStreamEncoderTest,
952 TestMaxCpuResolutionDowngrades_BalancedMode_NoFpsLimit) {
953 const int kMaxDowngrades = VideoStreamEncoder::kMaxCpuResolutionDowngrades;
asaperssonf7e294d2017-06-13 23:25:22 -0700954 const int kWidth = 1280;
955 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -0700956 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -0700957
958 // Enable kBalanced preference, no initial limitation.
959 AdaptingFrameForwarder source;
960 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -0700961 video_stream_encoder_->SetSource(
962 &source,
963 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -0700964 VerifyNoLimitation(source.sink_wants());
965 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
966 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
967
968 // Trigger adapt down kMaxCpuDowngrades times.
969 int t = 1;
970 for (int i = 1; i <= kMaxDowngrades; ++i) {
971 source.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
972 sink_.WaitForEncodedFrame(t++);
mflodmancc3d4422017-08-03 08:27:51 -0700973 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -0700974 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
975 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
976 EXPECT_EQ(i, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
977 }
978
979 // Trigger adapt down, max cpu downgrades reach, expect no change.
980 rtc::VideoSinkWants last_wants = source.sink_wants();
981 source.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
982 sink_.WaitForEncodedFrame(t++);
mflodmancc3d4422017-08-03 08:27:51 -0700983 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -0700984 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
985 EXPECT_EQ(last_wants.max_pixel_count, source.sink_wants().max_pixel_count);
986 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
987 EXPECT_EQ(kMaxDowngrades,
988 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
989
990 // Trigger adapt up kMaxCpuDowngrades times.
991 for (int i = 1; i <= kMaxDowngrades; ++i) {
992 source.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
993 sink_.WaitForEncodedFrame(t++);
mflodmancc3d4422017-08-03 08:27:51 -0700994 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -0700995 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
996 EXPECT_GT(source.sink_wants().max_pixel_count, last_wants.max_pixel_count);
997 EXPECT_EQ(kMaxDowngrades + i,
998 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
999 }
1000
1001 VerifyNoLimitation(source.sink_wants());
1002 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1003
mflodmancc3d4422017-08-03 08:27:51 -07001004 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001005}
mflodmancc3d4422017-08-03 08:27:51 -07001006TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
1007 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001008 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001009
sprangc5d62e22017-04-02 23:53:04 -07001010 const int kFrameWidth = 1280;
1011 const int kFrameHeight = 720;
1012 const int kFrameIntervalMs = 1000 / 30;
1013
1014 int frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -07001015
kthelgason5e13d412016-12-01 03:59:51 -08001016 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001017 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001018 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001019 frame_timestamp += kFrameIntervalMs;
1020
perkj803d97f2016-11-01 11:45:46 -07001021 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001022 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001023 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001024 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001025 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001026 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -07001027
asapersson0944a802017-04-07 00:57:58 -07001028 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -07001029 // wanted resolution.
1030 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
1031 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
1032 kFrameWidth * kFrameHeight);
1033 EXPECT_EQ(std::numeric_limits<int>::max(),
1034 video_source_.sink_wants().max_framerate_fps);
1035
1036 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -07001037 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001038 video_stream_encoder_->SetSource(
perkj803d97f2016-11-01 11:45:46 -07001039 &new_video_source,
1040 VideoSendStream::DegradationPreference::kMaintainResolution);
1041
sprangc5d62e22017-04-02 23:53:04 -07001042 // Initially no degradation registered.
asapersson02465b82017-04-10 01:12:52 -07001043 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001044
sprangc5d62e22017-04-02 23:53:04 -07001045 // Force an input frame rate to be available, or the adaptation call won't
1046 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -07001047 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -07001048 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -07001049 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -07001050 stats_proxy_->SetMockStats(stats);
1051
mflodmancc3d4422017-08-03 08:27:51 -07001052 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001053 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001054 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001055 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001056 frame_timestamp += kFrameIntervalMs;
1057
1058 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001059 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001060 EXPECT_EQ(std::numeric_limits<int>::max(),
1061 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001062 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001063
asapersson02465b82017-04-10 01:12:52 -07001064 // Turn off degradation completely.
mflodmancc3d4422017-08-03 08:27:51 -07001065 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001066 &new_video_source,
1067 VideoSendStream::DegradationPreference::kDegradationDisabled);
asapersson02465b82017-04-10 01:12:52 -07001068 VerifyNoLimitation(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001069
mflodmancc3d4422017-08-03 08:27:51 -07001070 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001071 new_video_source.IncomingCapturedFrame(
1072 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001073 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001074 frame_timestamp += kFrameIntervalMs;
1075
1076 // Still no degradation.
asapersson02465b82017-04-10 01:12:52 -07001077 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001078
1079 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001080 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001081 &new_video_source,
1082 VideoSendStream::DegradationPreference::kMaintainFramerate);
1083 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1084 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001085 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001086 EXPECT_EQ(std::numeric_limits<int>::max(),
1087 new_video_source.sink_wants().max_framerate_fps);
1088
1089 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001090 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001091 &new_video_source,
1092 VideoSendStream::DegradationPreference::kMaintainResolution);
1093 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1094 EXPECT_EQ(std::numeric_limits<int>::max(),
1095 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001096 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001097
mflodmancc3d4422017-08-03 08:27:51 -07001098 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001099}
1100
mflodmancc3d4422017-08-03 08:27:51 -07001101TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
1102 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001103
asaperssonfab67072017-04-04 05:51:49 -07001104 const int kWidth = 1280;
1105 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001106 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001107 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001108 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1109 EXPECT_FALSE(stats.bw_limited_resolution);
1110 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1111
1112 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001113 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001114 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001115 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001116
1117 stats = stats_proxy_->GetStats();
1118 EXPECT_TRUE(stats.bw_limited_resolution);
1119 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1120
1121 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001122 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001123 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001124 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001125
1126 stats = stats_proxy_->GetStats();
1127 EXPECT_FALSE(stats.bw_limited_resolution);
1128 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1129 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1130
mflodmancc3d4422017-08-03 08:27:51 -07001131 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001132}
1133
mflodmancc3d4422017-08-03 08:27:51 -07001134TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
1135 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001136
1137 const int kWidth = 1280;
1138 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001139 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001140 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001141 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1142 EXPECT_FALSE(stats.cpu_limited_resolution);
1143 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1144
1145 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001146 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001147 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001148 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001149
1150 stats = stats_proxy_->GetStats();
1151 EXPECT_TRUE(stats.cpu_limited_resolution);
1152 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1153
1154 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001155 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001156 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001157 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001158
1159 stats = stats_proxy_->GetStats();
1160 EXPECT_FALSE(stats.cpu_limited_resolution);
1161 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001162 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001163
mflodmancc3d4422017-08-03 08:27:51 -07001164 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001165}
1166
mflodmancc3d4422017-08-03 08:27:51 -07001167TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
1168 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001169
asaperssonfab67072017-04-04 05:51:49 -07001170 const int kWidth = 1280;
1171 const int kHeight = 720;
1172 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001173 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001174 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001175 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001176 EXPECT_FALSE(stats.cpu_limited_resolution);
1177 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1178
asaperssonfab67072017-04-04 05:51:49 -07001179 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001180 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001181 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001182 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001183 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001184 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001185 EXPECT_TRUE(stats.cpu_limited_resolution);
1186 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1187
1188 // Set new source with adaptation still enabled.
1189 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001190 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001191 &new_video_source,
1192 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001193
asaperssonfab67072017-04-04 05:51:49 -07001194 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001195 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001196 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001197 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001198 EXPECT_TRUE(stats.cpu_limited_resolution);
1199 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1200
1201 // Set adaptation disabled.
mflodmancc3d4422017-08-03 08:27:51 -07001202 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001203 &new_video_source,
sprangc5d62e22017-04-02 23:53:04 -07001204 VideoSendStream::DegradationPreference::kDegradationDisabled);
kthelgason876222f2016-11-29 01:44:11 -08001205
asaperssonfab67072017-04-04 05:51:49 -07001206 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001207 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001208 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001209 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001210 EXPECT_FALSE(stats.cpu_limited_resolution);
1211 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1212
1213 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001214 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001215 &new_video_source,
1216 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001217
asaperssonfab67072017-04-04 05:51:49 -07001218 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001219 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001220 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001221 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001222 EXPECT_TRUE(stats.cpu_limited_resolution);
1223 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1224
asaperssonfab67072017-04-04 05:51:49 -07001225 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001226 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001227 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001228 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001229 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001230 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001231 EXPECT_FALSE(stats.cpu_limited_resolution);
1232 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001233 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001234
mflodmancc3d4422017-08-03 08:27:51 -07001235 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001236}
1237
mflodmancc3d4422017-08-03 08:27:51 -07001238TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
1239 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001240
asaperssonfab67072017-04-04 05:51:49 -07001241 const int kWidth = 1280;
1242 const int kHeight = 720;
1243 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001244 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001245 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001246 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001247 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001248 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001249
1250 // Set new source with adaptation still enabled.
1251 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001252 video_stream_encoder_->SetSource(
1253 &new_video_source,
1254 VideoSendStream::DegradationPreference::kBalanced);
kthelgason876222f2016-11-29 01:44:11 -08001255
asaperssonfab67072017-04-04 05:51:49 -07001256 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001257 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001258 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001259 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001260 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001261 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001262
asaperssonfab67072017-04-04 05:51:49 -07001263 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001264 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001265 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001266 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001267 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001268 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001269 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001270 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001271
asaperssonfab67072017-04-04 05:51:49 -07001272 // Set new source with adaptation still enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001273 video_stream_encoder_->SetSource(
1274 &new_video_source,
1275 VideoSendStream::DegradationPreference::kBalanced);
kthelgason876222f2016-11-29 01:44:11 -08001276
asaperssonfab67072017-04-04 05:51:49 -07001277 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001278 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001279 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001280 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001281 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001282 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001283
asapersson02465b82017-04-10 01:12:52 -07001284 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001285 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001286 &new_video_source,
1287 VideoSendStream::DegradationPreference::kMaintainResolution);
1288
asaperssonfab67072017-04-04 05:51:49 -07001289 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001290 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001291 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001292 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001293 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001294 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1295 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001296
mflodmancc3d4422017-08-03 08:27:51 -07001297 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001298}
1299
mflodmancc3d4422017-08-03 08:27:51 -07001300TEST_F(VideoStreamEncoderTest,
1301 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1302 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001303
1304 const int kWidth = 1280;
1305 const int kHeight = 720;
1306 video_source_.set_adaptation_enabled(true);
1307 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001308 WaitForEncodedFrame(1);
asapersson36e9eb42017-03-31 05:29:12 -07001309 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1310 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1311 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1312
1313 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001314 video_stream_encoder_->TriggerQualityLow();
asapersson36e9eb42017-03-31 05:29:12 -07001315 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001316 WaitForEncodedFrame(2);
asapersson36e9eb42017-03-31 05:29:12 -07001317 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1318 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1319 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1320
1321 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001322 video_stream_encoder_->TriggerCpuOveruse();
asapersson36e9eb42017-03-31 05:29:12 -07001323 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001324 WaitForEncodedFrame(3);
asapersson36e9eb42017-03-31 05:29:12 -07001325 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1326 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1327 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1328
1329 // Set source with adaptation still enabled but quality scaler is off.
1330 fake_encoder_.SetQualityScaling(false);
mflodmancc3d4422017-08-03 08:27:51 -07001331 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001332 &video_source_,
1333 VideoSendStream::DegradationPreference::kMaintainFramerate);
asapersson36e9eb42017-03-31 05:29:12 -07001334
1335 video_source_.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001336 WaitForEncodedFrame(4);
asapersson36e9eb42017-03-31 05:29:12 -07001337 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1338 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1339 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1340
mflodmancc3d4422017-08-03 08:27:51 -07001341 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001342}
1343
mflodmancc3d4422017-08-03 08:27:51 -07001344TEST_F(VideoStreamEncoderTest,
1345 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
1346 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001347
asapersson0944a802017-04-07 00:57:58 -07001348 const int kWidth = 1280;
1349 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001350 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001351
asaperssonfab67072017-04-04 05:51:49 -07001352 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001353 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001354 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001355 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001356 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001357 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1358
asapersson02465b82017-04-10 01:12:52 -07001359 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001360 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001361 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001362 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001363 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001364 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001365 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001366 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1367
1368 // Set new source with adaptation still enabled.
1369 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001370 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001371 &new_video_source,
1372 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001373
1374 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001375 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001376 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001377 stats = stats_proxy_->GetStats();
1378 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001379 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001380 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1381
sprangc5d62e22017-04-02 23:53:04 -07001382 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001383 video_stream_encoder_->SetSource(
perkj803d97f2016-11-01 11:45:46 -07001384 &new_video_source,
1385 VideoSendStream::DegradationPreference::kMaintainResolution);
1386 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001387 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001388 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001389 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001390 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001391 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001392 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001393 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1394
sprangc5d62e22017-04-02 23:53:04 -07001395 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001396 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001397 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1398 mock_stats.input_frame_rate = 30;
1399 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001400 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001401 stats_proxy_->ResetMockStats();
1402
1403 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001404 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001405 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001406
1407 // Framerate now adapted.
1408 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001409 EXPECT_FALSE(stats.cpu_limited_resolution);
1410 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001411 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1412
1413 // Disable CPU adaptation.
mflodmancc3d4422017-08-03 08:27:51 -07001414 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001415 &new_video_source,
1416 VideoSendStream::DegradationPreference::kDegradationDisabled);
1417 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001418 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001419 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001420
1421 stats = stats_proxy_->GetStats();
1422 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001423 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001424 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1425
1426 // Try to trigger overuse. Should not succeed.
1427 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001428 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001429 stats_proxy_->ResetMockStats();
1430
1431 stats = stats_proxy_->GetStats();
1432 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001433 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001434 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1435
1436 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001437 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001438 &video_source_,
1439 VideoSendStream::DegradationPreference::kMaintainFramerate);
asaperssonfab67072017-04-04 05:51:49 -07001440 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001441 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001442 stats = stats_proxy_->GetStats();
1443 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001444 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001445 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001446
1447 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001448 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001449 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001450 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001451 stats = stats_proxy_->GetStats();
1452 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001453 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001454 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1455
1456 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001457 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001458 &new_video_source,
1459 VideoSendStream::DegradationPreference::kMaintainResolution);
1460 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001461 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001462 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001463 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001464 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001465 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001466 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001467 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1468
1469 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001470 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001471 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001472 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001473 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001474 stats = stats_proxy_->GetStats();
1475 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001476 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001477 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001478 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001479
mflodmancc3d4422017-08-03 08:27:51 -07001480 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001481}
1482
mflodmancc3d4422017-08-03 08:27:51 -07001483TEST_F(VideoStreamEncoderTest, StatsTracksPreferredBitrate) {
1484 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Erik Språng08127a92016-11-16 16:41:30 +01001485
asaperssonfab67072017-04-04 05:51:49 -07001486 const int kWidth = 1280;
1487 const int kHeight = 720;
1488 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001489 WaitForEncodedFrame(1);
Erik Språng08127a92016-11-16 16:41:30 +01001490
1491 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1492 EXPECT_EQ(video_encoder_config_.max_bitrate_bps,
1493 stats.preferred_media_bitrate_bps);
1494
mflodmancc3d4422017-08-03 08:27:51 -07001495 video_stream_encoder_->Stop();
Erik Språng08127a92016-11-16 16:41:30 +01001496}
1497
mflodmancc3d4422017-08-03 08:27:51 -07001498TEST_F(VideoStreamEncoderTest,
1499 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001500 const int kWidth = 1280;
1501 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001502 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001503
asaperssonfab67072017-04-04 05:51:49 -07001504 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001505 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001506
asaperssonfab67072017-04-04 05:51:49 -07001507 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001508 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001509
asaperssonfab67072017-04-04 05:51:49 -07001510 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001511 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001512
asaperssonfab67072017-04-04 05:51:49 -07001513 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001514 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001515
kthelgason876222f2016-11-29 01:44:11 -08001516 // Expect a scale down.
1517 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001518 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001519
asapersson02465b82017-04-10 01:12:52 -07001520 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001521 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001522 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001523 &new_video_source,
1524 VideoSendStream::DegradationPreference::kMaintainResolution);
1525
asaperssonfab67072017-04-04 05:51:49 -07001526 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001527 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001528 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001529 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001530
asaperssonfab67072017-04-04 05:51:49 -07001531 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001532 EXPECT_EQ(std::numeric_limits<int>::max(),
1533 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001534
asaperssonfab67072017-04-04 05:51:49 -07001535 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001536 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001537 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001538 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001539
asapersson02465b82017-04-10 01:12:52 -07001540 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001541 EXPECT_EQ(std::numeric_limits<int>::max(),
1542 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001543
mflodmancc3d4422017-08-03 08:27:51 -07001544 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001545}
1546
mflodmancc3d4422017-08-03 08:27:51 -07001547TEST_F(VideoStreamEncoderTest,
1548 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001549 const int kWidth = 1280;
1550 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001551 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001552
1553 // Enable kMaintainFramerate preference, no initial limitation.
1554 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001555 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001556 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1557
1558 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001559 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001560 VerifyNoLimitation(source.sink_wants());
1561 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1562 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1563
1564 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001565 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001566 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001567 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1568 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1569 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1570
1571 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001572 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001573 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1574 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1575 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1576
mflodmancc3d4422017-08-03 08:27:51 -07001577 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001578}
1579
mflodmancc3d4422017-08-03 08:27:51 -07001580TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001581 const int kWidth = 1280;
1582 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001583 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001584
1585 // Enable kBalanced preference, no initial limitation.
1586 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001587 video_stream_encoder_->SetSource(
1588 &source,
1589 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001590 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1591 sink_.WaitForEncodedFrame(1);
1592 VerifyNoLimitation(source.sink_wants());
1593
1594 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001595 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001596 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1597 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1598 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1599 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1600
1601 // Trigger adapt down for same input resolution, expect no change.
1602 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1603 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001604 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001605 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1606 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1607 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1608
1609 // Trigger adapt down for larger input resolution, expect no change.
1610 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1611 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001612 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001613 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1614 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1615 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1616
mflodmancc3d4422017-08-03 08:27:51 -07001617 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001618}
1619
mflodmancc3d4422017-08-03 08:27:51 -07001620TEST_F(VideoStreamEncoderTest,
1621 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001622 const int kWidth = 1280;
1623 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001624 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001625
1626 // Enable kMaintainFramerate preference, no initial limitation.
1627 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001628 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001629 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1630
1631 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001632 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001633 VerifyNoLimitation(source.sink_wants());
1634 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1635 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1636
1637 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001638 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001639 VerifyNoLimitation(source.sink_wants());
1640 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1641 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1642
mflodmancc3d4422017-08-03 08:27:51 -07001643 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001644}
1645
mflodmancc3d4422017-08-03 08:27:51 -07001646TEST_F(VideoStreamEncoderTest,
1647 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001648 const int kWidth = 1280;
1649 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001650 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001651
1652 // Enable kMaintainResolution preference, no initial limitation.
1653 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001654 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001655 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
1656
1657 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001658 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001659 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001660 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001661 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1662
1663 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001664 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001665 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001666 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001667 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1668
mflodmancc3d4422017-08-03 08:27:51 -07001669 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001670}
1671
mflodmancc3d4422017-08-03 08:27:51 -07001672TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001673 const int kWidth = 1280;
1674 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001675 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001676
1677 // Enable kBalanced preference, no initial limitation.
1678 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001679 video_stream_encoder_->SetSource(
1680 &source,
1681 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001682
1683 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1684 sink_.WaitForEncodedFrame(kWidth, kHeight);
1685 VerifyNoLimitation(source.sink_wants());
1686 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1687 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1688 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1689
1690 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001691 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001692 VerifyNoLimitation(source.sink_wants());
1693 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1694 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1695 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1696
mflodmancc3d4422017-08-03 08:27:51 -07001697 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001698}
1699
mflodmancc3d4422017-08-03 08:27:51 -07001700TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001701 const int kWidth = 1280;
1702 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001703 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001704
1705 // Enable kDegradationDisabled preference, no initial limitation.
1706 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001707 video_stream_encoder_->SetSource(
asapersson09f05612017-05-15 23:40:18 -07001708 &source, VideoSendStream::DegradationPreference::kDegradationDisabled);
1709
1710 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1711 sink_.WaitForEncodedFrame(kWidth, kHeight);
1712 VerifyNoLimitation(source.sink_wants());
1713 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1714 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1715 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1716
1717 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001718 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001719 VerifyNoLimitation(source.sink_wants());
1720 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1721 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1722 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1723
mflodmancc3d4422017-08-03 08:27:51 -07001724 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001725}
1726
mflodmancc3d4422017-08-03 08:27:51 -07001727TEST_F(VideoStreamEncoderTest,
1728 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001729 const int kWidth = 1280;
1730 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001731 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001732
1733 // Enable kMaintainFramerate preference, no initial limitation.
1734 AdaptingFrameForwarder source;
1735 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001736 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001737 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1738
1739 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001740 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001741 VerifyNoLimitation(source.sink_wants());
1742 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1743 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1744
1745 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001746 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001747 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001748 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001749 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001750 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1751 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1752
1753 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001754 video_stream_encoder_->TriggerQualityHigh();
asapersson02465b82017-04-10 01:12:52 -07001755 VerifyNoLimitation(source.sink_wants());
1756 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1757 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1758 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1759
mflodmancc3d4422017-08-03 08:27:51 -07001760 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001761}
1762
mflodmancc3d4422017-08-03 08:27:51 -07001763TEST_F(VideoStreamEncoderTest,
1764 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001765 const int kWidth = 1280;
1766 const int kHeight = 720;
1767 const int kInputFps = 30;
mflodmancc3d4422017-08-03 08:27:51 -07001768 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001769
1770 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1771 stats.input_frame_rate = kInputFps;
1772 stats_proxy_->SetMockStats(stats);
1773
1774 // Expect no scaling to begin with (preference: kMaintainFramerate).
1775 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1776 sink_.WaitForEncodedFrame(1);
1777 VerifyNoLimitation(video_source_.sink_wants());
1778
1779 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001780 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001781 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1782 sink_.WaitForEncodedFrame(2);
1783 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1784
1785 // Enable kMaintainResolution preference.
1786 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001787 video_stream_encoder_->SetSource(
asapersson09f05612017-05-15 23:40:18 -07001788 &new_video_source,
1789 VideoSendStream::DegradationPreference::kMaintainResolution);
1790 VerifyNoLimitation(new_video_source.sink_wants());
1791
1792 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001793 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001794 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1795 sink_.WaitForEncodedFrame(3);
1796 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1797
1798 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001799 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001800 VerifyNoLimitation(new_video_source.sink_wants());
1801
mflodmancc3d4422017-08-03 08:27:51 -07001802 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001803}
1804
mflodmancc3d4422017-08-03 08:27:51 -07001805TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001806 const int kWidth = 1280;
1807 const int kHeight = 720;
1808 const size_t kNumFrames = 10;
1809
mflodmancc3d4422017-08-03 08:27:51 -07001810 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001811
asaperssond0de2952017-04-21 01:47:31 -07001812 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001813 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001814 video_source_.set_adaptation_enabled(true);
1815
1816 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1817 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1818
1819 int downscales = 0;
1820 for (size_t i = 1; i <= kNumFrames; i++) {
1821 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001822 WaitForEncodedFrame(i);
asaperssond0de2952017-04-21 01:47:31 -07001823
asaperssonfab67072017-04-04 05:51:49 -07001824 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001825 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001826 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001827 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001828
1829 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1830 ++downscales;
1831
1832 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1833 EXPECT_EQ(downscales,
1834 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1835 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001836 }
mflodmancc3d4422017-08-03 08:27:51 -07001837 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001838}
1839
mflodmancc3d4422017-08-03 08:27:51 -07001840TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001841 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1842 const int kWidth = 1280;
1843 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001844 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001845
1846 // Enable kMaintainFramerate preference, no initial limitation.
1847 AdaptingFrameForwarder source;
1848 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001849 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07001850 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1851
1852 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001853 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001854 VerifyNoLimitation(source.sink_wants());
1855 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1856 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1857
1858 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001859 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001860 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001861 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001862 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001863 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1864 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1865
1866 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001867 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07001868 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001869 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001870 VerifyNoLimitation(source.sink_wants());
1871 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1872 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1873
1874 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001875 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001876 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001877 WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07001878 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001879 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1880 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1881
1882 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001883 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson09f05612017-05-15 23:40:18 -07001884 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1885 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001886 VerifyNoLimitation(source.sink_wants());
1887 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1888 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1889
mflodmancc3d4422017-08-03 08:27:51 -07001890 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001891}
1892
mflodmancc3d4422017-08-03 08:27:51 -07001893TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07001894 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
1895 const int kWidth = 1280;
1896 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001897 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001898
1899 // Enable kBalanced preference, no initial limitation.
1900 AdaptingFrameForwarder source;
1901 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001902 video_stream_encoder_->SetSource(
1903 &source,
1904 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001905
1906 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1907 sink_.WaitForEncodedFrame(kWidth, kHeight);
1908 VerifyNoLimitation(source.sink_wants());
1909 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1910 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1911
1912 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001913 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001914 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1915 sink_.WaitForEncodedFrame(2);
1916 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1917 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1918 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1919
1920 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001921 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001922 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1923 sink_.WaitForEncodedFrame(kWidth, kHeight);
1924 VerifyNoLimitation(source.sink_wants());
1925 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1926 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1927
1928 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001929 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001930 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
1931 sink_.WaitForEncodedFrame(4);
1932 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1933 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1934 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1935
1936 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001937 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001938 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1939 sink_.WaitForEncodedFrame(kWidth, kHeight);
1940 VerifyNoLimitation(source.sink_wants());
1941 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1942 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1943
mflodmancc3d4422017-08-03 08:27:51 -07001944 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001945}
1946
mflodmancc3d4422017-08-03 08:27:51 -07001947TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001948 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
1949 const int kWidth = 1280;
1950 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001951 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001952
1953 // Enable kMaintainFramerate preference, no initial limitation.
1954 AdaptingFrameForwarder source;
1955 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001956 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07001957 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1958
1959 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001960 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001961 VerifyNoLimitation(source.sink_wants());
1962 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1963 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1964 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1965 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1966
1967 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001968 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001969 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001970 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001971 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001972 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1973 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1974 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1975 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1976
1977 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07001978 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001979 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001980 WaitForEncodedFrame(3);
asapersson09f05612017-05-15 23:40:18 -07001981 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
1982 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07001983 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1984 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1985 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1986 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1987
1988 // Trigger cpu adapt down, max cpu downgrades reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001989 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001990 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001991 WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07001992 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07001993 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1994 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1995 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1996 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1997
1998 // Trigger quality adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07001999 video_stream_encoder_->TriggerQualityLow();
asaperssond0de2952017-04-21 01:47:31 -07002000 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002001 WaitForEncodedFrame(5);
asapersson09f05612017-05-15 23:40:18 -07002002 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002003 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2004 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2005 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2006 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2007
2008 // Trigger cpu adapt up, expect upscaled resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07002009 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07002010 source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002011 WaitForEncodedFrame(6);
asapersson09f05612017-05-15 23:40:18 -07002012 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002013 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2014 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2015 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2016 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2017
2018 // Trigger cpu adapt up, expect upscaled resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002019 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07002020 source.IncomingCapturedFrame(CreateFrame(7, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002021 WaitForEncodedFrame(7);
asapersson09f05612017-05-15 23:40:18 -07002022 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002023 last_wants = source.sink_wants();
2024 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2025 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2026 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2027 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2028
2029 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002030 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07002031 source.IncomingCapturedFrame(CreateFrame(8, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002032 WaitForEncodedFrame(8);
asapersson09f05612017-05-15 23:40:18 -07002033 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002034 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2035 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2036 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2037 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2038
2039 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002040 video_stream_encoder_->TriggerQualityHigh();
asaperssond0de2952017-04-21 01:47:31 -07002041 source.IncomingCapturedFrame(CreateFrame(9, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002042 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002043 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002044 VerifyNoLimitation(source.sink_wants());
2045 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2046 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2047 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2048 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002049
mflodmancc3d4422017-08-03 08:27:51 -07002050 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002051}
2052
mflodmancc3d4422017-08-03 08:27:51 -07002053TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002054 const int kWidth = 640;
2055 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002056
mflodmancc3d4422017-08-03 08:27:51 -07002057 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002058
perkj803d97f2016-11-01 11:45:46 -07002059 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002060 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002061 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002062 }
2063
mflodmancc3d4422017-08-03 08:27:51 -07002064 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002065 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002066 video_source_.IncomingCapturedFrame(CreateFrame(
2067 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002068 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002069 }
2070
mflodmancc3d4422017-08-03 08:27:51 -07002071 video_stream_encoder_->Stop();
2072 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002073 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002074
perkj803d97f2016-11-01 11:45:46 -07002075 EXPECT_EQ(1,
2076 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2077 EXPECT_EQ(
2078 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2079}
2080
mflodmancc3d4422017-08-03 08:27:51 -07002081TEST_F(VideoStreamEncoderTest,
2082 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2083 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002084 const int kWidth = 640;
2085 const int kHeight = 360;
2086
mflodmancc3d4422017-08-03 08:27:51 -07002087 video_stream_encoder_->SetSource(
asaperssonf4e44af2017-04-19 02:01:06 -07002088 &video_source_,
2089 VideoSendStream::DegradationPreference::kDegradationDisabled);
2090
2091 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2092 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002093 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002094 }
2095
mflodmancc3d4422017-08-03 08:27:51 -07002096 video_stream_encoder_->Stop();
2097 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002098 stats_proxy_.reset();
2099
2100 EXPECT_EQ(0,
2101 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2102}
2103
mflodmancc3d4422017-08-03 08:27:51 -07002104TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002105 MockBitrateObserver bitrate_observer;
mflodmancc3d4422017-08-03 08:27:51 -07002106 video_stream_encoder_->SetBitrateObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002107
2108 const int kDefaultFps = 30;
2109 const BitrateAllocation expected_bitrate =
2110 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002111 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002112
2113 // First called on bitrate updated, then again on first frame.
2114 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2115 .Times(2);
mflodmancc3d4422017-08-03 08:27:51 -07002116 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002117
2118 const int64_t kStartTimeMs = 1;
2119 video_source_.IncomingCapturedFrame(
2120 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002121 WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002122
2123 // Not called on second frame.
2124 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2125 .Times(0);
2126 video_source_.IncomingCapturedFrame(
2127 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002128 WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002129
2130 // Called after a process interval.
2131 const int64_t kProcessIntervalMs =
2132 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang4847ae62017-06-27 07:06:52 -07002133 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec *
2134 (kProcessIntervalMs + (1000 / kDefaultFps)));
sprang57c2fff2017-01-16 06:24:02 -08002135 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2136 .Times(1);
2137 video_source_.IncomingCapturedFrame(CreateFrame(
2138 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002139 WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002140
mflodmancc3d4422017-08-03 08:27:51 -07002141 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002142}
2143
mflodmancc3d4422017-08-03 08:27:51 -07002144TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
sprangfda496a2017-06-15 04:21:07 -07002145 const int kFrameWidth = 1280;
2146 const int kFrameHeight = 720;
2147 const int kFramerate = 24;
2148
mflodmancc3d4422017-08-03 08:27:51 -07002149 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002150 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002151 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002152 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2153
2154 // Insert a single frame, triggering initial configuration.
2155 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002156 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002157
mflodmancc3d4422017-08-03 08:27:51 -07002158 EXPECT_EQ(
2159 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2160 kDefaultFramerate);
sprangfda496a2017-06-15 04:21:07 -07002161
2162 // Trigger reconfigure encoder (without resetting the entire instance).
2163 VideoEncoderConfig video_encoder_config;
2164 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2165 video_encoder_config.number_of_streams = 1;
2166 video_encoder_config.video_stream_factory =
2167 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07002168 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2169 kMaxPayloadLength, false);
2170 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002171
2172 // Detector should be updated with fps limit from codec config.
mflodmancc3d4422017-08-03 08:27:51 -07002173 EXPECT_EQ(
2174 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2175 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002176
2177 // Trigger overuse, max framerate should be reduced.
2178 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2179 stats.input_frame_rate = kFramerate;
2180 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002181 video_stream_encoder_->TriggerCpuOveruse();
2182 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002183 int adapted_framerate =
mflodmancc3d4422017-08-03 08:27:51 -07002184 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002185 EXPECT_LT(adapted_framerate, kFramerate);
2186
2187 // Trigger underuse, max framerate should go back to codec configured fps.
2188 // Set extra low fps, to make sure it's actually reset, not just incremented.
2189 stats = stats_proxy_->GetStats();
2190 stats.input_frame_rate = adapted_framerate / 2;
2191 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002192 video_stream_encoder_->TriggerCpuNormalUsage();
2193 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2194 EXPECT_EQ(
2195 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2196 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002197
mflodmancc3d4422017-08-03 08:27:51 -07002198 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002199}
2200
mflodmancc3d4422017-08-03 08:27:51 -07002201TEST_F(VideoStreamEncoderTest,
2202 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
sprangfda496a2017-06-15 04:21:07 -07002203 const int kFrameWidth = 1280;
2204 const int kFrameHeight = 720;
2205 const int kLowFramerate = 15;
2206 const int kHighFramerate = 25;
2207
mflodmancc3d4422017-08-03 08:27:51 -07002208 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002209 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002210 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002211 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2212
2213 // Trigger initial configuration.
2214 VideoEncoderConfig video_encoder_config;
2215 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2216 video_encoder_config.number_of_streams = 1;
2217 video_encoder_config.video_stream_factory =
2218 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2219 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002220 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2221 kMaxPayloadLength, false);
2222 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002223
mflodmancc3d4422017-08-03 08:27:51 -07002224 EXPECT_EQ(
2225 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2226 kLowFramerate);
sprangfda496a2017-06-15 04:21:07 -07002227
2228 // Trigger overuse, max framerate should be reduced.
2229 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2230 stats.input_frame_rate = kLowFramerate;
2231 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002232 video_stream_encoder_->TriggerCpuOveruse();
2233 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002234 int adapted_framerate =
mflodmancc3d4422017-08-03 08:27:51 -07002235 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002236 EXPECT_LT(adapted_framerate, kLowFramerate);
2237
2238 // Reconfigure the encoder with a new (higher max framerate), max fps should
2239 // still respect the adaptation.
2240 video_encoder_config.video_stream_factory =
2241 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2242 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002243 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2244 kMaxPayloadLength, false);
2245 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002246
mflodmancc3d4422017-08-03 08:27:51 -07002247 EXPECT_EQ(
2248 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2249 adapted_framerate);
sprangfda496a2017-06-15 04:21:07 -07002250
2251 // Trigger underuse, max framerate should go back to codec configured fps.
2252 stats = stats_proxy_->GetStats();
2253 stats.input_frame_rate = adapted_framerate;
2254 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002255 video_stream_encoder_->TriggerCpuNormalUsage();
2256 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2257 EXPECT_EQ(
2258 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2259 kHighFramerate);
sprangfda496a2017-06-15 04:21:07 -07002260
mflodmancc3d4422017-08-03 08:27:51 -07002261 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002262}
2263
mflodmancc3d4422017-08-03 08:27:51 -07002264TEST_F(VideoStreamEncoderTest,
2265 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002266 const int kFrameWidth = 1280;
2267 const int kFrameHeight = 720;
2268 const int kFramerate = 24;
2269
mflodmancc3d4422017-08-03 08:27:51 -07002270 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002271 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002272 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002273 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2274
2275 // Trigger initial configuration.
2276 VideoEncoderConfig video_encoder_config;
2277 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2278 video_encoder_config.number_of_streams = 1;
2279 video_encoder_config.video_stream_factory =
2280 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2281 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002282 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2283 kMaxPayloadLength, false);
2284 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002285
mflodmancc3d4422017-08-03 08:27:51 -07002286 EXPECT_EQ(
2287 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2288 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002289
2290 // Trigger overuse, max framerate should be reduced.
2291 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2292 stats.input_frame_rate = kFramerate;
2293 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002294 video_stream_encoder_->TriggerCpuOveruse();
2295 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002296 int adapted_framerate =
mflodmancc3d4422017-08-03 08:27:51 -07002297 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002298 EXPECT_LT(adapted_framerate, kFramerate);
2299
2300 // Change degradation preference to not enable framerate scaling. Target
2301 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002302 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002303 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07002304 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2305 EXPECT_EQ(
2306 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2307 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002308
mflodmancc3d4422017-08-03 08:27:51 -07002309 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002310}
2311
mflodmancc3d4422017-08-03 08:27:51 -07002312TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002313 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002314 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002315 const int kWidth = 640;
2316 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002317
asaperssonfab67072017-04-04 05:51:49 -07002318 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002319
2320 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002321 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002322
2323 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002324 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002325
sprangc5d62e22017-04-02 23:53:04 -07002326 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002327
asaperssonfab67072017-04-04 05:51:49 -07002328 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002329 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002330 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002331
2332 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002333 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002334
sprangc5d62e22017-04-02 23:53:04 -07002335 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002336
mflodmancc3d4422017-08-03 08:27:51 -07002337 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002338}
2339
mflodmancc3d4422017-08-03 08:27:51 -07002340TEST_F(VideoStreamEncoderTest,
2341 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002342 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002343 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002344 const int kWidth = 640;
2345 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002346
2347 // We expect the n initial frames to get dropped.
2348 int i;
2349 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002350 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002351 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002352 }
2353 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002354 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002355 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002356
2357 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002358 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002359
mflodmancc3d4422017-08-03 08:27:51 -07002360 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002361}
2362
mflodmancc3d4422017-08-03 08:27:51 -07002363TEST_F(VideoStreamEncoderTest,
2364 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002365 const int kWidth = 640;
2366 const int kHeight = 360;
mflodmancc3d4422017-08-03 08:27:51 -07002367 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002368
2369 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002370 video_stream_encoder_->SetSource(
kthelgason2bc68642017-02-07 07:02:22 -08002371 &video_source_,
2372 VideoSendStream::DegradationPreference::kMaintainResolution);
2373
asaperssonfab67072017-04-04 05:51:49 -07002374 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002375 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002376 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002377
mflodmancc3d4422017-08-03 08:27:51 -07002378 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002379}
2380
mflodmancc3d4422017-08-03 08:27:51 -07002381TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002382 const int kWidth = 640;
2383 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002384 fake_encoder_.SetQualityScaling(false);
mflodmancc3d4422017-08-03 08:27:51 -07002385 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002386
kthelgasonb83797b2017-02-14 11:57:25 -08002387 // Force quality scaler reconfiguration by resetting the source.
mflodmancc3d4422017-08-03 08:27:51 -07002388 video_stream_encoder_->SetSource(
2389 &video_source_,
2390 VideoSendStream::DegradationPreference::kBalanced);
kthelgasonad9010c2017-02-14 00:46:51 -08002391
asaperssonfab67072017-04-04 05:51:49 -07002392 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002393 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002394 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002395
mflodmancc3d4422017-08-03 08:27:51 -07002396 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002397 fake_encoder_.SetQualityScaling(true);
2398}
2399
mflodmancc3d4422017-08-03 08:27:51 -07002400TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002401 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2402 const int kTooSmallWidth = 10;
2403 const int kTooSmallHeight = 10;
mflodmancc3d4422017-08-03 08:27:51 -07002404 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002405
2406 // Enable kMaintainFramerate preference, no initial limitation.
2407 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002408 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07002409 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
2410 VerifyNoLimitation(source.sink_wants());
2411 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2412
2413 // Trigger adapt down, too small frame, expect no change.
2414 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002415 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002416 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002417 VerifyNoLimitation(source.sink_wants());
2418 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2419 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2420
mflodmancc3d4422017-08-03 08:27:51 -07002421 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002422}
2423
mflodmancc3d4422017-08-03 08:27:51 -07002424TEST_F(VideoStreamEncoderTest,
2425 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002426 const int kTooSmallWidth = 10;
2427 const int kTooSmallHeight = 10;
2428 const int kFpsLimit = 7;
mflodmancc3d4422017-08-03 08:27:51 -07002429 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002430
2431 // Enable kBalanced preference, no initial limitation.
2432 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002433 video_stream_encoder_->SetSource(
2434 &source,
2435 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002436 VerifyNoLimitation(source.sink_wants());
2437 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2438 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2439
2440 // Trigger adapt down, expect limited framerate.
2441 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002442 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002443 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002444 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2445 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2446 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2447 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2448
2449 // Trigger adapt down, too small frame, expect no change.
2450 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002451 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002452 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002453 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2454 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2455 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2456 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2457
mflodmancc3d4422017-08-03 08:27:51 -07002458 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002459}
2460
mflodmancc3d4422017-08-03 08:27:51 -07002461TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002462 fake_encoder_.ForceInitEncodeFailure(true);
mflodmancc3d4422017-08-03 08:27:51 -07002463 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
emircan7b532db2017-08-17 18:20:40 -07002464 ResetEncoder("VP8", 2, 1, true, false);
asapersson02465b82017-04-10 01:12:52 -07002465 const int kFrameWidth = 1280;
2466 const int kFrameHeight = 720;
2467 video_source_.IncomingCapturedFrame(
2468 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002469 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002470 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002471}
2472
sprangb1ca0732017-02-01 08:38:12 -08002473// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002474TEST_F(VideoStreamEncoderTest,
2475 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
2476 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002477
2478 const int kFrameWidth = 1280;
2479 const int kFrameHeight = 720;
2480 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002481 // requested by
2482 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002483 video_source_.set_adaptation_enabled(true);
2484
2485 video_source_.IncomingCapturedFrame(
2486 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002487 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002488
2489 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002490 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002491 video_source_.IncomingCapturedFrame(
2492 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002493 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002494
asaperssonfab67072017-04-04 05:51:49 -07002495 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002496 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002497 video_source_.IncomingCapturedFrame(
2498 CreateFrame(3, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002499 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002500
mflodmancc3d4422017-08-03 08:27:51 -07002501 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002502}
sprangfe627f32017-03-29 08:24:59 -07002503
mflodmancc3d4422017-08-03 08:27:51 -07002504TEST_F(VideoStreamEncoderTest,
2505 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002506 const int kFrameWidth = 1280;
2507 const int kFrameHeight = 720;
sprang4847ae62017-06-27 07:06:52 -07002508 int kFrameIntervalMs = rtc::kNumMillisecsPerSec / max_framerate_;
sprangc5d62e22017-04-02 23:53:04 -07002509
mflodmancc3d4422017-08-03 08:27:51 -07002510 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2511 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07002512 &video_source_,
2513 VideoSendStream::DegradationPreference::kMaintainResolution);
2514 video_source_.set_adaptation_enabled(true);
2515
sprang4847ae62017-06-27 07:06:52 -07002516 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002517
2518 video_source_.IncomingCapturedFrame(
2519 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002520 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002521
2522 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002523 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002524
2525 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002526 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002527 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002528 video_source_.IncomingCapturedFrame(
2529 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002530 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002531 }
2532
2533 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002534 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002535 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002536 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002537 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002538 video_source_.IncomingCapturedFrame(
2539 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002540 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002541 ++num_frames_dropped;
2542 } else {
2543 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2544 }
2545 }
2546
sprang4847ae62017-06-27 07:06:52 -07002547 // Add some slack to account for frames dropped by the frame dropper.
2548 const int kErrorMargin = 1;
2549 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002550 kErrorMargin);
2551
2552 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002553 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002554 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002555 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002556 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002557 video_source_.IncomingCapturedFrame(
2558 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002559 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002560 ++num_frames_dropped;
2561 } else {
2562 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2563 }
2564 }
sprang4847ae62017-06-27 07:06:52 -07002565 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002566 kErrorMargin);
2567
2568 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002569 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002570 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002571 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002572 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002573 video_source_.IncomingCapturedFrame(
2574 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002575 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002576 ++num_frames_dropped;
2577 } else {
2578 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2579 }
2580 }
sprang4847ae62017-06-27 07:06:52 -07002581 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002582 kErrorMargin);
2583
2584 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002585 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002586 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002587 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002588 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002589 video_source_.IncomingCapturedFrame(
2590 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002591 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002592 ++num_frames_dropped;
2593 } else {
2594 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2595 }
2596 }
2597 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2598
mflodmancc3d4422017-08-03 08:27:51 -07002599 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002600}
2601
mflodmancc3d4422017-08-03 08:27:51 -07002602TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002603 const int kFramerateFps = 5;
2604 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
2605 const int kMinFpsFrameInterval = rtc::kNumMillisecsPerSec / kMinFramerateFps;
2606 const int kFrameWidth = 1280;
2607 const int kFrameHeight = 720;
2608
sprang4847ae62017-06-27 07:06:52 -07002609 // Reconfigure encoder with two temporal layers and screensharing, which will
2610 // disable frame dropping and make testing easier.
emircan7b532db2017-08-17 18:20:40 -07002611 ResetEncoder("VP8", 1, 2, true, true);
sprang4847ae62017-06-27 07:06:52 -07002612
mflodmancc3d4422017-08-03 08:27:51 -07002613 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2614 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07002615 &video_source_,
2616 VideoSendStream::DegradationPreference::kMaintainResolution);
2617 video_source_.set_adaptation_enabled(true);
2618
sprang4847ae62017-06-27 07:06:52 -07002619 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002620
2621 // Trigger overuse as much as we can.
mflodmancc3d4422017-08-03 08:27:51 -07002622 for (int i = 0; i < VideoStreamEncoder::kMaxCpuResolutionDowngrades; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002623 // Insert frames to get a new fps estimate...
2624 for (int j = 0; j < kFramerateFps; ++j) {
2625 video_source_.IncomingCapturedFrame(
2626 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
2627 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002628 }
2629 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002630 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002631 }
2632
2633 // Drain any frame in the pipeline.
sprang4847ae62017-06-27 07:06:52 -07002634 WaitForFrame(kDefaultTimeoutMs);
sprangc5d62e22017-04-02 23:53:04 -07002635
2636 // Insert frames at min fps, all should go through.
2637 for (int i = 0; i < 10; ++i) {
2638 timestamp_ms += kMinFpsFrameInterval;
sprangc5d62e22017-04-02 23:53:04 -07002639 video_source_.IncomingCapturedFrame(
2640 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002641 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002642 }
asaperssonf7e294d2017-06-13 23:25:22 -07002643
mflodmancc3d4422017-08-03 08:27:51 -07002644 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002645}
asaperssonf7e294d2017-06-13 23:25:22 -07002646
mflodmancc3d4422017-08-03 08:27:51 -07002647TEST_F(VideoStreamEncoderTest,
2648 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002649 const int kWidth = 1280;
2650 const int kHeight = 720;
2651 const int64_t kFrameIntervalMs = 150;
2652 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002653 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002654
2655 // Enable kBalanced preference, no initial limitation.
2656 AdaptingFrameForwarder source;
2657 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002658 video_stream_encoder_->SetSource(
2659 &source,
2660 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002661 timestamp_ms += kFrameIntervalMs;
2662 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002663 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002664 VerifyNoLimitation(source.sink_wants());
2665 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2666 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2667 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2668
2669 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002670 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002671 timestamp_ms += kFrameIntervalMs;
2672 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002673 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002674 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2675 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2676 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2677 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2678
2679 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002680 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002681 timestamp_ms += kFrameIntervalMs;
2682 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002683 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002684 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2685 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2686 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2687 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2688
2689 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002690 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002691 timestamp_ms += kFrameIntervalMs;
2692 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002693 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002694 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2695 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2696 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2697 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2698
2699 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002700 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002701 timestamp_ms += kFrameIntervalMs;
2702 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002703 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002704 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2705 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2706 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2707 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2708
2709 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002710 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002711 timestamp_ms += kFrameIntervalMs;
2712 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002713 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002714 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2715 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2716 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2717 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2718
2719 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002720 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002721 timestamp_ms += kFrameIntervalMs;
2722 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002723 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002724 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2725 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2726 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2727 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2728
2729 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002730 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002731 timestamp_ms += kFrameIntervalMs;
2732 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002733 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002734 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2735 rtc::VideoSinkWants last_wants = source.sink_wants();
2736 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2737 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2738 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2739
2740 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002741 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002742 timestamp_ms += kFrameIntervalMs;
2743 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002744 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002745 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2746 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2747 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2748 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2749
2750 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002751 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002752 timestamp_ms += kFrameIntervalMs;
2753 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002754 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002755 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2756 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2757 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2758 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2759
2760 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002761 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002762 timestamp_ms += kFrameIntervalMs;
2763 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002764 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002765 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2766 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2767 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2768 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2769
2770 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002771 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002772 timestamp_ms += kFrameIntervalMs;
2773 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002774 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002775 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2776 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2777 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2778 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2779
2780 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002781 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002782 timestamp_ms += kFrameIntervalMs;
2783 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002784 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002785 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2786 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2787 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2788 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2789
2790 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002791 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002792 timestamp_ms += kFrameIntervalMs;
2793 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002794 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002795 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2796 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2797 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2798 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2799
2800 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002801 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002802 timestamp_ms += kFrameIntervalMs;
2803 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002804 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002805 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2806 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2807 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2808 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2809
2810 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002811 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002812 timestamp_ms += kFrameIntervalMs;
2813 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002814 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002815 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2816 VerifyNoLimitation(source.sink_wants());
2817 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2818 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2819 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2820
2821 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002822 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002823 VerifyNoLimitation(source.sink_wants());
2824 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2825
mflodmancc3d4422017-08-03 08:27:51 -07002826 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002827}
2828
mflodmancc3d4422017-08-03 08:27:51 -07002829TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07002830 const int kWidth = 1280;
2831 const int kHeight = 720;
2832 const int64_t kFrameIntervalMs = 150;
2833 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002834 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002835
2836 // Enable kBalanced preference, no initial limitation.
2837 AdaptingFrameForwarder source;
2838 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002839 video_stream_encoder_->SetSource(
2840 &source,
2841 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002842 timestamp_ms += kFrameIntervalMs;
2843 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002844 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002845 VerifyNoLimitation(source.sink_wants());
2846 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2847 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2848 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2849 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2850 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2851 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2852
2853 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002854 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002855 timestamp_ms += kFrameIntervalMs;
2856 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002857 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002858 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2859 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2860 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2861 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2862 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2863 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2864 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2865
2866 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002867 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002868 timestamp_ms += kFrameIntervalMs;
2869 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002870 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002871 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2872 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2873 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2874 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2875 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2876 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2877 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2878
2879 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002880 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002881 timestamp_ms += kFrameIntervalMs;
2882 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002883 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002884 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2885 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2886 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2887 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2888 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2889 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2890 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2891
2892 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002893 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002894 timestamp_ms += kFrameIntervalMs;
2895 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002896 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002897 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2898 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2899 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2900 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2901 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2902 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2903 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2904
2905 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002906 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002907 timestamp_ms += kFrameIntervalMs;
2908 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002909 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002910 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2911 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2912 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2913 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2914 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2915 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2916 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2917
2918 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002919 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002920 timestamp_ms += kFrameIntervalMs;
2921 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002922 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002923 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2924 VerifyNoLimitation(source.sink_wants());
2925 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2926 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2927 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2928 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2929 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2930 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2931
2932 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002933 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002934 VerifyNoLimitation(source.sink_wants());
2935 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2936 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2937
mflodmancc3d4422017-08-03 08:27:51 -07002938 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002939}
2940
mflodmancc3d4422017-08-03 08:27:51 -07002941TEST_F(VideoStreamEncoderTest,
2942 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07002943 const int kWidth = 640;
2944 const int kHeight = 360;
2945 const int kFpsLimit = 15;
2946 const int64_t kFrameIntervalMs = 150;
2947 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002948 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002949
2950 // Enable kBalanced preference, no initial limitation.
2951 AdaptingFrameForwarder source;
2952 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002953 video_stream_encoder_->SetSource(
2954 &source,
2955 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002956 timestamp_ms += kFrameIntervalMs;
2957 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002958 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002959 VerifyNoLimitation(source.sink_wants());
2960 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2961 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2962 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2963 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2964 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2965 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2966
2967 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002968 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002969 timestamp_ms += kFrameIntervalMs;
2970 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002971 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002972 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2973 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2974 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2975 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2976 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2977 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2978 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2979
2980 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002981 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002982 timestamp_ms += kFrameIntervalMs;
2983 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002984 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002985 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2986 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2987 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2988 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2989 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2990 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2991 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2992
2993 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002994 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002995 timestamp_ms += kFrameIntervalMs;
2996 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002997 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002998 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2999 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3000 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3001 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3002 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3003 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3004 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3005
3006 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003007 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003008 timestamp_ms += kFrameIntervalMs;
3009 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003010 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003011 VerifyNoLimitation(source.sink_wants());
3012 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3013 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3014 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3015 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3016 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3017 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3018
3019 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003020 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003021 VerifyNoLimitation(source.sink_wants());
3022 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3023 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3024
mflodmancc3d4422017-08-03 08:27:51 -07003025 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003026}
3027
mflodmancc3d4422017-08-03 08:27:51 -07003028TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003029 // Simulates simulcast behavior and makes highest stream resolutions divisible
3030 // by 4.
3031 class CroppingVideoStreamFactory
3032 : public VideoEncoderConfig::VideoStreamFactoryInterface {
3033 public:
3034 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
3035 int framerate)
3036 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
3037 EXPECT_GT(num_temporal_layers, 0u);
3038 EXPECT_GT(framerate, 0);
3039 }
3040
3041 private:
3042 std::vector<VideoStream> CreateEncoderStreams(
3043 int width,
3044 int height,
3045 const VideoEncoderConfig& encoder_config) override {
3046 std::vector<VideoStream> streams =
3047 test::CreateVideoStreams(width - width % 4, height - height % 4,
3048 encoder_config);
3049 for (VideoStream& stream : streams) {
3050 stream.temporal_layer_thresholds_bps.resize(num_temporal_layers_ - 1);
3051 stream.max_framerate = framerate_;
3052 }
3053 return streams;
3054 }
3055
3056 const size_t num_temporal_layers_;
3057 const int framerate_;
3058 };
3059
3060 const int kFrameWidth = 1920;
3061 const int kFrameHeight = 1080;
3062 // 3/4 of 1920.
3063 const int kAdaptedFrameWidth = 1440;
3064 // 3/4 of 1080 rounded down to multiple of 4.
3065 const int kAdaptedFrameHeight = 808;
3066 const int kFramerate = 24;
3067
mflodmancc3d4422017-08-03 08:27:51 -07003068 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003069 // Trigger reconfigure encoder (without resetting the entire instance).
3070 VideoEncoderConfig video_encoder_config;
3071 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3072 video_encoder_config.number_of_streams = 1;
3073 video_encoder_config.video_stream_factory =
3074 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003075 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
3076 kMaxPayloadLength, false);
3077 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003078
3079 video_source_.set_adaptation_enabled(true);
3080
3081 video_source_.IncomingCapturedFrame(
3082 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003083 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003084
3085 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003086 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003087 video_source_.IncomingCapturedFrame(
3088 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003089 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003090
mflodmancc3d4422017-08-03 08:27:51 -07003091 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003092}
3093
mflodmancc3d4422017-08-03 08:27:51 -07003094TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003095 const int kFrameWidth = 1280;
3096 const int kFrameHeight = 720;
3097 const int kLowFps = 2;
3098 const int kHighFps = 30;
3099
mflodmancc3d4422017-08-03 08:27:51 -07003100 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003101
3102 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3103 max_framerate_ = kLowFps;
3104
3105 // Insert 2 seconds of 2fps video.
3106 for (int i = 0; i < kLowFps * 2; ++i) {
3107 video_source_.IncomingCapturedFrame(
3108 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3109 WaitForEncodedFrame(timestamp_ms);
3110 timestamp_ms += 1000 / kLowFps;
3111 }
3112
3113 // Make sure encoder is updated with new target.
mflodmancc3d4422017-08-03 08:27:51 -07003114 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003115 video_source_.IncomingCapturedFrame(
3116 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3117 WaitForEncodedFrame(timestamp_ms);
3118 timestamp_ms += 1000 / kLowFps;
3119
3120 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3121
3122 // Insert 30fps frames for just a little more than the forced update period.
3123 const int kVcmTimerIntervalFrames =
3124 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3125 const int kFrameIntervalMs = 1000 / kHighFps;
3126 max_framerate_ = kHighFps;
3127 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3128 video_source_.IncomingCapturedFrame(
3129 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3130 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3131 // be dropped if the encoder hans't been updated with the new higher target
3132 // framerate yet, causing it to overshoot the target bitrate and then
3133 // suffering the wrath of the media optimizer.
3134 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3135 timestamp_ms += kFrameIntervalMs;
3136 }
3137
3138 // Don expect correct measurement just yet, but it should be higher than
3139 // before.
3140 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3141
mflodmancc3d4422017-08-03 08:27:51 -07003142 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003143}
3144
mflodmancc3d4422017-08-03 08:27:51 -07003145TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003146 const int kFrameWidth = 1280;
3147 const int kFrameHeight = 720;
3148 const int kTargetBitrateBps = 1000000;
3149
3150 MockBitrateObserver bitrate_observer;
mflodmancc3d4422017-08-03 08:27:51 -07003151 video_stream_encoder_->SetBitrateObserver(&bitrate_observer);
sprang4847ae62017-06-27 07:06:52 -07003152
3153 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3154 // Initial bitrate update.
mflodmancc3d4422017-08-03 08:27:51 -07003155 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3156 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003157
3158 // Insert a first video frame, causes another bitrate update.
3159 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3160 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3161 video_source_.IncomingCapturedFrame(
3162 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3163 WaitForEncodedFrame(timestamp_ms);
3164
3165 // Next, simulate video suspension due to pacer queue overrun.
mflodmancc3d4422017-08-03 08:27:51 -07003166 video_stream_encoder_->OnBitrateUpdated(0, 0, 1);
sprang4847ae62017-06-27 07:06:52 -07003167
3168 // Skip ahead until a new periodic parameter update should have occured.
3169 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3170 fake_clock_.AdvanceTimeMicros(
3171 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3172 rtc::kNumMicrosecsPerMillisec);
3173
3174 // Bitrate observer should not be called.
3175 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3176 video_source_.IncomingCapturedFrame(
3177 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3178 ExpectDroppedFrame();
3179
mflodmancc3d4422017-08-03 08:27:51 -07003180 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003181}
ilnik6b826ef2017-06-16 06:53:48 -07003182
perkj26091b12016-09-01 01:17:40 -07003183} // namespace webrtc