blob: d7d09db7aad8d1379a65f984dddf6369815a95bb [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 -080032// TODO(kthelgason): Lower this limit when better testing
33// on MediaCodec and fallback implementations are in place.
34const int kMinPixelsPerFrame = 320 * 180;
sprangc5d62e22017-04-02 23:53:04 -070035const int kMinFramerateFps = 2;
36const int64_t kFrameTimeoutMs = 100;
37} // namespace
kthelgason33ce8892016-12-09 03:53:59 -080038
perkj26091b12016-09-01 01:17:40 -070039namespace webrtc {
40
kthelgason876222f2016-11-29 01:44:11 -080041using DegredationPreference = VideoSendStream::DegradationPreference;
sprangb1ca0732017-02-01 08:38:12 -080042using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080043using ::testing::_;
44using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080045
perkj803d97f2016-11-01 11:45:46 -070046namespace {
asapersson5f7226f2016-11-25 04:37:00 -080047const size_t kMaxPayloadLength = 1440;
kthelgason2bc68642017-02-07 07:02:22 -080048const int kTargetBitrateBps = 1000000;
49const int kLowTargetBitrateBps = kTargetBitrateBps / 10;
50const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070051const int kDefaultFramerate = 30;
asapersson5f7226f2016-11-25 04:37:00 -080052
perkj803d97f2016-11-01 11:45:46 -070053class TestBuffer : public webrtc::I420Buffer {
54 public:
55 TestBuffer(rtc::Event* event, int width, int height)
56 : I420Buffer(width, height), event_(event) {}
57
58 private:
59 friend class rtc::RefCountedObject<TestBuffer>;
60 ~TestBuffer() override {
61 if (event_)
62 event_->Set();
63 }
64 rtc::Event* const event_;
65};
66
sprangfda496a2017-06-15 04:21:07 -070067class CpuOveruseDetectorProxy : public OveruseFrameDetector {
68 public:
69 CpuOveruseDetectorProxy(const CpuOveruseOptions& options,
70 AdaptationObserverInterface* overuse_observer,
71 EncodedFrameObserver* encoder_timing_,
72 CpuOveruseMetricsObserver* metrics_observer)
73 : OveruseFrameDetector(options,
74 overuse_observer,
75 encoder_timing_,
76 metrics_observer),
77 last_target_framerate_fps_(-1) {}
78 virtual ~CpuOveruseDetectorProxy() {}
79
80 void OnTargetFramerateUpdated(int framerate_fps) override {
81 rtc::CritScope cs(&lock_);
82 last_target_framerate_fps_ = framerate_fps;
83 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
84 }
85
86 int GetLastTargetFramerate() {
87 rtc::CritScope cs(&lock_);
88 return last_target_framerate_fps_;
89 }
90
91 private:
92 rtc::CriticalSection lock_;
93 int last_target_framerate_fps_ GUARDED_BY(lock_);
94};
95
mflodmancc3d4422017-08-03 08:27:51 -070096class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -070097 public:
mflodmancc3d4422017-08-03 08:27:51 -070098 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
kthelgason876222f2016-11-29 01:44:11 -080099 const VideoSendStream::Config::EncoderSettings& settings)
mflodmancc3d4422017-08-03 08:27:51 -0700100 : VideoStreamEncoder(
101 1 /* number_of_cores */,
102 stats_proxy,
103 settings,
104 nullptr /* pre_encode_callback */,
105 nullptr /* encoder_timing */,
106 std::unique_ptr<OveruseFrameDetector>(
107 overuse_detector_proxy_ = new CpuOveruseDetectorProxy(
108 GetCpuOveruseOptions(settings.full_overuse_time),
109 this,
110 nullptr,
111 stats_proxy))) {}
perkj803d97f2016-11-01 11:45:46 -0700112
sprangb1ca0732017-02-01 08:38:12 -0800113 void PostTaskAndWait(bool down, AdaptReason reason) {
perkj803d97f2016-11-01 11:45:46 -0700114 rtc::Event event(false, false);
kthelgason876222f2016-11-29 01:44:11 -0800115 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800116 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700117 event.Set();
118 });
perkj070ba852017-02-16 15:46:27 -0800119 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700120 }
121
kthelgason2fc52542017-03-03 00:24:41 -0800122 // This is used as a synchronisation mechanism, to make sure that the
123 // encoder queue is not blocked before we start sending it frames.
124 void WaitUntilTaskQueueIsIdle() {
125 rtc::Event event(false, false);
126 encoder_queue()->PostTask([&event] {
127 event.Set();
128 });
129 ASSERT_TRUE(event.Wait(5000));
130 }
131
sprangb1ca0732017-02-01 08:38:12 -0800132 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800133
sprangb1ca0732017-02-01 08:38:12 -0800134 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800135
sprangb1ca0732017-02-01 08:38:12 -0800136 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800137
sprangb1ca0732017-02-01 08:38:12 -0800138 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700139
140 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700141};
142
asapersson5f7226f2016-11-25 04:37:00 -0800143class VideoStreamFactory
144 : public VideoEncoderConfig::VideoStreamFactoryInterface {
145 public:
sprangfda496a2017-06-15 04:21:07 -0700146 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
147 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800148 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700149 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800150 }
151
152 private:
153 std::vector<VideoStream> CreateEncoderStreams(
154 int width,
155 int height,
156 const VideoEncoderConfig& encoder_config) override {
157 std::vector<VideoStream> streams =
158 test::CreateVideoStreams(width, height, encoder_config);
159 for (VideoStream& stream : streams) {
160 stream.temporal_layer_thresholds_bps.resize(num_temporal_layers_ - 1);
sprangfda496a2017-06-15 04:21:07 -0700161 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800162 }
163 return streams;
164 }
sprangfda496a2017-06-15 04:21:07 -0700165
asapersson5f7226f2016-11-25 04:37:00 -0800166 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700167 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800168};
169
ilnik6b826ef2017-06-16 06:53:48 -0700170
sprangb1ca0732017-02-01 08:38:12 -0800171class AdaptingFrameForwarder : public test::FrameForwarder {
172 public:
173 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700174 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800175
176 void set_adaptation_enabled(bool enabled) {
177 rtc::CritScope cs(&crit_);
178 adaptation_enabled_ = enabled;
179 }
180
asaperssonfab67072017-04-04 05:51:49 -0700181 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800182 rtc::CritScope cs(&crit_);
183 return adaptation_enabled_;
184 }
185
asapersson09f05612017-05-15 23:40:18 -0700186 rtc::VideoSinkWants last_wants() const {
187 rtc::CritScope cs(&crit_);
188 return last_wants_;
189 }
190
sprangb1ca0732017-02-01 08:38:12 -0800191 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
192 int cropped_width = 0;
193 int cropped_height = 0;
194 int out_width = 0;
195 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700196 if (adaption_enabled()) {
197 if (adapter_.AdaptFrameResolution(
198 video_frame.width(), video_frame.height(),
199 video_frame.timestamp_us() * 1000, &cropped_width,
200 &cropped_height, &out_width, &out_height)) {
201 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
202 nullptr, out_width, out_height),
203 99, 99, kVideoRotation_0);
204 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
205 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
206 }
sprangb1ca0732017-02-01 08:38:12 -0800207 } else {
208 test::FrameForwarder::IncomingCapturedFrame(video_frame);
209 }
210 }
211
212 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
213 const rtc::VideoSinkWants& wants) override {
214 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700215 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700216 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
217 wants.max_pixel_count,
218 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800219 test::FrameForwarder::AddOrUpdateSink(sink, wants);
220 }
sprangb1ca0732017-02-01 08:38:12 -0800221 cricket::VideoAdapter adapter_;
222 bool adaptation_enabled_ GUARDED_BY(crit_);
asapersson09f05612017-05-15 23:40:18 -0700223 rtc::VideoSinkWants last_wants_ GUARDED_BY(crit_);
sprangb1ca0732017-02-01 08:38:12 -0800224};
sprangc5d62e22017-04-02 23:53:04 -0700225
226class MockableSendStatisticsProxy : public SendStatisticsProxy {
227 public:
228 MockableSendStatisticsProxy(Clock* clock,
229 const VideoSendStream::Config& config,
230 VideoEncoderConfig::ContentType content_type)
231 : SendStatisticsProxy(clock, config, content_type) {}
232
233 VideoSendStream::Stats GetStats() override {
234 rtc::CritScope cs(&lock_);
235 if (mock_stats_)
236 return *mock_stats_;
237 return SendStatisticsProxy::GetStats();
238 }
239
240 void SetMockStats(const VideoSendStream::Stats& stats) {
241 rtc::CritScope cs(&lock_);
242 mock_stats_.emplace(stats);
243 }
244
245 void ResetMockStats() {
246 rtc::CritScope cs(&lock_);
247 mock_stats_.reset();
248 }
249
250 private:
251 rtc::CriticalSection lock_;
252 rtc::Optional<VideoSendStream::Stats> mock_stats_ GUARDED_BY(lock_);
253};
254
sprang4847ae62017-06-27 07:06:52 -0700255class MockBitrateObserver : public VideoBitrateAllocationObserver {
256 public:
257 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const BitrateAllocation&));
258};
259
perkj803d97f2016-11-01 11:45:46 -0700260} // namespace
261
mflodmancc3d4422017-08-03 08:27:51 -0700262class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700263 public:
264 static const int kDefaultTimeoutMs = 30 * 1000;
265
mflodmancc3d4422017-08-03 08:27:51 -0700266 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700267 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700268 codec_width_(320),
269 codec_height_(240),
sprang4847ae62017-06-27 07:06:52 -0700270 max_framerate_(30),
perkj26091b12016-09-01 01:17:40 -0700271 fake_encoder_(),
sprangc5d62e22017-04-02 23:53:04 -0700272 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700273 Clock::GetRealTimeClock(),
274 video_send_config_,
275 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700276 sink_(&fake_encoder_) {}
277
278 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700279 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700280 video_send_config_ = VideoSendStream::Config(nullptr);
281 video_send_config_.encoder_settings.encoder = &fake_encoder_;
282 video_send_config_.encoder_settings.payload_name = "FAKE";
283 video_send_config_.encoder_settings.payload_type = 125;
284
Per512ecb32016-09-23 15:52:06 +0200285 VideoEncoderConfig video_encoder_config;
perkjfa10b552016-10-02 23:45:26 -0700286 test::FillEncoderConfiguration(1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700287 video_encoder_config.video_stream_factory =
288 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100289 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700290
291 // Framerate limit is specified by the VideoStreamFactory.
292 std::vector<VideoStream> streams =
293 video_encoder_config.video_stream_factory->CreateEncoderStreams(
294 codec_width_, codec_height_, video_encoder_config);
295 max_framerate_ = streams[0].max_framerate;
296 fake_clock_.SetTimeMicros(1234);
297
asapersson5f7226f2016-11-25 04:37:00 -0800298 ConfigureEncoder(std::move(video_encoder_config), true /* nack_enabled */);
299 }
300
301 void ConfigureEncoder(VideoEncoderConfig video_encoder_config,
302 bool nack_enabled) {
mflodmancc3d4422017-08-03 08:27:51 -0700303 if (video_stream_encoder_)
304 video_stream_encoder_->Stop();
305 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700306 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700307 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
308 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -0700309 &video_source_,
310 VideoSendStream::DegradationPreference::kMaintainFramerate);
mflodmancc3d4422017-08-03 08:27:51 -0700311 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
312 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
313 kMaxPayloadLength, nack_enabled);
314 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800315 }
316
317 void ResetEncoder(const std::string& payload_name,
318 size_t num_streams,
319 size_t num_temporal_layers,
sprang4847ae62017-06-27 07:06:52 -0700320 bool nack_enabled,
321 bool screenshare) {
asapersson5f7226f2016-11-25 04:37:00 -0800322 video_send_config_.encoder_settings.payload_name = payload_name;
323
324 VideoEncoderConfig video_encoder_config;
325 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800326 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800327 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700328 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
329 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700330 video_encoder_config.content_type =
331 screenshare ? VideoEncoderConfig::ContentType::kScreen
332 : VideoEncoderConfig::ContentType::kRealtimeVideo;
asapersson5f7226f2016-11-25 04:37:00 -0800333 ConfigureEncoder(std::move(video_encoder_config), nack_enabled);
perkj26091b12016-09-01 01:17:40 -0700334 }
335
sprang57c2fff2017-01-16 06:24:02 -0800336 VideoFrame CreateFrame(int64_t ntp_time_ms,
337 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200338 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
339 destruction_event, codec_width_, codec_height_),
340 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800341 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700342 return frame;
343 }
344
sprang57c2fff2017-01-16 06:24:02 -0800345 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700346 VideoFrame frame(
347 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
348 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800349 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700350 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700351 return frame;
352 }
353
asapersson02465b82017-04-10 01:12:52 -0700354 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700355 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700356 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
357 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700358 }
359
asapersson09f05612017-05-15 23:40:18 -0700360 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
361 const rtc::VideoSinkWants& wants2) {
362 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
363 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
364 }
365
366 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
367 const rtc::VideoSinkWants& wants2) {
368 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
369 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
370 EXPECT_GT(wants1.max_pixel_count, 0);
371 }
372
373 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
374 const rtc::VideoSinkWants& wants2) {
375 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
376 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
377 }
378
asaperssonf7e294d2017-06-13 23:25:22 -0700379 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
380 const rtc::VideoSinkWants& wants2) {
381 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
382 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
383 }
384
385 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
386 const rtc::VideoSinkWants& wants2) {
387 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
388 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
389 }
390
391 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
392 const rtc::VideoSinkWants& wants2) {
393 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
394 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
395 }
396
397 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
398 const rtc::VideoSinkWants& wants2) {
399 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
400 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
401 EXPECT_GT(wants1.max_pixel_count, 0);
402 }
403
404 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
405 const rtc::VideoSinkWants& wants2) {
406 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
407 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
408 }
409
asapersson09f05612017-05-15 23:40:18 -0700410 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
411 int pixel_count) {
412 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700413 EXPECT_LT(wants.max_pixel_count, pixel_count);
414 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700415 }
416
417 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
418 EXPECT_LT(wants.max_framerate_fps, fps);
419 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
420 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700421 }
422
asaperssonf7e294d2017-06-13 23:25:22 -0700423 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
424 int expected_fps) {
425 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
426 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
427 EXPECT_FALSE(wants.target_pixel_count);
428 }
429
sprang4847ae62017-06-27 07:06:52 -0700430 void WaitForEncodedFrame(int64_t expected_ntp_time) {
431 sink_.WaitForEncodedFrame(expected_ntp_time);
432 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
433 }
434
435 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
436 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
437 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
438 return ok;
439 }
440
441 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
442 sink_.WaitForEncodedFrame(expected_width, expected_height);
443 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
444 }
445
446 void ExpectDroppedFrame() {
447 sink_.ExpectDroppedFrame();
448 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
449 }
450
451 bool WaitForFrame(int64_t timeout_ms) {
452 bool ok = sink_.WaitForFrame(timeout_ms);
453 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
454 return ok;
455 }
456
perkj26091b12016-09-01 01:17:40 -0700457 class TestEncoder : public test::FakeEncoder {
458 public:
459 TestEncoder()
460 : FakeEncoder(Clock::GetRealTimeClock()),
461 continue_encode_event_(false, false) {}
462
asaperssonfab67072017-04-04 05:51:49 -0700463 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800464 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700465 return config_;
466 }
467
468 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800469 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700470 block_next_encode_ = true;
471 }
472
kthelgason876222f2016-11-29 01:44:11 -0800473 VideoEncoder::ScalingSettings GetScalingSettings() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800474 rtc::CritScope lock(&local_crit_sect_);
kthelgasonad9010c2017-02-14 00:46:51 -0800475 if (quality_scaling_)
476 return VideoEncoder::ScalingSettings(true, 1, 2);
477 return VideoEncoder::ScalingSettings(false);
kthelgason876222f2016-11-29 01:44:11 -0800478 }
479
perkjfa10b552016-10-02 23:45:26 -0700480 void ContinueEncode() { continue_encode_event_.Set(); }
481
482 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
483 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800484 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700485 EXPECT_EQ(timestamp_, timestamp);
486 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
487 }
488
kthelgason2fc52542017-03-03 00:24:41 -0800489 void SetQualityScaling(bool b) {
490 rtc::CritScope lock(&local_crit_sect_);
491 quality_scaling_ = b;
492 }
kthelgasonad9010c2017-02-14 00:46:51 -0800493
sprangfe627f32017-03-29 08:24:59 -0700494 void ForceInitEncodeFailure(bool force_failure) {
495 rtc::CritScope lock(&local_crit_sect_);
496 force_init_encode_failed_ = force_failure;
497 }
498
perkjfa10b552016-10-02 23:45:26 -0700499 private:
perkj26091b12016-09-01 01:17:40 -0700500 int32_t Encode(const VideoFrame& input_image,
501 const CodecSpecificInfo* codec_specific_info,
502 const std::vector<FrameType>* frame_types) override {
503 bool block_encode;
504 {
brandtre78d2662017-01-16 05:57:16 -0800505 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700506 EXPECT_GT(input_image.timestamp(), timestamp_);
507 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
508 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
509
510 timestamp_ = input_image.timestamp();
511 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700512 last_input_width_ = input_image.width();
513 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700514 block_encode = block_next_encode_;
515 block_next_encode_ = false;
516 }
517 int32_t result =
518 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
519 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700520 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700521 return result;
522 }
523
sprangfe627f32017-03-29 08:24:59 -0700524 int32_t InitEncode(const VideoCodec* config,
525 int32_t number_of_cores,
526 size_t max_payload_size) override {
527 int res =
528 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
529 rtc::CritScope lock(&local_crit_sect_);
530 if (config->codecType == kVideoCodecVP8 && config->VP8().tl_factory) {
531 // Simulate setting up temporal layers, in order to validate the life
532 // cycle of these objects.
533 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
534 int num_temporal_layers =
535 std::max<int>(1, config->VP8().numberOfTemporalLayers);
536 for (int i = 0; i < num_streams; ++i) {
537 allocated_temporal_layers_.emplace_back(
538 config->VP8().tl_factory->Create(i, num_temporal_layers, 42));
539 }
540 }
541 if (force_init_encode_failed_)
542 return -1;
543 return res;
544 }
545
brandtre78d2662017-01-16 05:57:16 -0800546 rtc::CriticalSection local_crit_sect_;
sprangfe627f32017-03-29 08:24:59 -0700547 bool block_next_encode_ GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700548 rtc::Event continue_encode_event_;
sprangfe627f32017-03-29 08:24:59 -0700549 uint32_t timestamp_ GUARDED_BY(local_crit_sect_) = 0;
550 int64_t ntp_time_ms_ GUARDED_BY(local_crit_sect_) = 0;
551 int last_input_width_ GUARDED_BY(local_crit_sect_) = 0;
552 int last_input_height_ GUARDED_BY(local_crit_sect_) = 0;
553 bool quality_scaling_ GUARDED_BY(local_crit_sect_) = true;
554 std::vector<std::unique_ptr<TemporalLayers>> allocated_temporal_layers_
555 GUARDED_BY(local_crit_sect_);
556 bool force_init_encode_failed_ GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700557 };
558
mflodmancc3d4422017-08-03 08:27:51 -0700559 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700560 public:
561 explicit TestSink(TestEncoder* test_encoder)
562 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
563
perkj26091b12016-09-01 01:17:40 -0700564 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700565 EXPECT_TRUE(
566 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
567 }
568
569 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
570 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700571 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700572 if (!encoded_frame_event_.Wait(timeout_ms))
573 return false;
perkj26091b12016-09-01 01:17:40 -0700574 {
575 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800576 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700577 }
578 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700579 return true;
perkj26091b12016-09-01 01:17:40 -0700580 }
581
sprangb1ca0732017-02-01 08:38:12 -0800582 void WaitForEncodedFrame(uint32_t expected_width,
583 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700584 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
585 CheckLastFrameSizeMathces(expected_width, expected_height);
586 }
587
588 void CheckLastFrameSizeMathces(uint32_t expected_width,
589 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800590 uint32_t width = 0;
591 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800592 {
593 rtc::CritScope lock(&crit_);
594 width = last_width_;
595 height = last_height_;
596 }
597 EXPECT_EQ(expected_height, height);
598 EXPECT_EQ(expected_width, width);
599 }
600
kthelgason2fc52542017-03-03 00:24:41 -0800601 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800602
sprangc5d62e22017-04-02 23:53:04 -0700603 bool WaitForFrame(int64_t timeout_ms) {
604 return encoded_frame_event_.Wait(timeout_ms);
605 }
606
perkj26091b12016-09-01 01:17:40 -0700607 void SetExpectNoFrames() {
608 rtc::CritScope lock(&crit_);
609 expect_frames_ = false;
610 }
611
asaperssonfab67072017-04-04 05:51:49 -0700612 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200613 rtc::CritScope lock(&crit_);
614 return number_of_reconfigurations_;
615 }
616
asaperssonfab67072017-04-04 05:51:49 -0700617 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200618 rtc::CritScope lock(&crit_);
619 return min_transmit_bitrate_bps_;
620 }
621
perkj26091b12016-09-01 01:17:40 -0700622 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700623 Result OnEncodedImage(
624 const EncodedImage& encoded_image,
625 const CodecSpecificInfo* codec_specific_info,
626 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200627 rtc::CritScope lock(&crit_);
628 EXPECT_TRUE(expect_frames_);
sprangb1ca0732017-02-01 08:38:12 -0800629 last_timestamp_ = encoded_image._timeStamp;
630 last_width_ = encoded_image._encodedWidth;
631 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200632 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800633 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200634 }
635
636 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
637 int min_transmit_bitrate_bps) override {
638 rtc::CriticalSection crit_;
639 ++number_of_reconfigurations_;
640 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
641 }
642
perkj26091b12016-09-01 01:17:40 -0700643 rtc::CriticalSection crit_;
644 TestEncoder* test_encoder_;
645 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800646 uint32_t last_timestamp_ = 0;
647 uint32_t last_height_ = 0;
648 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700649 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200650 int number_of_reconfigurations_ = 0;
651 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700652 };
653
654 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100655 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200656 int codec_width_;
657 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700658 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700659 TestEncoder fake_encoder_;
sprangc5d62e22017-04-02 23:53:04 -0700660 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700661 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800662 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700663 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700664 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700665};
666
mflodmancc3d4422017-08-03 08:27:51 -0700667TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
668 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700669 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700670 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700671 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700672 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700673 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700674}
675
mflodmancc3d4422017-08-03 08:27:51 -0700676TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700677 // Dropped since no target bitrate has been set.
678 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700679 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
680 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700681
mflodmancc3d4422017-08-03 08:27:51 -0700682 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700683
perkja49cbd32016-09-16 07:53:41 -0700684 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700685 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700686 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700687}
688
mflodmancc3d4422017-08-03 08:27:51 -0700689TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
690 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700691 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700692 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700693
mflodmancc3d4422017-08-03 08:27:51 -0700694 video_stream_encoder_->OnBitrateUpdated(0, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700695 // Dropped since bitrate is zero.
perkja49cbd32016-09-16 07:53:41 -0700696 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkj26091b12016-09-01 01:17:40 -0700697
mflodmancc3d4422017-08-03 08:27:51 -0700698 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700699 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700700 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700701 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700702}
703
mflodmancc3d4422017-08-03 08:27:51 -0700704TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
705 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700706 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700707 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700708
709 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700710 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700711
perkja49cbd32016-09-16 07:53:41 -0700712 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700713 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700714 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700715}
716
mflodmancc3d4422017-08-03 08:27:51 -0700717TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
718 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700719
perkja49cbd32016-09-16 07:53:41 -0700720 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700721 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700722
mflodmancc3d4422017-08-03 08:27:51 -0700723 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700724 sink_.SetExpectNoFrames();
725 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700726 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
727 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700728}
729
mflodmancc3d4422017-08-03 08:27:51 -0700730TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
731 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700732
733 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700734 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700735 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700736 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
737 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700738 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
739 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700740 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700741 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700742
mflodmancc3d4422017-08-03 08:27:51 -0700743 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700744}
745
mflodmancc3d4422017-08-03 08:27:51 -0700746TEST_F(VideoStreamEncoderTest,
747 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
748 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100749 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200750
751 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200752 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700753 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100754 // The encoder will have been configured once when the first frame is
755 // received.
756 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200757
758 VideoEncoderConfig video_encoder_config;
perkjfa10b552016-10-02 23:45:26 -0700759 test::FillEncoderConfiguration(1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200760 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -0700761 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
762 kMaxPayloadLength,
763 true /* nack_enabled */);
Per512ecb32016-09-23 15:52:06 +0200764
765 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200766 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700767 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100768 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700769 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700770
mflodmancc3d4422017-08-03 08:27:51 -0700771 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -0700772}
773
mflodmancc3d4422017-08-03 08:27:51 -0700774TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
775 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkjfa10b552016-10-02 23:45:26 -0700776
777 // Capture a frame and wait for it to synchronize with the encoder thread.
778 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700779 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100780 // The encoder will have been configured once.
781 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700782 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
783 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
784
785 codec_width_ *= 2;
786 codec_height_ *= 2;
787 // Capture a frame with a higher resolution and wait for it to synchronize
788 // with the encoder thread.
789 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700790 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700791 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
792 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100793 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700794
mflodmancc3d4422017-08-03 08:27:51 -0700795 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -0700796}
797
mflodmancc3d4422017-08-03 08:27:51 -0700798TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOffFor1S1TLWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800799 const bool kNackEnabled = true;
800 const size_t kNumStreams = 1;
801 const size_t kNumTl = 1;
sprang4847ae62017-06-27 07:06:52 -0700802 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700803 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800804
805 // Capture a frame and wait for it to synchronize with the encoder thread.
806 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700807 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800808 // The encoder have been configured once when the first frame is received.
809 EXPECT_EQ(1, sink_.number_of_reconfigurations());
810 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
811 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
812 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
813 // Resilience is off for no temporal layers with nack on.
814 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700815 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800816}
817
mflodmancc3d4422017-08-03 08:27:51 -0700818TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOffFor2S1TlWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800819 const bool kNackEnabled = true;
820 const size_t kNumStreams = 2;
821 const size_t kNumTl = 1;
sprang4847ae62017-06-27 07:06:52 -0700822 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700823 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800824
825 // Capture a frame and wait for it to synchronize with the encoder thread.
826 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700827 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800828 // The encoder have been configured once when the first frame is received.
829 EXPECT_EQ(1, sink_.number_of_reconfigurations());
830 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
831 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
832 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
833 // Resilience is off for no temporal layers and >1 streams with nack on.
834 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700835 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800836}
837
mflodmancc3d4422017-08-03 08:27:51 -0700838TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOnFor1S1TLWithNackDisabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800839 const bool kNackEnabled = false;
840 const size_t kNumStreams = 1;
841 const size_t kNumTl = 1;
sprang4847ae62017-06-27 07:06:52 -0700842 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700843 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800844
845 // Capture a frame and wait for it to synchronize with the encoder thread.
846 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700847 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800848 // The encoder have been configured once when the first frame is received.
849 EXPECT_EQ(1, sink_.number_of_reconfigurations());
850 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
851 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
852 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
853 // Resilience is on for no temporal layers with nack off.
854 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700855 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800856}
857
mflodmancc3d4422017-08-03 08:27:51 -0700858TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOnFor1S2TlWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800859 const bool kNackEnabled = true;
860 const size_t kNumStreams = 1;
861 const size_t kNumTl = 2;
sprang4847ae62017-06-27 07:06:52 -0700862 ResetEncoder("VP8", kNumStreams, kNumTl, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700863 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800864
865 // Capture a frame and wait for it to synchronize with the encoder thread.
866 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700867 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800868 // The encoder have been configured once when the first frame is received.
869 EXPECT_EQ(1, sink_.number_of_reconfigurations());
870 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
871 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
872 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
873 // Resilience is on for temporal layers.
874 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700875 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800876}
877
mflodmancc3d4422017-08-03 08:27:51 -0700878TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -0700879 EXPECT_TRUE(video_source_.has_sinks());
880 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700881 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -0700882 &new_video_source,
883 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -0700884 EXPECT_FALSE(video_source_.has_sinks());
885 EXPECT_TRUE(new_video_source.has_sinks());
886
mflodmancc3d4422017-08-03 08:27:51 -0700887 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700888}
889
mflodmancc3d4422017-08-03 08:27:51 -0700890TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -0700891 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700892 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -0700893 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700894 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700895}
896
mflodmancc3d4422017-08-03 08:27:51 -0700897TEST_F(VideoStreamEncoderTest, SinkWantsFromOveruseDetector) {
898 const int kMaxDowngrades = VideoStreamEncoder::kMaxCpuResolutionDowngrades;
899 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -0700900
asapersson02465b82017-04-10 01:12:52 -0700901 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700902
903 int frame_width = 1280;
904 int frame_height = 720;
905
mflodmancc3d4422017-08-03 08:27:51 -0700906 // Trigger CPU overuse kMaxCpuDowngrades times. Every time, VideoStreamEncoder
907 // should request lower resolution.
asaperssond0de2952017-04-21 01:47:31 -0700908 for (int i = 1; i <= kMaxDowngrades; ++i) {
perkj803d97f2016-11-01 11:45:46 -0700909 video_source_.IncomingCapturedFrame(
910 CreateFrame(i, frame_width, frame_height));
sprang4847ae62017-06-27 07:06:52 -0700911 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -0700912
mflodmancc3d4422017-08-03 08:27:51 -0700913 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700914
sprang84a37592017-02-10 07:04:27 -0800915 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700916 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
perkj803d97f2016-11-01 11:45:46 -0700917 frame_width * frame_height);
asaperssond0de2952017-04-21 01:47:31 -0700918 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
919 EXPECT_EQ(i, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -0700920
921 frame_width /= 2;
922 frame_height /= 2;
923 }
924
kthelgason876222f2016-11-29 01:44:11 -0800925 // Trigger CPU overuse one more time. This should not trigger a request for
perkj803d97f2016-11-01 11:45:46 -0700926 // lower resolution.
927 rtc::VideoSinkWants current_wants = video_source_.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -0700928 video_source_.IncomingCapturedFrame(
929 CreateFrame(kMaxDowngrades + 1, frame_width, frame_height));
sprang4847ae62017-06-27 07:06:52 -0700930 WaitForEncodedFrame(kMaxDowngrades + 1);
mflodmancc3d4422017-08-03 08:27:51 -0700931 video_stream_encoder_->TriggerCpuOveruse();
sprang84a37592017-02-10 07:04:27 -0800932 EXPECT_EQ(video_source_.sink_wants().target_pixel_count,
933 current_wants.target_pixel_count);
perkj803d97f2016-11-01 11:45:46 -0700934 EXPECT_EQ(video_source_.sink_wants().max_pixel_count,
935 current_wants.max_pixel_count);
asaperssond0de2952017-04-21 01:47:31 -0700936 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
937 EXPECT_EQ(kMaxDowngrades,
938 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -0700939
940 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -0700941 video_stream_encoder_->TriggerCpuNormalUsage();
sprang84a37592017-02-10 07:04:27 -0800942 EXPECT_EQ(frame_width * frame_height * 5 / 3,
943 video_source_.sink_wants().target_pixel_count.value_or(0));
944 EXPECT_EQ(frame_width * frame_height * 4,
sprangc5d62e22017-04-02 23:53:04 -0700945 video_source_.sink_wants().max_pixel_count);
asaperssond0de2952017-04-21 01:47:31 -0700946 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
947 EXPECT_EQ(kMaxDowngrades + 1,
948 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -0700949
mflodmancc3d4422017-08-03 08:27:51 -0700950 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700951}
952
mflodmancc3d4422017-08-03 08:27:51 -0700953TEST_F(VideoStreamEncoderTest,
954 TestMaxCpuResolutionDowngrades_BalancedMode_NoFpsLimit) {
955 const int kMaxDowngrades = VideoStreamEncoder::kMaxCpuResolutionDowngrades;
asaperssonf7e294d2017-06-13 23:25:22 -0700956 const int kWidth = 1280;
957 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -0700958 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -0700959
960 // Enable kBalanced preference, no initial limitation.
961 AdaptingFrameForwarder source;
962 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -0700963 video_stream_encoder_->SetSource(
964 &source,
965 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -0700966 VerifyNoLimitation(source.sink_wants());
967 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
968 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
969
970 // Trigger adapt down kMaxCpuDowngrades times.
971 int t = 1;
972 for (int i = 1; i <= kMaxDowngrades; ++i) {
973 source.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
974 sink_.WaitForEncodedFrame(t++);
mflodmancc3d4422017-08-03 08:27:51 -0700975 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -0700976 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
977 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
978 EXPECT_EQ(i, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
979 }
980
981 // Trigger adapt down, max cpu downgrades reach, expect no change.
982 rtc::VideoSinkWants last_wants = source.sink_wants();
983 source.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
984 sink_.WaitForEncodedFrame(t++);
mflodmancc3d4422017-08-03 08:27:51 -0700985 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -0700986 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
987 EXPECT_EQ(last_wants.max_pixel_count, source.sink_wants().max_pixel_count);
988 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
989 EXPECT_EQ(kMaxDowngrades,
990 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
991
992 // Trigger adapt up kMaxCpuDowngrades times.
993 for (int i = 1; i <= kMaxDowngrades; ++i) {
994 source.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
995 sink_.WaitForEncodedFrame(t++);
mflodmancc3d4422017-08-03 08:27:51 -0700996 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -0700997 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
998 EXPECT_GT(source.sink_wants().max_pixel_count, last_wants.max_pixel_count);
999 EXPECT_EQ(kMaxDowngrades + i,
1000 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1001 }
1002
1003 VerifyNoLimitation(source.sink_wants());
1004 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1005
mflodmancc3d4422017-08-03 08:27:51 -07001006 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001007}
mflodmancc3d4422017-08-03 08:27:51 -07001008TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
1009 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001010 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001011
sprangc5d62e22017-04-02 23:53:04 -07001012 const int kFrameWidth = 1280;
1013 const int kFrameHeight = 720;
1014 const int kFrameIntervalMs = 1000 / 30;
1015
1016 int frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -07001017
kthelgason5e13d412016-12-01 03:59:51 -08001018 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001019 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001020 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001021 frame_timestamp += kFrameIntervalMs;
1022
perkj803d97f2016-11-01 11:45:46 -07001023 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001024 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001025 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001026 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001027 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001028 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -07001029
asapersson0944a802017-04-07 00:57:58 -07001030 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -07001031 // wanted resolution.
1032 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
1033 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
1034 kFrameWidth * kFrameHeight);
1035 EXPECT_EQ(std::numeric_limits<int>::max(),
1036 video_source_.sink_wants().max_framerate_fps);
1037
1038 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -07001039 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001040 video_stream_encoder_->SetSource(
perkj803d97f2016-11-01 11:45:46 -07001041 &new_video_source,
1042 VideoSendStream::DegradationPreference::kMaintainResolution);
1043
sprangc5d62e22017-04-02 23:53:04 -07001044 // Initially no degradation registered.
asapersson02465b82017-04-10 01:12:52 -07001045 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001046
sprangc5d62e22017-04-02 23:53:04 -07001047 // Force an input frame rate to be available, or the adaptation call won't
1048 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -07001049 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -07001050 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -07001051 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -07001052 stats_proxy_->SetMockStats(stats);
1053
mflodmancc3d4422017-08-03 08:27:51 -07001054 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001055 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001056 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001057 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001058 frame_timestamp += kFrameIntervalMs;
1059
1060 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001061 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001062 EXPECT_EQ(std::numeric_limits<int>::max(),
1063 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001064 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001065
asapersson02465b82017-04-10 01:12:52 -07001066 // Turn off degradation completely.
mflodmancc3d4422017-08-03 08:27:51 -07001067 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001068 &new_video_source,
1069 VideoSendStream::DegradationPreference::kDegradationDisabled);
asapersson02465b82017-04-10 01:12:52 -07001070 VerifyNoLimitation(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001071
mflodmancc3d4422017-08-03 08:27:51 -07001072 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001073 new_video_source.IncomingCapturedFrame(
1074 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001075 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001076 frame_timestamp += kFrameIntervalMs;
1077
1078 // Still no degradation.
asapersson02465b82017-04-10 01:12:52 -07001079 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001080
1081 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001082 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001083 &new_video_source,
1084 VideoSendStream::DegradationPreference::kMaintainFramerate);
1085 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1086 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001087 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001088 EXPECT_EQ(std::numeric_limits<int>::max(),
1089 new_video_source.sink_wants().max_framerate_fps);
1090
1091 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001092 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001093 &new_video_source,
1094 VideoSendStream::DegradationPreference::kMaintainResolution);
1095 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1096 EXPECT_EQ(std::numeric_limits<int>::max(),
1097 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001098 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001099
mflodmancc3d4422017-08-03 08:27:51 -07001100 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001101}
1102
mflodmancc3d4422017-08-03 08:27:51 -07001103TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
1104 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001105
asaperssonfab67072017-04-04 05:51:49 -07001106 const int kWidth = 1280;
1107 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001108 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001109 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001110 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1111 EXPECT_FALSE(stats.bw_limited_resolution);
1112 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1113
1114 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001115 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001116 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001117 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001118
1119 stats = stats_proxy_->GetStats();
1120 EXPECT_TRUE(stats.bw_limited_resolution);
1121 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1122
1123 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001124 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001125 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001126 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001127
1128 stats = stats_proxy_->GetStats();
1129 EXPECT_FALSE(stats.bw_limited_resolution);
1130 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1131 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1132
mflodmancc3d4422017-08-03 08:27:51 -07001133 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001134}
1135
mflodmancc3d4422017-08-03 08:27:51 -07001136TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
1137 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001138
1139 const int kWidth = 1280;
1140 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001141 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001142 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001143 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1144 EXPECT_FALSE(stats.cpu_limited_resolution);
1145 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1146
1147 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001148 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001149 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001150 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001151
1152 stats = stats_proxy_->GetStats();
1153 EXPECT_TRUE(stats.cpu_limited_resolution);
1154 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1155
1156 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001157 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001158 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001159 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001160
1161 stats = stats_proxy_->GetStats();
1162 EXPECT_FALSE(stats.cpu_limited_resolution);
1163 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001164 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001165
mflodmancc3d4422017-08-03 08:27:51 -07001166 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001167}
1168
mflodmancc3d4422017-08-03 08:27:51 -07001169TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
1170 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001171
asaperssonfab67072017-04-04 05:51:49 -07001172 const int kWidth = 1280;
1173 const int kHeight = 720;
1174 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001175 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001176 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001177 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001178 EXPECT_FALSE(stats.cpu_limited_resolution);
1179 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1180
asaperssonfab67072017-04-04 05:51:49 -07001181 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001182 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001183 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001184 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001185 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001186 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001187 EXPECT_TRUE(stats.cpu_limited_resolution);
1188 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1189
1190 // Set new source with adaptation still enabled.
1191 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001192 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001193 &new_video_source,
1194 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001195
asaperssonfab67072017-04-04 05:51:49 -07001196 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001197 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001198 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001199 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001200 EXPECT_TRUE(stats.cpu_limited_resolution);
1201 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1202
1203 // Set adaptation disabled.
mflodmancc3d4422017-08-03 08:27:51 -07001204 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001205 &new_video_source,
sprangc5d62e22017-04-02 23:53:04 -07001206 VideoSendStream::DegradationPreference::kDegradationDisabled);
kthelgason876222f2016-11-29 01:44:11 -08001207
asaperssonfab67072017-04-04 05:51:49 -07001208 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001209 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001210 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001211 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001212 EXPECT_FALSE(stats.cpu_limited_resolution);
1213 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1214
1215 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001216 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001217 &new_video_source,
1218 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001219
asaperssonfab67072017-04-04 05:51:49 -07001220 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001221 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001222 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001223 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001224 EXPECT_TRUE(stats.cpu_limited_resolution);
1225 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1226
asaperssonfab67072017-04-04 05:51:49 -07001227 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001228 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001229 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001230 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001231 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001232 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001233 EXPECT_FALSE(stats.cpu_limited_resolution);
1234 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001235 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001236
mflodmancc3d4422017-08-03 08:27:51 -07001237 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001238}
1239
mflodmancc3d4422017-08-03 08:27:51 -07001240TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
1241 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001242
asaperssonfab67072017-04-04 05:51:49 -07001243 const int kWidth = 1280;
1244 const int kHeight = 720;
1245 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001246 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001247 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001248 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001249 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001250 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001251
1252 // Set new source with adaptation still enabled.
1253 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001254 video_stream_encoder_->SetSource(
1255 &new_video_source,
1256 VideoSendStream::DegradationPreference::kBalanced);
kthelgason876222f2016-11-29 01:44:11 -08001257
asaperssonfab67072017-04-04 05:51:49 -07001258 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001259 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001260 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001261 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001262 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001263 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001264
asaperssonfab67072017-04-04 05:51:49 -07001265 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001266 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001267 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001268 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001269 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001270 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001271 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001272 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001273
asaperssonfab67072017-04-04 05:51:49 -07001274 // Set new source with adaptation still enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001275 video_stream_encoder_->SetSource(
1276 &new_video_source,
1277 VideoSendStream::DegradationPreference::kBalanced);
kthelgason876222f2016-11-29 01:44:11 -08001278
asaperssonfab67072017-04-04 05:51:49 -07001279 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001280 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001281 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001282 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001283 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001284 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001285
asapersson02465b82017-04-10 01:12:52 -07001286 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001287 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001288 &new_video_source,
1289 VideoSendStream::DegradationPreference::kMaintainResolution);
1290
asaperssonfab67072017-04-04 05:51:49 -07001291 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001292 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001293 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001294 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001295 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001296 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1297 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001298
mflodmancc3d4422017-08-03 08:27:51 -07001299 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001300}
1301
mflodmancc3d4422017-08-03 08:27:51 -07001302TEST_F(VideoStreamEncoderTest,
1303 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1304 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001305
1306 const int kWidth = 1280;
1307 const int kHeight = 720;
1308 video_source_.set_adaptation_enabled(true);
1309 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001310 WaitForEncodedFrame(1);
asapersson36e9eb42017-03-31 05:29:12 -07001311 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1312 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1313 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1314
1315 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001316 video_stream_encoder_->TriggerQualityLow();
asapersson36e9eb42017-03-31 05:29:12 -07001317 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001318 WaitForEncodedFrame(2);
asapersson36e9eb42017-03-31 05:29:12 -07001319 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1320 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1321 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1322
1323 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001324 video_stream_encoder_->TriggerCpuOveruse();
asapersson36e9eb42017-03-31 05:29:12 -07001325 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001326 WaitForEncodedFrame(3);
asapersson36e9eb42017-03-31 05:29:12 -07001327 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1328 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1329 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1330
1331 // Set source with adaptation still enabled but quality scaler is off.
1332 fake_encoder_.SetQualityScaling(false);
mflodmancc3d4422017-08-03 08:27:51 -07001333 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001334 &video_source_,
1335 VideoSendStream::DegradationPreference::kMaintainFramerate);
asapersson36e9eb42017-03-31 05:29:12 -07001336
1337 video_source_.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001338 WaitForEncodedFrame(4);
asapersson36e9eb42017-03-31 05:29:12 -07001339 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1340 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1341 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1342
mflodmancc3d4422017-08-03 08:27:51 -07001343 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001344}
1345
mflodmancc3d4422017-08-03 08:27:51 -07001346TEST_F(VideoStreamEncoderTest,
1347 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
1348 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001349
asapersson0944a802017-04-07 00:57:58 -07001350 const int kWidth = 1280;
1351 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001352 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001353
asaperssonfab67072017-04-04 05:51:49 -07001354 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001355 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001356 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001357 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001358 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001359 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1360
asapersson02465b82017-04-10 01:12:52 -07001361 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001362 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001363 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001364 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001365 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001366 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001367 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001368 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1369
1370 // Set new source with adaptation still enabled.
1371 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001372 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001373 &new_video_source,
1374 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001375
1376 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001377 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001378 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001379 stats = stats_proxy_->GetStats();
1380 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001381 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001382 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1383
sprangc5d62e22017-04-02 23:53:04 -07001384 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001385 video_stream_encoder_->SetSource(
perkj803d97f2016-11-01 11:45:46 -07001386 &new_video_source,
1387 VideoSendStream::DegradationPreference::kMaintainResolution);
1388 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001389 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001390 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001391 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001392 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001393 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001394 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001395 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1396
sprangc5d62e22017-04-02 23:53:04 -07001397 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001398 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001399 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1400 mock_stats.input_frame_rate = 30;
1401 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001402 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001403 stats_proxy_->ResetMockStats();
1404
1405 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001406 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001407 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001408
1409 // Framerate now adapted.
1410 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001411 EXPECT_FALSE(stats.cpu_limited_resolution);
1412 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001413 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1414
1415 // Disable CPU adaptation.
mflodmancc3d4422017-08-03 08:27:51 -07001416 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001417 &new_video_source,
1418 VideoSendStream::DegradationPreference::kDegradationDisabled);
1419 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001420 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001421 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001422
1423 stats = stats_proxy_->GetStats();
1424 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001425 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001426 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1427
1428 // Try to trigger overuse. Should not succeed.
1429 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001430 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001431 stats_proxy_->ResetMockStats();
1432
1433 stats = stats_proxy_->GetStats();
1434 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001435 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001436 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1437
1438 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001439 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001440 &video_source_,
1441 VideoSendStream::DegradationPreference::kMaintainFramerate);
asaperssonfab67072017-04-04 05:51:49 -07001442 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001443 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001444 stats = stats_proxy_->GetStats();
1445 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001446 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001447 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001448
1449 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001450 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001451 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001452 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001453 stats = stats_proxy_->GetStats();
1454 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001455 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001456 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1457
1458 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001459 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001460 &new_video_source,
1461 VideoSendStream::DegradationPreference::kMaintainResolution);
1462 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001463 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001464 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001465 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001466 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001467 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001468 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001469 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1470
1471 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001472 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001473 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001474 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001475 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001476 stats = stats_proxy_->GetStats();
1477 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001478 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001479 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001480 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001481
mflodmancc3d4422017-08-03 08:27:51 -07001482 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001483}
1484
mflodmancc3d4422017-08-03 08:27:51 -07001485TEST_F(VideoStreamEncoderTest, StatsTracksPreferredBitrate) {
1486 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Erik Språng08127a92016-11-16 16:41:30 +01001487
asaperssonfab67072017-04-04 05:51:49 -07001488 const int kWidth = 1280;
1489 const int kHeight = 720;
1490 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001491 WaitForEncodedFrame(1);
Erik Språng08127a92016-11-16 16:41:30 +01001492
1493 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1494 EXPECT_EQ(video_encoder_config_.max_bitrate_bps,
1495 stats.preferred_media_bitrate_bps);
1496
mflodmancc3d4422017-08-03 08:27:51 -07001497 video_stream_encoder_->Stop();
Erik Språng08127a92016-11-16 16:41:30 +01001498}
1499
mflodmancc3d4422017-08-03 08:27:51 -07001500TEST_F(VideoStreamEncoderTest,
1501 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001502 const int kWidth = 1280;
1503 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001504 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001505
asaperssonfab67072017-04-04 05:51:49 -07001506 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001507 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001508
asaperssonfab67072017-04-04 05:51:49 -07001509 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001510 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001511
asaperssonfab67072017-04-04 05:51:49 -07001512 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001513 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001514
asaperssonfab67072017-04-04 05:51:49 -07001515 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001516 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001517
kthelgason876222f2016-11-29 01:44:11 -08001518 // Expect a scale down.
1519 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001520 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001521
asapersson02465b82017-04-10 01:12:52 -07001522 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001523 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001524 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001525 &new_video_source,
1526 VideoSendStream::DegradationPreference::kMaintainResolution);
1527
asaperssonfab67072017-04-04 05:51:49 -07001528 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001529 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001530 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001531 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001532
asaperssonfab67072017-04-04 05:51:49 -07001533 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001534 EXPECT_EQ(std::numeric_limits<int>::max(),
1535 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001536
asaperssonfab67072017-04-04 05:51:49 -07001537 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001538 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001539 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001540 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001541
asapersson02465b82017-04-10 01:12:52 -07001542 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001543 EXPECT_EQ(std::numeric_limits<int>::max(),
1544 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001545
mflodmancc3d4422017-08-03 08:27:51 -07001546 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001547}
1548
mflodmancc3d4422017-08-03 08:27:51 -07001549TEST_F(VideoStreamEncoderTest,
1550 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001551 const int kWidth = 1280;
1552 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001553 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001554
1555 // Enable kMaintainFramerate preference, no initial limitation.
1556 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001557 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001558 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1559
1560 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001561 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001562 VerifyNoLimitation(source.sink_wants());
1563 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1564 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1565
1566 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001567 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001568 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001569 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1570 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1571 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1572
1573 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001574 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001575 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1576 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1577 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1578
mflodmancc3d4422017-08-03 08:27:51 -07001579 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001580}
1581
mflodmancc3d4422017-08-03 08:27:51 -07001582TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001583 const int kWidth = 1280;
1584 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001585 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001586
1587 // Enable kBalanced preference, no initial limitation.
1588 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001589 video_stream_encoder_->SetSource(
1590 &source,
1591 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001592 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1593 sink_.WaitForEncodedFrame(1);
1594 VerifyNoLimitation(source.sink_wants());
1595
1596 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001597 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001598 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1599 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1600 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1601 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1602
1603 // Trigger adapt down for same input resolution, expect no change.
1604 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1605 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001606 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001607 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1608 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1609 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1610
1611 // Trigger adapt down for larger input resolution, expect no change.
1612 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1613 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001614 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001615 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1616 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1617 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1618
mflodmancc3d4422017-08-03 08:27:51 -07001619 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001620}
1621
mflodmancc3d4422017-08-03 08:27:51 -07001622TEST_F(VideoStreamEncoderTest,
1623 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001624 const int kWidth = 1280;
1625 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001626 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001627
1628 // Enable kMaintainFramerate preference, no initial limitation.
1629 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001630 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001631 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1632
1633 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001634 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001635 VerifyNoLimitation(source.sink_wants());
1636 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1637 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1638
1639 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001640 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001641 VerifyNoLimitation(source.sink_wants());
1642 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1643 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1644
mflodmancc3d4422017-08-03 08:27:51 -07001645 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001646}
1647
mflodmancc3d4422017-08-03 08:27:51 -07001648TEST_F(VideoStreamEncoderTest,
1649 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001650 const int kWidth = 1280;
1651 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001652 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001653
1654 // Enable kMaintainResolution preference, no initial limitation.
1655 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001656 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001657 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
1658
1659 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001660 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001661 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001662 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001663 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1664
1665 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001666 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001667 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001668 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001669 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1670
mflodmancc3d4422017-08-03 08:27:51 -07001671 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001672}
1673
mflodmancc3d4422017-08-03 08:27:51 -07001674TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001675 const int kWidth = 1280;
1676 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001677 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001678
1679 // Enable kBalanced preference, no initial limitation.
1680 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001681 video_stream_encoder_->SetSource(
1682 &source,
1683 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001684
1685 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1686 sink_.WaitForEncodedFrame(kWidth, kHeight);
1687 VerifyNoLimitation(source.sink_wants());
1688 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1689 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1690 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1691
1692 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001693 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001694 VerifyNoLimitation(source.sink_wants());
1695 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1696 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1697 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1698
mflodmancc3d4422017-08-03 08:27:51 -07001699 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001700}
1701
mflodmancc3d4422017-08-03 08:27:51 -07001702TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001703 const int kWidth = 1280;
1704 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001705 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001706
1707 // Enable kDegradationDisabled preference, no initial limitation.
1708 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001709 video_stream_encoder_->SetSource(
asapersson09f05612017-05-15 23:40:18 -07001710 &source, VideoSendStream::DegradationPreference::kDegradationDisabled);
1711
1712 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1713 sink_.WaitForEncodedFrame(kWidth, kHeight);
1714 VerifyNoLimitation(source.sink_wants());
1715 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1716 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1717 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1718
1719 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001720 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001721 VerifyNoLimitation(source.sink_wants());
1722 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1723 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1724 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1725
mflodmancc3d4422017-08-03 08:27:51 -07001726 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001727}
1728
mflodmancc3d4422017-08-03 08:27:51 -07001729TEST_F(VideoStreamEncoderTest,
1730 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001731 const int kWidth = 1280;
1732 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001733 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001734
1735 // Enable kMaintainFramerate preference, no initial limitation.
1736 AdaptingFrameForwarder source;
1737 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001738 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001739 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1740
1741 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001742 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001743 VerifyNoLimitation(source.sink_wants());
1744 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1745 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1746
1747 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001748 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001749 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001750 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001751 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001752 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1753 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1754
1755 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001756 video_stream_encoder_->TriggerQualityHigh();
asapersson02465b82017-04-10 01:12:52 -07001757 VerifyNoLimitation(source.sink_wants());
1758 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1759 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1760 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1761
mflodmancc3d4422017-08-03 08:27:51 -07001762 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001763}
1764
mflodmancc3d4422017-08-03 08:27:51 -07001765TEST_F(VideoStreamEncoderTest,
1766 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001767 const int kWidth = 1280;
1768 const int kHeight = 720;
1769 const int kInputFps = 30;
mflodmancc3d4422017-08-03 08:27:51 -07001770 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001771
1772 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1773 stats.input_frame_rate = kInputFps;
1774 stats_proxy_->SetMockStats(stats);
1775
1776 // Expect no scaling to begin with (preference: kMaintainFramerate).
1777 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1778 sink_.WaitForEncodedFrame(1);
1779 VerifyNoLimitation(video_source_.sink_wants());
1780
1781 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001782 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001783 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1784 sink_.WaitForEncodedFrame(2);
1785 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1786
1787 // Enable kMaintainResolution preference.
1788 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001789 video_stream_encoder_->SetSource(
asapersson09f05612017-05-15 23:40:18 -07001790 &new_video_source,
1791 VideoSendStream::DegradationPreference::kMaintainResolution);
1792 VerifyNoLimitation(new_video_source.sink_wants());
1793
1794 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001795 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001796 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1797 sink_.WaitForEncodedFrame(3);
1798 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1799
1800 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001801 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001802 VerifyNoLimitation(new_video_source.sink_wants());
1803
mflodmancc3d4422017-08-03 08:27:51 -07001804 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001805}
1806
mflodmancc3d4422017-08-03 08:27:51 -07001807TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001808 const int kWidth = 1280;
1809 const int kHeight = 720;
1810 const size_t kNumFrames = 10;
1811
mflodmancc3d4422017-08-03 08:27:51 -07001812 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001813
asaperssond0de2952017-04-21 01:47:31 -07001814 // Enable adapter, expected input resolutions when downscaling:
1815 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (min resolution limit)
1816 video_source_.set_adaptation_enabled(true);
1817
1818 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1819 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1820
1821 int downscales = 0;
1822 for (size_t i = 1; i <= kNumFrames; i++) {
1823 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001824 WaitForEncodedFrame(i);
asaperssond0de2952017-04-21 01:47:31 -07001825
asaperssonfab67072017-04-04 05:51:49 -07001826 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001827 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001828 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001829 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001830
1831 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1832 ++downscales;
1833
1834 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1835 EXPECT_EQ(downscales,
1836 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1837 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001838 }
mflodmancc3d4422017-08-03 08:27:51 -07001839 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001840}
1841
mflodmancc3d4422017-08-03 08:27:51 -07001842TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001843 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1844 const int kWidth = 1280;
1845 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001846 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001847
1848 // Enable kMaintainFramerate preference, no initial limitation.
1849 AdaptingFrameForwarder source;
1850 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001851 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07001852 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1853
1854 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001855 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001856 VerifyNoLimitation(source.sink_wants());
1857 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1858 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1859
1860 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001861 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001862 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001863 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001864 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001865 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1866 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1867
1868 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001869 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07001870 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001871 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001872 VerifyNoLimitation(source.sink_wants());
1873 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1874 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1875
1876 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001877 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001878 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001879 WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07001880 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001881 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1882 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1883
1884 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001885 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson09f05612017-05-15 23:40:18 -07001886 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1887 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001888 VerifyNoLimitation(source.sink_wants());
1889 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1890 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1891
mflodmancc3d4422017-08-03 08:27:51 -07001892 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001893}
1894
mflodmancc3d4422017-08-03 08:27:51 -07001895TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07001896 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
1897 const int kWidth = 1280;
1898 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001899 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001900
1901 // Enable kBalanced preference, no initial limitation.
1902 AdaptingFrameForwarder source;
1903 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001904 video_stream_encoder_->SetSource(
1905 &source,
1906 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001907
1908 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1909 sink_.WaitForEncodedFrame(kWidth, kHeight);
1910 VerifyNoLimitation(source.sink_wants());
1911 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1912 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1913
1914 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001915 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001916 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1917 sink_.WaitForEncodedFrame(2);
1918 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1919 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1920 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1921
1922 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001923 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001924 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1925 sink_.WaitForEncodedFrame(kWidth, kHeight);
1926 VerifyNoLimitation(source.sink_wants());
1927 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1928 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1929
1930 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001931 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001932 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
1933 sink_.WaitForEncodedFrame(4);
1934 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1935 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1936 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1937
1938 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001939 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001940 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1941 sink_.WaitForEncodedFrame(kWidth, kHeight);
1942 VerifyNoLimitation(source.sink_wants());
1943 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1944 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1945
mflodmancc3d4422017-08-03 08:27:51 -07001946 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001947}
1948
mflodmancc3d4422017-08-03 08:27:51 -07001949TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001950 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
1951 const int kWidth = 1280;
1952 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001953 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001954
1955 // Enable kMaintainFramerate preference, no initial limitation.
1956 AdaptingFrameForwarder source;
1957 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001958 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07001959 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1960
1961 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001962 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001963 VerifyNoLimitation(source.sink_wants());
1964 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1965 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1966 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1967 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1968
1969 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07001970 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001971 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001972 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001973 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001974 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1975 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1976 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1977 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1978
1979 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07001980 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001981 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001982 WaitForEncodedFrame(3);
asapersson09f05612017-05-15 23:40:18 -07001983 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
1984 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07001985 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1986 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1987 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1988 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1989
1990 // Trigger cpu adapt down, max cpu downgrades reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001991 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001992 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001993 WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07001994 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07001995 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1996 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1997 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1998 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1999
2000 // Trigger quality adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002001 video_stream_encoder_->TriggerQualityLow();
asaperssond0de2952017-04-21 01:47:31 -07002002 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002003 WaitForEncodedFrame(5);
asapersson09f05612017-05-15 23:40:18 -07002004 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002005 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2006 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2007 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2008 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2009
2010 // Trigger cpu adapt up, expect upscaled resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07002011 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07002012 source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002013 WaitForEncodedFrame(6);
asapersson09f05612017-05-15 23:40:18 -07002014 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002015 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2016 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2017 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2018 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2019
2020 // Trigger cpu adapt up, expect upscaled resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002021 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07002022 source.IncomingCapturedFrame(CreateFrame(7, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002023 WaitForEncodedFrame(7);
asapersson09f05612017-05-15 23:40:18 -07002024 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002025 last_wants = source.sink_wants();
2026 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2027 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2028 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2029 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2030
2031 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002032 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07002033 source.IncomingCapturedFrame(CreateFrame(8, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002034 WaitForEncodedFrame(8);
asapersson09f05612017-05-15 23:40:18 -07002035 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002036 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2037 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2038 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2039 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2040
2041 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002042 video_stream_encoder_->TriggerQualityHigh();
asaperssond0de2952017-04-21 01:47:31 -07002043 source.IncomingCapturedFrame(CreateFrame(9, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002044 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002045 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002046 VerifyNoLimitation(source.sink_wants());
2047 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2048 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2049 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2050 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002051
mflodmancc3d4422017-08-03 08:27:51 -07002052 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002053}
2054
mflodmancc3d4422017-08-03 08:27:51 -07002055TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002056 const int kWidth = 640;
2057 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002058
mflodmancc3d4422017-08-03 08:27:51 -07002059 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002060
perkj803d97f2016-11-01 11:45:46 -07002061 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002062 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002063 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002064 }
2065
mflodmancc3d4422017-08-03 08:27:51 -07002066 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002067 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002068 video_source_.IncomingCapturedFrame(CreateFrame(
2069 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002070 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002071 }
2072
mflodmancc3d4422017-08-03 08:27:51 -07002073 video_stream_encoder_->Stop();
2074 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002075 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002076
perkj803d97f2016-11-01 11:45:46 -07002077 EXPECT_EQ(1,
2078 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2079 EXPECT_EQ(
2080 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2081}
2082
mflodmancc3d4422017-08-03 08:27:51 -07002083TEST_F(VideoStreamEncoderTest,
2084 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2085 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002086 const int kWidth = 640;
2087 const int kHeight = 360;
2088
mflodmancc3d4422017-08-03 08:27:51 -07002089 video_stream_encoder_->SetSource(
asaperssonf4e44af2017-04-19 02:01:06 -07002090 &video_source_,
2091 VideoSendStream::DegradationPreference::kDegradationDisabled);
2092
2093 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2094 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002095 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002096 }
2097
mflodmancc3d4422017-08-03 08:27:51 -07002098 video_stream_encoder_->Stop();
2099 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002100 stats_proxy_.reset();
2101
2102 EXPECT_EQ(0,
2103 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2104}
2105
mflodmancc3d4422017-08-03 08:27:51 -07002106TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002107 MockBitrateObserver bitrate_observer;
mflodmancc3d4422017-08-03 08:27:51 -07002108 video_stream_encoder_->SetBitrateObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002109
2110 const int kDefaultFps = 30;
2111 const BitrateAllocation expected_bitrate =
2112 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002113 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002114
2115 // First called on bitrate updated, then again on first frame.
2116 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2117 .Times(2);
mflodmancc3d4422017-08-03 08:27:51 -07002118 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002119
2120 const int64_t kStartTimeMs = 1;
2121 video_source_.IncomingCapturedFrame(
2122 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002123 WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002124
2125 // Not called on second frame.
2126 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2127 .Times(0);
2128 video_source_.IncomingCapturedFrame(
2129 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002130 WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002131
2132 // Called after a process interval.
2133 const int64_t kProcessIntervalMs =
2134 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang4847ae62017-06-27 07:06:52 -07002135 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec *
2136 (kProcessIntervalMs + (1000 / kDefaultFps)));
sprang57c2fff2017-01-16 06:24:02 -08002137 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2138 .Times(1);
2139 video_source_.IncomingCapturedFrame(CreateFrame(
2140 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002141 WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002142
mflodmancc3d4422017-08-03 08:27:51 -07002143 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002144}
2145
mflodmancc3d4422017-08-03 08:27:51 -07002146TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
sprangfda496a2017-06-15 04:21:07 -07002147 const int kFrameWidth = 1280;
2148 const int kFrameHeight = 720;
2149 const int kFramerate = 24;
2150
mflodmancc3d4422017-08-03 08:27:51 -07002151 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002152 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002153 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002154 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2155
2156 // Insert a single frame, triggering initial configuration.
2157 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002158 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002159
mflodmancc3d4422017-08-03 08:27:51 -07002160 EXPECT_EQ(
2161 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2162 kDefaultFramerate);
sprangfda496a2017-06-15 04:21:07 -07002163
2164 // Trigger reconfigure encoder (without resetting the entire instance).
2165 VideoEncoderConfig video_encoder_config;
2166 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2167 video_encoder_config.number_of_streams = 1;
2168 video_encoder_config.video_stream_factory =
2169 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07002170 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2171 kMaxPayloadLength, false);
2172 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002173
2174 // Detector should be updated with fps limit from codec config.
mflodmancc3d4422017-08-03 08:27:51 -07002175 EXPECT_EQ(
2176 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2177 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002178
2179 // Trigger overuse, max framerate should be reduced.
2180 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2181 stats.input_frame_rate = kFramerate;
2182 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002183 video_stream_encoder_->TriggerCpuOveruse();
2184 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002185 int adapted_framerate =
mflodmancc3d4422017-08-03 08:27:51 -07002186 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002187 EXPECT_LT(adapted_framerate, kFramerate);
2188
2189 // Trigger underuse, max framerate should go back to codec configured fps.
2190 // Set extra low fps, to make sure it's actually reset, not just incremented.
2191 stats = stats_proxy_->GetStats();
2192 stats.input_frame_rate = adapted_framerate / 2;
2193 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002194 video_stream_encoder_->TriggerCpuNormalUsage();
2195 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2196 EXPECT_EQ(
2197 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2198 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002199
mflodmancc3d4422017-08-03 08:27:51 -07002200 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002201}
2202
mflodmancc3d4422017-08-03 08:27:51 -07002203TEST_F(VideoStreamEncoderTest,
2204 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
sprangfda496a2017-06-15 04:21:07 -07002205 const int kFrameWidth = 1280;
2206 const int kFrameHeight = 720;
2207 const int kLowFramerate = 15;
2208 const int kHighFramerate = 25;
2209
mflodmancc3d4422017-08-03 08:27:51 -07002210 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002211 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002212 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002213 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2214
2215 // Trigger initial configuration.
2216 VideoEncoderConfig video_encoder_config;
2217 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2218 video_encoder_config.number_of_streams = 1;
2219 video_encoder_config.video_stream_factory =
2220 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2221 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002222 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2223 kMaxPayloadLength, false);
2224 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002225
mflodmancc3d4422017-08-03 08:27:51 -07002226 EXPECT_EQ(
2227 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2228 kLowFramerate);
sprangfda496a2017-06-15 04:21:07 -07002229
2230 // Trigger overuse, max framerate should be reduced.
2231 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2232 stats.input_frame_rate = kLowFramerate;
2233 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002234 video_stream_encoder_->TriggerCpuOveruse();
2235 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002236 int adapted_framerate =
mflodmancc3d4422017-08-03 08:27:51 -07002237 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002238 EXPECT_LT(adapted_framerate, kLowFramerate);
2239
2240 // Reconfigure the encoder with a new (higher max framerate), max fps should
2241 // still respect the adaptation.
2242 video_encoder_config.video_stream_factory =
2243 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2244 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002245 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2246 kMaxPayloadLength, false);
2247 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002248
mflodmancc3d4422017-08-03 08:27:51 -07002249 EXPECT_EQ(
2250 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2251 adapted_framerate);
sprangfda496a2017-06-15 04:21:07 -07002252
2253 // Trigger underuse, max framerate should go back to codec configured fps.
2254 stats = stats_proxy_->GetStats();
2255 stats.input_frame_rate = adapted_framerate;
2256 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002257 video_stream_encoder_->TriggerCpuNormalUsage();
2258 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2259 EXPECT_EQ(
2260 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2261 kHighFramerate);
sprangfda496a2017-06-15 04:21:07 -07002262
mflodmancc3d4422017-08-03 08:27:51 -07002263 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002264}
2265
mflodmancc3d4422017-08-03 08:27:51 -07002266TEST_F(VideoStreamEncoderTest,
2267 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002268 const int kFrameWidth = 1280;
2269 const int kFrameHeight = 720;
2270 const int kFramerate = 24;
2271
mflodmancc3d4422017-08-03 08:27:51 -07002272 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002273 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002274 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002275 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2276
2277 // Trigger initial configuration.
2278 VideoEncoderConfig video_encoder_config;
2279 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2280 video_encoder_config.number_of_streams = 1;
2281 video_encoder_config.video_stream_factory =
2282 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2283 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002284 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2285 kMaxPayloadLength, false);
2286 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002287
mflodmancc3d4422017-08-03 08:27:51 -07002288 EXPECT_EQ(
2289 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2290 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002291
2292 // Trigger overuse, max framerate should be reduced.
2293 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2294 stats.input_frame_rate = kFramerate;
2295 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002296 video_stream_encoder_->TriggerCpuOveruse();
2297 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002298 int adapted_framerate =
mflodmancc3d4422017-08-03 08:27:51 -07002299 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002300 EXPECT_LT(adapted_framerate, kFramerate);
2301
2302 // Change degradation preference to not enable framerate scaling. Target
2303 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002304 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002305 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07002306 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2307 EXPECT_EQ(
2308 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2309 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002310
mflodmancc3d4422017-08-03 08:27:51 -07002311 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002312}
2313
mflodmancc3d4422017-08-03 08:27:51 -07002314TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002315 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002316 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002317 const int kWidth = 640;
2318 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002319
asaperssonfab67072017-04-04 05:51:49 -07002320 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002321
2322 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002323 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002324
2325 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002326 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002327
sprangc5d62e22017-04-02 23:53:04 -07002328 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002329
asaperssonfab67072017-04-04 05:51:49 -07002330 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002331 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002332 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002333
2334 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002335 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002336
sprangc5d62e22017-04-02 23:53:04 -07002337 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002338
mflodmancc3d4422017-08-03 08:27:51 -07002339 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002340}
2341
mflodmancc3d4422017-08-03 08:27:51 -07002342TEST_F(VideoStreamEncoderTest,
2343 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002344 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002345 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002346 const int kWidth = 640;
2347 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002348
2349 // We expect the n initial frames to get dropped.
2350 int i;
2351 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002352 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002353 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002354 }
2355 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002356 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002357 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002358
2359 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002360 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002361
mflodmancc3d4422017-08-03 08:27:51 -07002362 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002363}
2364
mflodmancc3d4422017-08-03 08:27:51 -07002365TEST_F(VideoStreamEncoderTest,
2366 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002367 const int kWidth = 640;
2368 const int kHeight = 360;
mflodmancc3d4422017-08-03 08:27:51 -07002369 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002370
2371 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002372 video_stream_encoder_->SetSource(
kthelgason2bc68642017-02-07 07:02:22 -08002373 &video_source_,
2374 VideoSendStream::DegradationPreference::kMaintainResolution);
2375
asaperssonfab67072017-04-04 05:51:49 -07002376 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002377 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002378 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002379
mflodmancc3d4422017-08-03 08:27:51 -07002380 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002381}
2382
mflodmancc3d4422017-08-03 08:27:51 -07002383TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002384 const int kWidth = 640;
2385 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002386 fake_encoder_.SetQualityScaling(false);
mflodmancc3d4422017-08-03 08:27:51 -07002387 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002388
kthelgasonb83797b2017-02-14 11:57:25 -08002389 // Force quality scaler reconfiguration by resetting the source.
mflodmancc3d4422017-08-03 08:27:51 -07002390 video_stream_encoder_->SetSource(
2391 &video_source_,
2392 VideoSendStream::DegradationPreference::kBalanced);
kthelgasonad9010c2017-02-14 00:46:51 -08002393
asaperssonfab67072017-04-04 05:51:49 -07002394 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002395 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002396 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002397
mflodmancc3d4422017-08-03 08:27:51 -07002398 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002399 fake_encoder_.SetQualityScaling(true);
2400}
2401
mflodmancc3d4422017-08-03 08:27:51 -07002402TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002403 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2404 const int kTooSmallWidth = 10;
2405 const int kTooSmallHeight = 10;
mflodmancc3d4422017-08-03 08:27:51 -07002406 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002407
2408 // Enable kMaintainFramerate preference, no initial limitation.
2409 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002410 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07002411 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
2412 VerifyNoLimitation(source.sink_wants());
2413 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2414
2415 // Trigger adapt down, too small frame, expect no change.
2416 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002417 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002418 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002419 VerifyNoLimitation(source.sink_wants());
2420 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2421 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2422
mflodmancc3d4422017-08-03 08:27:51 -07002423 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002424}
2425
mflodmancc3d4422017-08-03 08:27:51 -07002426TEST_F(VideoStreamEncoderTest,
2427 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002428 const int kTooSmallWidth = 10;
2429 const int kTooSmallHeight = 10;
2430 const int kFpsLimit = 7;
mflodmancc3d4422017-08-03 08:27:51 -07002431 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002432
2433 // Enable kBalanced preference, no initial limitation.
2434 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002435 video_stream_encoder_->SetSource(
2436 &source,
2437 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002438 VerifyNoLimitation(source.sink_wants());
2439 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2440 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2441
2442 // Trigger adapt down, expect limited framerate.
2443 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002444 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002445 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002446 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2447 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2448 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2449 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2450
2451 // Trigger adapt down, too small frame, expect no change.
2452 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002453 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002454 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002455 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2456 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2457 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2458 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2459
mflodmancc3d4422017-08-03 08:27:51 -07002460 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002461}
2462
mflodmancc3d4422017-08-03 08:27:51 -07002463TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002464 fake_encoder_.ForceInitEncodeFailure(true);
mflodmancc3d4422017-08-03 08:27:51 -07002465 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002466 ResetEncoder("VP8", 2, 1, true, false);
asapersson02465b82017-04-10 01:12:52 -07002467 const int kFrameWidth = 1280;
2468 const int kFrameHeight = 720;
2469 video_source_.IncomingCapturedFrame(
2470 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002471 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002472 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002473}
2474
sprangb1ca0732017-02-01 08:38:12 -08002475// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002476TEST_F(VideoStreamEncoderTest,
2477 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
2478 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002479
2480 const int kFrameWidth = 1280;
2481 const int kFrameHeight = 720;
2482 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002483 // requested by
2484 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002485 video_source_.set_adaptation_enabled(true);
2486
2487 video_source_.IncomingCapturedFrame(
2488 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002489 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002490
2491 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002492 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002493 video_source_.IncomingCapturedFrame(
2494 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002495 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002496
asaperssonfab67072017-04-04 05:51:49 -07002497 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002498 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002499 video_source_.IncomingCapturedFrame(
2500 CreateFrame(3, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002501 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002502
mflodmancc3d4422017-08-03 08:27:51 -07002503 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002504}
sprangfe627f32017-03-29 08:24:59 -07002505
mflodmancc3d4422017-08-03 08:27:51 -07002506TEST_F(VideoStreamEncoderTest,
2507 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002508 const int kFrameWidth = 1280;
2509 const int kFrameHeight = 720;
sprang4847ae62017-06-27 07:06:52 -07002510 int kFrameIntervalMs = rtc::kNumMillisecsPerSec / max_framerate_;
sprangc5d62e22017-04-02 23:53:04 -07002511
mflodmancc3d4422017-08-03 08:27:51 -07002512 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2513 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07002514 &video_source_,
2515 VideoSendStream::DegradationPreference::kMaintainResolution);
2516 video_source_.set_adaptation_enabled(true);
2517
sprang4847ae62017-06-27 07:06:52 -07002518 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002519
2520 video_source_.IncomingCapturedFrame(
2521 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002522 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002523
2524 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002525 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002526
2527 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002528 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002529 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002530 video_source_.IncomingCapturedFrame(
2531 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002532 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002533 }
2534
2535 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002536 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002537 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002538 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002539 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002540 video_source_.IncomingCapturedFrame(
2541 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002542 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002543 ++num_frames_dropped;
2544 } else {
2545 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2546 }
2547 }
2548
sprang4847ae62017-06-27 07:06:52 -07002549 // Add some slack to account for frames dropped by the frame dropper.
2550 const int kErrorMargin = 1;
2551 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002552 kErrorMargin);
2553
2554 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002555 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002556 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002557 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002558 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002559 video_source_.IncomingCapturedFrame(
2560 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002561 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002562 ++num_frames_dropped;
2563 } else {
2564 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2565 }
2566 }
sprang4847ae62017-06-27 07:06:52 -07002567 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002568 kErrorMargin);
2569
2570 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002571 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002572 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002573 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002574 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002575 video_source_.IncomingCapturedFrame(
2576 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002577 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002578 ++num_frames_dropped;
2579 } else {
2580 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2581 }
2582 }
sprang4847ae62017-06-27 07:06:52 -07002583 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002584 kErrorMargin);
2585
2586 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002587 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002588 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002589 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002590 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002591 video_source_.IncomingCapturedFrame(
2592 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002593 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002594 ++num_frames_dropped;
2595 } else {
2596 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2597 }
2598 }
2599 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2600
mflodmancc3d4422017-08-03 08:27:51 -07002601 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002602}
2603
mflodmancc3d4422017-08-03 08:27:51 -07002604TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002605 const int kFramerateFps = 5;
2606 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
2607 const int kMinFpsFrameInterval = rtc::kNumMillisecsPerSec / kMinFramerateFps;
2608 const int kFrameWidth = 1280;
2609 const int kFrameHeight = 720;
2610
sprang4847ae62017-06-27 07:06:52 -07002611 // Reconfigure encoder with two temporal layers and screensharing, which will
2612 // disable frame dropping and make testing easier.
2613 ResetEncoder("VP8", 1, 2, true, true);
2614
mflodmancc3d4422017-08-03 08:27:51 -07002615 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2616 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07002617 &video_source_,
2618 VideoSendStream::DegradationPreference::kMaintainResolution);
2619 video_source_.set_adaptation_enabled(true);
2620
sprang4847ae62017-06-27 07:06:52 -07002621 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002622
2623 // Trigger overuse as much as we can.
mflodmancc3d4422017-08-03 08:27:51 -07002624 for (int i = 0; i < VideoStreamEncoder::kMaxCpuResolutionDowngrades; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002625 // Insert frames to get a new fps estimate...
2626 for (int j = 0; j < kFramerateFps; ++j) {
2627 video_source_.IncomingCapturedFrame(
2628 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
2629 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002630 }
2631 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002632 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002633 }
2634
2635 // Drain any frame in the pipeline.
sprang4847ae62017-06-27 07:06:52 -07002636 WaitForFrame(kDefaultTimeoutMs);
sprangc5d62e22017-04-02 23:53:04 -07002637
2638 // Insert frames at min fps, all should go through.
2639 for (int i = 0; i < 10; ++i) {
2640 timestamp_ms += kMinFpsFrameInterval;
sprangc5d62e22017-04-02 23:53:04 -07002641 video_source_.IncomingCapturedFrame(
2642 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002643 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002644 }
asaperssonf7e294d2017-06-13 23:25:22 -07002645
mflodmancc3d4422017-08-03 08:27:51 -07002646 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002647}
asaperssonf7e294d2017-06-13 23:25:22 -07002648
mflodmancc3d4422017-08-03 08:27:51 -07002649TEST_F(VideoStreamEncoderTest,
2650 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002651 const int kWidth = 1280;
2652 const int kHeight = 720;
2653 const int64_t kFrameIntervalMs = 150;
2654 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002655 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002656
2657 // Enable kBalanced preference, no initial limitation.
2658 AdaptingFrameForwarder source;
2659 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002660 video_stream_encoder_->SetSource(
2661 &source,
2662 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002663 timestamp_ms += kFrameIntervalMs;
2664 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002665 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002666 VerifyNoLimitation(source.sink_wants());
2667 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2668 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2669 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2670
2671 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002672 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002673 timestamp_ms += kFrameIntervalMs;
2674 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002675 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002676 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2677 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2678 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2679 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2680
2681 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002682 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002683 timestamp_ms += kFrameIntervalMs;
2684 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002685 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002686 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2687 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2688 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2689 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2690
2691 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002692 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002693 timestamp_ms += kFrameIntervalMs;
2694 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002695 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002696 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2697 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2698 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2699 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2700
2701 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002702 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002703 timestamp_ms += kFrameIntervalMs;
2704 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002705 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002706 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2707 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2708 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2709 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2710
2711 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002712 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002713 timestamp_ms += kFrameIntervalMs;
2714 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002715 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002716 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2717 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2718 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2719 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2720
2721 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002722 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002723 timestamp_ms += kFrameIntervalMs;
2724 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002725 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002726 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2727 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2728 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2729 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2730
2731 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002732 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002733 timestamp_ms += kFrameIntervalMs;
2734 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002735 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002736 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2737 rtc::VideoSinkWants last_wants = source.sink_wants();
2738 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2739 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2740 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2741
2742 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002743 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002744 timestamp_ms += kFrameIntervalMs;
2745 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002746 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002747 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2748 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2749 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2750 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2751
2752 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002753 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002754 timestamp_ms += kFrameIntervalMs;
2755 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002756 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002757 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2758 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2759 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2760 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2761
2762 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002763 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002764 timestamp_ms += kFrameIntervalMs;
2765 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002766 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002767 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2768 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2769 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2770 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2771
2772 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002773 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002774 timestamp_ms += kFrameIntervalMs;
2775 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002776 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002777 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2778 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2779 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2780 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2781
2782 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002783 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002784 timestamp_ms += kFrameIntervalMs;
2785 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002786 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002787 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2788 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2789 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2790 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2791
2792 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002793 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002794 timestamp_ms += kFrameIntervalMs;
2795 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002796 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002797 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2798 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2799 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2800 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2801
2802 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002803 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002804 timestamp_ms += kFrameIntervalMs;
2805 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002806 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002807 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2808 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2809 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2810 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2811
2812 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002813 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002814 timestamp_ms += kFrameIntervalMs;
2815 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002816 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002817 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2818 VerifyNoLimitation(source.sink_wants());
2819 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2820 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2821 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2822
2823 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002824 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002825 VerifyNoLimitation(source.sink_wants());
2826 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2827
mflodmancc3d4422017-08-03 08:27:51 -07002828 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002829}
2830
mflodmancc3d4422017-08-03 08:27:51 -07002831TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07002832 const int kWidth = 1280;
2833 const int kHeight = 720;
2834 const int64_t kFrameIntervalMs = 150;
2835 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002836 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002837
2838 // Enable kBalanced preference, no initial limitation.
2839 AdaptingFrameForwarder source;
2840 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002841 video_stream_encoder_->SetSource(
2842 &source,
2843 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002844 timestamp_ms += kFrameIntervalMs;
2845 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002846 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002847 VerifyNoLimitation(source.sink_wants());
2848 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2849 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2850 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2851 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2852 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2853 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2854
2855 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002856 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002857 timestamp_ms += kFrameIntervalMs;
2858 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002859 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002860 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2861 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2862 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2863 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2864 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2865 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2866 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2867
2868 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002869 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002870 timestamp_ms += kFrameIntervalMs;
2871 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002872 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002873 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2874 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2875 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2876 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2877 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2878 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2879 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2880
2881 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002882 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002883 timestamp_ms += kFrameIntervalMs;
2884 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002885 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002886 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2887 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2888 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2889 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2890 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2891 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2892 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2893
2894 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002895 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002896 timestamp_ms += kFrameIntervalMs;
2897 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002898 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002899 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2900 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2901 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2902 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2903 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2904 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2905 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2906
2907 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002908 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002909 timestamp_ms += kFrameIntervalMs;
2910 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002911 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002912 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2913 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2914 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2915 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2916 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2917 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2918 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2919
2920 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002921 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002922 timestamp_ms += kFrameIntervalMs;
2923 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002924 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002925 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2926 VerifyNoLimitation(source.sink_wants());
2927 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2928 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2929 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2930 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2931 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2932 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2933
2934 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002935 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002936 VerifyNoLimitation(source.sink_wants());
2937 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2938 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2939
mflodmancc3d4422017-08-03 08:27:51 -07002940 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002941}
2942
mflodmancc3d4422017-08-03 08:27:51 -07002943TEST_F(VideoStreamEncoderTest,
2944 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07002945 const int kWidth = 640;
2946 const int kHeight = 360;
2947 const int kFpsLimit = 15;
2948 const int64_t kFrameIntervalMs = 150;
2949 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002950 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002951
2952 // Enable kBalanced preference, no initial limitation.
2953 AdaptingFrameForwarder source;
2954 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002955 video_stream_encoder_->SetSource(
2956 &source,
2957 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002958 timestamp_ms += kFrameIntervalMs;
2959 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002960 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002961 VerifyNoLimitation(source.sink_wants());
2962 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2963 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2964 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2965 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2966 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2967 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2968
2969 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002970 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002971 timestamp_ms += kFrameIntervalMs;
2972 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002973 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002974 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2975 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2976 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2977 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2978 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2979 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2980 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2981
2982 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002983 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002984 timestamp_ms += kFrameIntervalMs;
2985 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002986 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002987 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2988 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2989 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2990 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2991 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2992 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2993 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2994
2995 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002996 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002997 timestamp_ms += kFrameIntervalMs;
2998 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002999 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003000 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3001 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3002 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3003 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3004 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3005 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3006 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3007
3008 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003009 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003010 timestamp_ms += kFrameIntervalMs;
3011 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003012 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003013 VerifyNoLimitation(source.sink_wants());
3014 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3015 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3016 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3017 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3018 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3019 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3020
3021 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003022 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003023 VerifyNoLimitation(source.sink_wants());
3024 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3025 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3026
mflodmancc3d4422017-08-03 08:27:51 -07003027 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003028}
3029
mflodmancc3d4422017-08-03 08:27:51 -07003030TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003031 // Simulates simulcast behavior and makes highest stream resolutions divisible
3032 // by 4.
3033 class CroppingVideoStreamFactory
3034 : public VideoEncoderConfig::VideoStreamFactoryInterface {
3035 public:
3036 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
3037 int framerate)
3038 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
3039 EXPECT_GT(num_temporal_layers, 0u);
3040 EXPECT_GT(framerate, 0);
3041 }
3042
3043 private:
3044 std::vector<VideoStream> CreateEncoderStreams(
3045 int width,
3046 int height,
3047 const VideoEncoderConfig& encoder_config) override {
3048 std::vector<VideoStream> streams =
3049 test::CreateVideoStreams(width - width % 4, height - height % 4,
3050 encoder_config);
3051 for (VideoStream& stream : streams) {
3052 stream.temporal_layer_thresholds_bps.resize(num_temporal_layers_ - 1);
3053 stream.max_framerate = framerate_;
3054 }
3055 return streams;
3056 }
3057
3058 const size_t num_temporal_layers_;
3059 const int framerate_;
3060 };
3061
3062 const int kFrameWidth = 1920;
3063 const int kFrameHeight = 1080;
3064 // 3/4 of 1920.
3065 const int kAdaptedFrameWidth = 1440;
3066 // 3/4 of 1080 rounded down to multiple of 4.
3067 const int kAdaptedFrameHeight = 808;
3068 const int kFramerate = 24;
3069
mflodmancc3d4422017-08-03 08:27:51 -07003070 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003071 // Trigger reconfigure encoder (without resetting the entire instance).
3072 VideoEncoderConfig video_encoder_config;
3073 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3074 video_encoder_config.number_of_streams = 1;
3075 video_encoder_config.video_stream_factory =
3076 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003077 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
3078 kMaxPayloadLength, false);
3079 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003080
3081 video_source_.set_adaptation_enabled(true);
3082
3083 video_source_.IncomingCapturedFrame(
3084 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003085 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003086
3087 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003088 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003089 video_source_.IncomingCapturedFrame(
3090 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003091 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003092
mflodmancc3d4422017-08-03 08:27:51 -07003093 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003094}
3095
mflodmancc3d4422017-08-03 08:27:51 -07003096TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003097 const int kFrameWidth = 1280;
3098 const int kFrameHeight = 720;
3099 const int kLowFps = 2;
3100 const int kHighFps = 30;
3101
mflodmancc3d4422017-08-03 08:27:51 -07003102 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003103
3104 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3105 max_framerate_ = kLowFps;
3106
3107 // Insert 2 seconds of 2fps video.
3108 for (int i = 0; i < kLowFps * 2; ++i) {
3109 video_source_.IncomingCapturedFrame(
3110 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3111 WaitForEncodedFrame(timestamp_ms);
3112 timestamp_ms += 1000 / kLowFps;
3113 }
3114
3115 // Make sure encoder is updated with new target.
mflodmancc3d4422017-08-03 08:27:51 -07003116 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003117 video_source_.IncomingCapturedFrame(
3118 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3119 WaitForEncodedFrame(timestamp_ms);
3120 timestamp_ms += 1000 / kLowFps;
3121
3122 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3123
3124 // Insert 30fps frames for just a little more than the forced update period.
3125 const int kVcmTimerIntervalFrames =
3126 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3127 const int kFrameIntervalMs = 1000 / kHighFps;
3128 max_framerate_ = kHighFps;
3129 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3130 video_source_.IncomingCapturedFrame(
3131 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3132 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3133 // be dropped if the encoder hans't been updated with the new higher target
3134 // framerate yet, causing it to overshoot the target bitrate and then
3135 // suffering the wrath of the media optimizer.
3136 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3137 timestamp_ms += kFrameIntervalMs;
3138 }
3139
3140 // Don expect correct measurement just yet, but it should be higher than
3141 // before.
3142 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3143
mflodmancc3d4422017-08-03 08:27:51 -07003144 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003145}
3146
mflodmancc3d4422017-08-03 08:27:51 -07003147TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003148 const int kFrameWidth = 1280;
3149 const int kFrameHeight = 720;
3150 const int kTargetBitrateBps = 1000000;
3151
3152 MockBitrateObserver bitrate_observer;
mflodmancc3d4422017-08-03 08:27:51 -07003153 video_stream_encoder_->SetBitrateObserver(&bitrate_observer);
sprang4847ae62017-06-27 07:06:52 -07003154
3155 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3156 // Initial bitrate update.
mflodmancc3d4422017-08-03 08:27:51 -07003157 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3158 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003159
3160 // Insert a first video frame, causes another bitrate update.
3161 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3162 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3163 video_source_.IncomingCapturedFrame(
3164 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3165 WaitForEncodedFrame(timestamp_ms);
3166
3167 // Next, simulate video suspension due to pacer queue overrun.
mflodmancc3d4422017-08-03 08:27:51 -07003168 video_stream_encoder_->OnBitrateUpdated(0, 0, 1);
sprang4847ae62017-06-27 07:06:52 -07003169
3170 // Skip ahead until a new periodic parameter update should have occured.
3171 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3172 fake_clock_.AdvanceTimeMicros(
3173 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3174 rtc::kNumMicrosecsPerMillisec);
3175
3176 // Bitrate observer should not be called.
3177 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3178 video_source_.IncomingCapturedFrame(
3179 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3180 ExpectDroppedFrame();
3181
mflodmancc3d4422017-08-03 08:27:51 -07003182 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003183}
ilnik6b826ef2017-06-16 06:53:48 -07003184
perkj26091b12016-09-01 01:17:40 -07003185} // namespace webrtc