blob: 02d6d3ec127979345c4ef9a771fd42e9ed213f44 [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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "api/video/i420_buffer.h"
16#include "media/base/videoadapter.h"
17#include "modules/video_coding/codecs/vp8/temporal_layers.h"
18#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
19#include "rtc_base/fakeclock.h"
20#include "rtc_base/logging.h"
21#include "system_wrappers/include/metrics_default.h"
22#include "system_wrappers/include/sleep.h"
23#include "test/encoder_settings.h"
24#include "test/fake_encoder.h"
25#include "test/frame_generator.h"
26#include "test/gmock.h"
27#include "test/gtest.h"
28#include "video/send_statistics_proxy.h"
29#include "video/video_stream_encoder.h"
perkj26091b12016-09-01 01:17:40 -070030
kthelgason33ce8892016-12-09 03:53:59 -080031namespace {
kthelgason33ce8892016-12-09 03:53:59 -080032const int kMinPixelsPerFrame = 320 * 180;
sprangc5d62e22017-04-02 23:53:04 -070033const int kMinFramerateFps = 2;
34const int64_t kFrameTimeoutMs = 100;
emircanbbcc3562017-08-18 00:28:40 -070035const unsigned char kNumSlDummy = 0;
sprangc5d62e22017-04-02 23:53:04 -070036} // namespace
kthelgason33ce8892016-12-09 03:53:59 -080037
perkj26091b12016-09-01 01:17:40 -070038namespace webrtc {
39
kthelgason876222f2016-11-29 01:44:11 -080040using DegredationPreference = VideoSendStream::DegradationPreference;
sprangb1ca0732017-02-01 08:38:12 -080041using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080042using ::testing::_;
43using ::testing::Return;
kthelgason876222f2016-11-29 01:44:11 -080044
perkj803d97f2016-11-01 11:45:46 -070045namespace {
asapersson5f7226f2016-11-25 04:37:00 -080046const size_t kMaxPayloadLength = 1440;
kthelgason2bc68642017-02-07 07:02:22 -080047const int kTargetBitrateBps = 1000000;
48const int kLowTargetBitrateBps = kTargetBitrateBps / 10;
49const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070050const int kDefaultFramerate = 30;
asapersson5f7226f2016-11-25 04:37:00 -080051
perkj803d97f2016-11-01 11:45:46 -070052class TestBuffer : public webrtc::I420Buffer {
53 public:
54 TestBuffer(rtc::Event* event, int width, int height)
55 : I420Buffer(width, height), event_(event) {}
56
57 private:
58 friend class rtc::RefCountedObject<TestBuffer>;
59 ~TestBuffer() override {
60 if (event_)
61 event_->Set();
62 }
63 rtc::Event* const event_;
64};
65
mflodmancc3d4422017-08-03 08:27:51 -070066class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -070067 public:
Niels Möllereee7ced2017-12-01 11:25:01 +010068 VideoStreamEncoderUnderTest(
69 SendStatisticsProxy* stats_proxy,
70 const VideoSendStream::Config::EncoderSettings& settings)
mflodmancc3d4422017-08-03 08:27:51 -070071 : VideoStreamEncoder(
72 1 /* number_of_cores */,
73 stats_proxy,
74 settings,
75 nullptr /* pre_encode_callback */,
76 nullptr /* encoder_timing */,
77 std::unique_ptr<OveruseFrameDetector>(
Niels Möllereee7ced2017-12-01 11:25:01 +010078 overuse_detector_ = new OveruseFrameDetector(
mflodmancc3d4422017-08-03 08:27:51 -070079 GetCpuOveruseOptions(settings.full_overuse_time),
80 this,
81 nullptr,
82 stats_proxy))) {}
perkj803d97f2016-11-01 11:45:46 -070083
sprangb1ca0732017-02-01 08:38:12 -080084 void PostTaskAndWait(bool down, AdaptReason reason) {
perkj803d97f2016-11-01 11:45:46 -070085 rtc::Event event(false, false);
kthelgason876222f2016-11-29 01:44:11 -080086 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -080087 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -070088 event.Set();
89 });
perkj070ba852017-02-16 15:46:27 -080090 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -070091 }
92
kthelgason2fc52542017-03-03 00:24:41 -080093 // This is used as a synchronisation mechanism, to make sure that the
94 // encoder queue is not blocked before we start sending it frames.
95 void WaitUntilTaskQueueIsIdle() {
96 rtc::Event event(false, false);
97 encoder_queue()->PostTask([&event] {
98 event.Set();
99 });
100 ASSERT_TRUE(event.Wait(5000));
101 }
102
sprangb1ca0732017-02-01 08:38:12 -0800103 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800104
sprangb1ca0732017-02-01 08:38:12 -0800105 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800106
sprangb1ca0732017-02-01 08:38:12 -0800107 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800108
sprangb1ca0732017-02-01 08:38:12 -0800109 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700110
Niels Möllereee7ced2017-12-01 11:25:01 +0100111 OveruseFrameDetector* overuse_detector_;
perkj803d97f2016-11-01 11:45:46 -0700112};
113
asapersson5f7226f2016-11-25 04:37:00 -0800114class VideoStreamFactory
115 : public VideoEncoderConfig::VideoStreamFactoryInterface {
116 public:
sprangfda496a2017-06-15 04:21:07 -0700117 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
118 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800119 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700120 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800121 }
122
123 private:
124 std::vector<VideoStream> CreateEncoderStreams(
125 int width,
126 int height,
127 const VideoEncoderConfig& encoder_config) override {
128 std::vector<VideoStream> streams =
129 test::CreateVideoStreams(width, height, encoder_config);
130 for (VideoStream& stream : streams) {
131 stream.temporal_layer_thresholds_bps.resize(num_temporal_layers_ - 1);
sprangfda496a2017-06-15 04:21:07 -0700132 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800133 }
134 return streams;
135 }
sprangfda496a2017-06-15 04:21:07 -0700136
asapersson5f7226f2016-11-25 04:37:00 -0800137 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700138 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800139};
140
ilnik6b826ef2017-06-16 06:53:48 -0700141
sprangb1ca0732017-02-01 08:38:12 -0800142class AdaptingFrameForwarder : public test::FrameForwarder {
143 public:
144 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700145 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800146
147 void set_adaptation_enabled(bool enabled) {
148 rtc::CritScope cs(&crit_);
149 adaptation_enabled_ = enabled;
150 }
151
asaperssonfab67072017-04-04 05:51:49 -0700152 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800153 rtc::CritScope cs(&crit_);
154 return adaptation_enabled_;
155 }
156
asapersson09f05612017-05-15 23:40:18 -0700157 rtc::VideoSinkWants last_wants() const {
158 rtc::CritScope cs(&crit_);
159 return last_wants_;
160 }
161
sprangb1ca0732017-02-01 08:38:12 -0800162 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
163 int cropped_width = 0;
164 int cropped_height = 0;
165 int out_width = 0;
166 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700167 if (adaption_enabled()) {
168 if (adapter_.AdaptFrameResolution(
169 video_frame.width(), video_frame.height(),
170 video_frame.timestamp_us() * 1000, &cropped_width,
171 &cropped_height, &out_width, &out_height)) {
172 VideoFrame adapted_frame(new rtc::RefCountedObject<TestBuffer>(
173 nullptr, out_width, out_height),
174 99, 99, kVideoRotation_0);
175 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
176 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
177 }
sprangb1ca0732017-02-01 08:38:12 -0800178 } else {
179 test::FrameForwarder::IncomingCapturedFrame(video_frame);
180 }
181 }
182
183 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
184 const rtc::VideoSinkWants& wants) override {
185 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700186 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700187 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
188 wants.max_pixel_count,
189 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800190 test::FrameForwarder::AddOrUpdateSink(sink, wants);
191 }
sprangb1ca0732017-02-01 08:38:12 -0800192 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700193 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
194 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
sprangb1ca0732017-02-01 08:38:12 -0800195};
sprangc5d62e22017-04-02 23:53:04 -0700196
197class MockableSendStatisticsProxy : public SendStatisticsProxy {
198 public:
199 MockableSendStatisticsProxy(Clock* clock,
200 const VideoSendStream::Config& config,
201 VideoEncoderConfig::ContentType content_type)
202 : SendStatisticsProxy(clock, config, content_type) {}
203
204 VideoSendStream::Stats GetStats() override {
205 rtc::CritScope cs(&lock_);
206 if (mock_stats_)
207 return *mock_stats_;
208 return SendStatisticsProxy::GetStats();
209 }
210
211 void SetMockStats(const VideoSendStream::Stats& stats) {
212 rtc::CritScope cs(&lock_);
213 mock_stats_.emplace(stats);
214 }
215
216 void ResetMockStats() {
217 rtc::CritScope cs(&lock_);
218 mock_stats_.reset();
219 }
220
221 private:
222 rtc::CriticalSection lock_;
danilchapa37de392017-09-09 04:17:22 -0700223 rtc::Optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700224};
225
sprang4847ae62017-06-27 07:06:52 -0700226class MockBitrateObserver : public VideoBitrateAllocationObserver {
227 public:
228 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const BitrateAllocation&));
229};
230
perkj803d97f2016-11-01 11:45:46 -0700231} // namespace
232
mflodmancc3d4422017-08-03 08:27:51 -0700233class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700234 public:
235 static const int kDefaultTimeoutMs = 30 * 1000;
236
mflodmancc3d4422017-08-03 08:27:51 -0700237 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700238 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700239 codec_width_(320),
240 codec_height_(240),
sprang4847ae62017-06-27 07:06:52 -0700241 max_framerate_(30),
perkj26091b12016-09-01 01:17:40 -0700242 fake_encoder_(),
sprangc5d62e22017-04-02 23:53:04 -0700243 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700244 Clock::GetRealTimeClock(),
245 video_send_config_,
246 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700247 sink_(&fake_encoder_) {}
248
249 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700250 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700251 video_send_config_ = VideoSendStream::Config(nullptr);
252 video_send_config_.encoder_settings.encoder = &fake_encoder_;
253 video_send_config_.encoder_settings.payload_name = "FAKE";
254 video_send_config_.encoder_settings.payload_type = 125;
255
Per512ecb32016-09-23 15:52:06 +0200256 VideoEncoderConfig video_encoder_config;
perkjfa10b552016-10-02 23:45:26 -0700257 test::FillEncoderConfiguration(1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700258 video_encoder_config.video_stream_factory =
259 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100260 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700261
262 // Framerate limit is specified by the VideoStreamFactory.
263 std::vector<VideoStream> streams =
264 video_encoder_config.video_stream_factory->CreateEncoderStreams(
265 codec_width_, codec_height_, video_encoder_config);
266 max_framerate_ = streams[0].max_framerate;
267 fake_clock_.SetTimeMicros(1234);
268
asapersson5f7226f2016-11-25 04:37:00 -0800269 ConfigureEncoder(std::move(video_encoder_config), true /* nack_enabled */);
270 }
271
272 void ConfigureEncoder(VideoEncoderConfig video_encoder_config,
273 bool nack_enabled) {
mflodmancc3d4422017-08-03 08:27:51 -0700274 if (video_stream_encoder_)
275 video_stream_encoder_->Stop();
276 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
perkj803d97f2016-11-01 11:45:46 -0700277 stats_proxy_.get(), video_send_config_.encoder_settings));
mflodmancc3d4422017-08-03 08:27:51 -0700278 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
279 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -0700280 &video_source_,
281 VideoSendStream::DegradationPreference::kMaintainFramerate);
mflodmancc3d4422017-08-03 08:27:51 -0700282 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
283 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
284 kMaxPayloadLength, nack_enabled);
285 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800286 }
287
288 void ResetEncoder(const std::string& payload_name,
289 size_t num_streams,
290 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700291 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700292 bool nack_enabled,
293 bool screenshare) {
asapersson5f7226f2016-11-25 04:37:00 -0800294 video_send_config_.encoder_settings.payload_name = payload_name;
295
296 VideoEncoderConfig video_encoder_config;
297 video_encoder_config.number_of_streams = num_streams;
kthelgason2bc68642017-02-07 07:02:22 -0800298 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800299 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700300 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
301 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700302 video_encoder_config.content_type =
303 screenshare ? VideoEncoderConfig::ContentType::kScreen
304 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700305 if (payload_name == "VP9") {
306 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
307 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
308 video_encoder_config.encoder_specific_settings =
309 new rtc::RefCountedObject<
310 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
311 }
asapersson5f7226f2016-11-25 04:37:00 -0800312 ConfigureEncoder(std::move(video_encoder_config), nack_enabled);
perkj26091b12016-09-01 01:17:40 -0700313 }
314
sprang57c2fff2017-01-16 06:24:02 -0800315 VideoFrame CreateFrame(int64_t ntp_time_ms,
316 rtc::Event* destruction_event) const {
Per512ecb32016-09-23 15:52:06 +0200317 VideoFrame frame(new rtc::RefCountedObject<TestBuffer>(
318 destruction_event, codec_width_, codec_height_),
319 99, 99, kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800320 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700321 return frame;
322 }
323
sprang57c2fff2017-01-16 06:24:02 -0800324 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
perkj803d97f2016-11-01 11:45:46 -0700325 VideoFrame frame(
326 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height), 99, 99,
327 kVideoRotation_0);
sprang57c2fff2017-01-16 06:24:02 -0800328 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700329 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700330 return frame;
331 }
332
asapersson02465b82017-04-10 01:12:52 -0700333 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700334 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700335 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
336 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700337 }
338
asapersson09f05612017-05-15 23:40:18 -0700339 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
340 const rtc::VideoSinkWants& wants2) {
341 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
342 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
343 }
344
345 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
346 const rtc::VideoSinkWants& wants2) {
347 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
348 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
349 EXPECT_GT(wants1.max_pixel_count, 0);
350 }
351
352 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
353 const rtc::VideoSinkWants& wants2) {
354 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
355 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
356 }
357
asaperssonf7e294d2017-06-13 23:25:22 -0700358 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
359 const rtc::VideoSinkWants& wants2) {
360 EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
361 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
362 }
363
364 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
365 const rtc::VideoSinkWants& wants2) {
366 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
367 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
368 }
369
370 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
371 const rtc::VideoSinkWants& wants2) {
372 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
373 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
374 }
375
376 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
377 const rtc::VideoSinkWants& wants2) {
378 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
379 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
380 EXPECT_GT(wants1.max_pixel_count, 0);
381 }
382
383 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
384 const rtc::VideoSinkWants& wants2) {
385 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
386 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
387 }
388
asapersson09f05612017-05-15 23:40:18 -0700389 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
390 int pixel_count) {
391 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700392 EXPECT_LT(wants.max_pixel_count, pixel_count);
393 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700394 }
395
396 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
397 EXPECT_LT(wants.max_framerate_fps, fps);
398 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
399 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700400 }
401
asaperssonf7e294d2017-06-13 23:25:22 -0700402 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
403 int expected_fps) {
404 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
405 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
406 EXPECT_FALSE(wants.target_pixel_count);
407 }
408
sprang4847ae62017-06-27 07:06:52 -0700409 void WaitForEncodedFrame(int64_t expected_ntp_time) {
410 sink_.WaitForEncodedFrame(expected_ntp_time);
411 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
412 }
413
414 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
415 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
416 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
417 return ok;
418 }
419
420 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
421 sink_.WaitForEncodedFrame(expected_width, expected_height);
422 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
423 }
424
425 void ExpectDroppedFrame() {
426 sink_.ExpectDroppedFrame();
427 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
428 }
429
430 bool WaitForFrame(int64_t timeout_ms) {
431 bool ok = sink_.WaitForFrame(timeout_ms);
432 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec / max_framerate_);
433 return ok;
434 }
435
perkj26091b12016-09-01 01:17:40 -0700436 class TestEncoder : public test::FakeEncoder {
437 public:
438 TestEncoder()
439 : FakeEncoder(Clock::GetRealTimeClock()),
440 continue_encode_event_(false, false) {}
441
asaperssonfab67072017-04-04 05:51:49 -0700442 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800443 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700444 return config_;
445 }
446
447 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800448 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700449 block_next_encode_ = true;
450 }
451
kthelgason876222f2016-11-29 01:44:11 -0800452 VideoEncoder::ScalingSettings GetScalingSettings() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800453 rtc::CritScope lock(&local_crit_sect_);
kthelgasonad9010c2017-02-14 00:46:51 -0800454 if (quality_scaling_)
asapersson142fcc92017-08-17 08:58:54 -0700455 return VideoEncoder::ScalingSettings(true, 1, 2, kMinPixelsPerFrame);
kthelgasonad9010c2017-02-14 00:46:51 -0800456 return VideoEncoder::ScalingSettings(false);
kthelgason876222f2016-11-29 01:44:11 -0800457 }
458
perkjfa10b552016-10-02 23:45:26 -0700459 void ContinueEncode() { continue_encode_event_.Set(); }
460
461 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
462 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800463 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700464 EXPECT_EQ(timestamp_, timestamp);
465 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
466 }
467
kthelgason2fc52542017-03-03 00:24:41 -0800468 void SetQualityScaling(bool b) {
469 rtc::CritScope lock(&local_crit_sect_);
470 quality_scaling_ = b;
471 }
kthelgasonad9010c2017-02-14 00:46:51 -0800472
sprangfe627f32017-03-29 08:24:59 -0700473 void ForceInitEncodeFailure(bool force_failure) {
474 rtc::CritScope lock(&local_crit_sect_);
475 force_init_encode_failed_ = force_failure;
476 }
477
perkjfa10b552016-10-02 23:45:26 -0700478 private:
perkj26091b12016-09-01 01:17:40 -0700479 int32_t Encode(const VideoFrame& input_image,
480 const CodecSpecificInfo* codec_specific_info,
481 const std::vector<FrameType>* frame_types) override {
482 bool block_encode;
483 {
brandtre78d2662017-01-16 05:57:16 -0800484 rtc::CritScope lock(&local_crit_sect_);
perkj26091b12016-09-01 01:17:40 -0700485 EXPECT_GT(input_image.timestamp(), timestamp_);
486 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
487 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
488
489 timestamp_ = input_image.timestamp();
490 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700491 last_input_width_ = input_image.width();
492 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700493 block_encode = block_next_encode_;
494 block_next_encode_ = false;
495 }
496 int32_t result =
497 FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
498 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700499 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700500 return result;
501 }
502
sprangfe627f32017-03-29 08:24:59 -0700503 int32_t InitEncode(const VideoCodec* config,
504 int32_t number_of_cores,
505 size_t max_payload_size) override {
506 int res =
507 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
508 rtc::CritScope lock(&local_crit_sect_);
509 if (config->codecType == kVideoCodecVP8 && config->VP8().tl_factory) {
510 // Simulate setting up temporal layers, in order to validate the life
511 // cycle of these objects.
512 int num_streams = std::max<int>(1, config->numberOfSimulcastStreams);
513 int num_temporal_layers =
514 std::max<int>(1, config->VP8().numberOfTemporalLayers);
515 for (int i = 0; i < num_streams; ++i) {
516 allocated_temporal_layers_.emplace_back(
517 config->VP8().tl_factory->Create(i, num_temporal_layers, 42));
518 }
519 }
520 if (force_init_encode_failed_)
521 return -1;
522 return res;
523 }
524
brandtre78d2662017-01-16 05:57:16 -0800525 rtc::CriticalSection local_crit_sect_;
danilchapa37de392017-09-09 04:17:22 -0700526 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700527 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700528 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
529 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
530 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
531 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
532 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
sprangfe627f32017-03-29 08:24:59 -0700533 std::vector<std::unique_ptr<TemporalLayers>> allocated_temporal_layers_
danilchapa37de392017-09-09 04:17:22 -0700534 RTC_GUARDED_BY(local_crit_sect_);
535 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700536 };
537
mflodmancc3d4422017-08-03 08:27:51 -0700538 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700539 public:
540 explicit TestSink(TestEncoder* test_encoder)
541 : test_encoder_(test_encoder), encoded_frame_event_(false, false) {}
542
perkj26091b12016-09-01 01:17:40 -0700543 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700544 EXPECT_TRUE(
545 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
546 }
547
548 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
549 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700550 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700551 if (!encoded_frame_event_.Wait(timeout_ms))
552 return false;
perkj26091b12016-09-01 01:17:40 -0700553 {
554 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800555 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700556 }
557 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700558 return true;
perkj26091b12016-09-01 01:17:40 -0700559 }
560
sprangb1ca0732017-02-01 08:38:12 -0800561 void WaitForEncodedFrame(uint32_t expected_width,
562 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700563 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
564 CheckLastFrameSizeMathces(expected_width, expected_height);
565 }
566
567 void CheckLastFrameSizeMathces(uint32_t expected_width,
568 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800569 uint32_t width = 0;
570 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800571 {
572 rtc::CritScope lock(&crit_);
573 width = last_width_;
574 height = last_height_;
575 }
576 EXPECT_EQ(expected_height, height);
577 EXPECT_EQ(expected_width, width);
578 }
579
kthelgason2fc52542017-03-03 00:24:41 -0800580 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800581
sprangc5d62e22017-04-02 23:53:04 -0700582 bool WaitForFrame(int64_t timeout_ms) {
583 return encoded_frame_event_.Wait(timeout_ms);
584 }
585
perkj26091b12016-09-01 01:17:40 -0700586 void SetExpectNoFrames() {
587 rtc::CritScope lock(&crit_);
588 expect_frames_ = false;
589 }
590
asaperssonfab67072017-04-04 05:51:49 -0700591 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200592 rtc::CritScope lock(&crit_);
593 return number_of_reconfigurations_;
594 }
595
asaperssonfab67072017-04-04 05:51:49 -0700596 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200597 rtc::CritScope lock(&crit_);
598 return min_transmit_bitrate_bps_;
599 }
600
perkj26091b12016-09-01 01:17:40 -0700601 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700602 Result OnEncodedImage(
603 const EncodedImage& encoded_image,
604 const CodecSpecificInfo* codec_specific_info,
605 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200606 rtc::CritScope lock(&crit_);
607 EXPECT_TRUE(expect_frames_);
sprangb1ca0732017-02-01 08:38:12 -0800608 last_timestamp_ = encoded_image._timeStamp;
609 last_width_ = encoded_image._encodedWidth;
610 last_height_ = encoded_image._encodedHeight;
Per512ecb32016-09-23 15:52:06 +0200611 encoded_frame_event_.Set();
sprangb1ca0732017-02-01 08:38:12 -0800612 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200613 }
614
615 void OnEncoderConfigurationChanged(std::vector<VideoStream> streams,
616 int min_transmit_bitrate_bps) override {
617 rtc::CriticalSection crit_;
618 ++number_of_reconfigurations_;
619 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
620 }
621
perkj26091b12016-09-01 01:17:40 -0700622 rtc::CriticalSection crit_;
623 TestEncoder* test_encoder_;
624 rtc::Event encoded_frame_event_;
sprangb1ca0732017-02-01 08:38:12 -0800625 uint32_t last_timestamp_ = 0;
626 uint32_t last_height_ = 0;
627 uint32_t last_width_ = 0;
perkj26091b12016-09-01 01:17:40 -0700628 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +0200629 int number_of_reconfigurations_ = 0;
630 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -0700631 };
632
633 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +0100634 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +0200635 int codec_width_;
636 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -0700637 int max_framerate_;
perkj26091b12016-09-01 01:17:40 -0700638 TestEncoder fake_encoder_;
sprangc5d62e22017-04-02 23:53:04 -0700639 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -0700640 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -0800641 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -0700642 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -0700643 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -0700644};
645
mflodmancc3d4422017-08-03 08:27:51 -0700646TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
647 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700648 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700649 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -0700650 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -0700651 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -0700652 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700653}
654
mflodmancc3d4422017-08-03 08:27:51 -0700655TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -0700656 // Dropped since no target bitrate has been set.
657 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700658 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
659 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700660
mflodmancc3d4422017-08-03 08:27:51 -0700661 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700662
perkja49cbd32016-09-16 07:53:41 -0700663 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700664 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700665 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700666}
667
mflodmancc3d4422017-08-03 08:27:51 -0700668TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
669 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700670 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700671 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700672
mflodmancc3d4422017-08-03 08:27:51 -0700673 video_stream_encoder_->OnBitrateUpdated(0, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700674 // Dropped since bitrate is zero.
perkja49cbd32016-09-16 07:53:41 -0700675 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkj26091b12016-09-01 01:17:40 -0700676
mflodmancc3d4422017-08-03 08:27:51 -0700677 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700678 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700679 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -0700680 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700681}
682
mflodmancc3d4422017-08-03 08:27:51 -0700683TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
684 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkja49cbd32016-09-16 07:53:41 -0700685 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700686 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700687
688 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -0700689 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -0700690
perkja49cbd32016-09-16 07:53:41 -0700691 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700692 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -0700693 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700694}
695
mflodmancc3d4422017-08-03 08:27:51 -0700696TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
697 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700698
perkja49cbd32016-09-16 07:53:41 -0700699 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700700 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700701
mflodmancc3d4422017-08-03 08:27:51 -0700702 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700703 sink_.SetExpectNoFrames();
704 rtc::Event frame_destroyed_event(false, false);
perkja49cbd32016-09-16 07:53:41 -0700705 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
706 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700707}
708
mflodmancc3d4422017-08-03 08:27:51 -0700709TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
710 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj26091b12016-09-01 01:17:40 -0700711
712 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -0700713 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700714 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -0700715 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
716 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -0700717 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
718 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -0700719 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -0700720 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -0700721
mflodmancc3d4422017-08-03 08:27:51 -0700722 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -0700723}
724
mflodmancc3d4422017-08-03 08:27:51 -0700725TEST_F(VideoStreamEncoderTest,
726 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
727 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Per21d45d22016-10-30 21:37:57 +0100728 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200729
730 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200731 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700732 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100733 // The encoder will have been configured once when the first frame is
734 // received.
735 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +0200736
737 VideoEncoderConfig video_encoder_config;
perkjfa10b552016-10-02 23:45:26 -0700738 test::FillEncoderConfiguration(1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +0200739 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -0700740 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
741 kMaxPayloadLength,
742 true /* nack_enabled */);
Per512ecb32016-09-23 15:52:06 +0200743
744 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +0200745 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700746 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +0100747 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -0700748 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -0700749
mflodmancc3d4422017-08-03 08:27:51 -0700750 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -0700751}
752
mflodmancc3d4422017-08-03 08:27:51 -0700753TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
754 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkjfa10b552016-10-02 23:45:26 -0700755
756 // Capture a frame and wait for it to synchronize with the encoder thread.
757 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700758 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +0100759 // The encoder will have been configured once.
760 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700761 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
762 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
763
764 codec_width_ *= 2;
765 codec_height_ *= 2;
766 // Capture a frame with a higher resolution and wait for it to synchronize
767 // with the encoder thread.
768 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700769 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -0700770 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
771 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +0100772 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -0700773
mflodmancc3d4422017-08-03 08:27:51 -0700774 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -0700775}
776
mflodmancc3d4422017-08-03 08:27:51 -0700777TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOffFor1S1TLWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800778 const bool kNackEnabled = true;
779 const size_t kNumStreams = 1;
780 const size_t kNumTl = 1;
emircanbbcc3562017-08-18 00:28:40 -0700781 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700782 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800783
784 // Capture a frame and wait for it to synchronize with the encoder thread.
785 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700786 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800787 // The encoder have been configured once when the first frame is received.
788 EXPECT_EQ(1, sink_.number_of_reconfigurations());
789 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
790 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
791 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
792 // Resilience is off for no temporal layers with nack on.
793 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700794 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800795}
796
mflodmancc3d4422017-08-03 08:27:51 -0700797TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOffFor2S1TlWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800798 const bool kNackEnabled = true;
799 const size_t kNumStreams = 2;
800 const size_t kNumTl = 1;
emircanbbcc3562017-08-18 00:28:40 -0700801 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700802 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800803
804 // Capture a frame and wait for it to synchronize with the encoder thread.
805 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700806 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800807 // The encoder have been configured once when the first frame is received.
808 EXPECT_EQ(1, sink_.number_of_reconfigurations());
809 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
810 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
811 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
812 // Resilience is off for no temporal layers and >1 streams with nack on.
813 EXPECT_EQ(kResilienceOff, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700814 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800815}
816
mflodmancc3d4422017-08-03 08:27:51 -0700817TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOnFor1S1TLWithNackDisabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800818 const bool kNackEnabled = false;
819 const size_t kNumStreams = 1;
820 const size_t kNumTl = 1;
emircanbbcc3562017-08-18 00:28:40 -0700821 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700822 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800823
824 // Capture a frame and wait for it to synchronize with the encoder thread.
825 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700826 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800827 // The encoder have been configured once when the first frame is received.
828 EXPECT_EQ(1, sink_.number_of_reconfigurations());
829 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
830 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
831 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
832 // Resilience is on for no temporal layers with nack off.
833 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700834 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800835}
836
mflodmancc3d4422017-08-03 08:27:51 -0700837TEST_F(VideoStreamEncoderTest, Vp8ResilienceIsOnFor1S2TlWithNackEnabled) {
asapersson5f7226f2016-11-25 04:37:00 -0800838 const bool kNackEnabled = true;
839 const size_t kNumStreams = 1;
840 const size_t kNumTl = 2;
emircanbbcc3562017-08-18 00:28:40 -0700841 ResetEncoder("VP8", kNumStreams, kNumTl, kNumSlDummy, kNackEnabled, false);
mflodmancc3d4422017-08-03 08:27:51 -0700842 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800843
844 // Capture a frame and wait for it to synchronize with the encoder thread.
845 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -0700846 WaitForEncodedFrame(1);
asapersson5f7226f2016-11-25 04:37:00 -0800847 // The encoder have been configured once when the first frame is received.
848 EXPECT_EQ(1, sink_.number_of_reconfigurations());
849 EXPECT_EQ(kVideoCodecVP8, fake_encoder_.codec_config().codecType);
850 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
851 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP8()->numberOfTemporalLayers);
852 // Resilience is on for temporal layers.
853 EXPECT_EQ(kResilientStream, fake_encoder_.codec_config().VP8()->resilience);
mflodmancc3d4422017-08-03 08:27:51 -0700854 video_stream_encoder_->Stop();
asapersson5f7226f2016-11-25 04:37:00 -0800855}
856
emircanbbcc3562017-08-18 00:28:40 -0700857TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOffFor1SL1TLWithNackEnabled) {
858 const bool kNackEnabled = true;
859 const size_t kNumStreams = 1;
860 const size_t kNumTl = 1;
861 const unsigned char kNumSl = 1;
862 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
863 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
864
865 // Capture a frame and wait for it to synchronize with the encoder thread.
866 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
867 sink_.WaitForEncodedFrame(1);
868 // The encoder have been configured once when the first frame is received.
869 EXPECT_EQ(1, sink_.number_of_reconfigurations());
870 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
871 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
872 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
873 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
874 // Resilience is off for no spatial and temporal layers with nack on.
875 EXPECT_FALSE(fake_encoder_.codec_config().VP9()->resilienceOn);
876 video_stream_encoder_->Stop();
877}
878
879TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOnFor1SL1TLWithNackDisabled) {
880 const bool kNackEnabled = false;
881 const size_t kNumStreams = 1;
882 const size_t kNumTl = 1;
883 const unsigned char kNumSl = 1;
884 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
885 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
886
887 // Capture a frame and wait for it to synchronize with the encoder thread.
888 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
889 sink_.WaitForEncodedFrame(1);
890 // The encoder have been configured once when the first frame is received.
891 EXPECT_EQ(1, sink_.number_of_reconfigurations());
892 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
893 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
894 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
895 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
896 // Resilience is on if nack is off.
897 EXPECT_TRUE(fake_encoder_.codec_config().VP9()->resilienceOn);
898 video_stream_encoder_->Stop();
899}
900
901TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOnFor2SL1TLWithNackEnabled) {
902 const bool kNackEnabled = true;
903 const size_t kNumStreams = 1;
904 const size_t kNumTl = 1;
905 const unsigned char kNumSl = 2;
906 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
907 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
908
909 // Capture a frame and wait for it to synchronize with the encoder thread.
910 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
911 sink_.WaitForEncodedFrame(1);
912 // The encoder have been configured once when the first frame is received.
913 EXPECT_EQ(1, sink_.number_of_reconfigurations());
914 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
915 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
916 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
917 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
918 // Resilience is on for spatial layers.
919 EXPECT_TRUE(fake_encoder_.codec_config().VP9()->resilienceOn);
920 video_stream_encoder_->Stop();
921}
922
923TEST_F(VideoStreamEncoderTest, Vp9ResilienceIsOnFor1SL2TLWithNackEnabled) {
924 const bool kNackEnabled = true;
925 const size_t kNumStreams = 1;
926 const size_t kNumTl = 2;
927 const unsigned char kNumSl = 1;
928 ResetEncoder("VP9", kNumStreams, kNumTl, kNumSl, kNackEnabled, false);
929 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
930
931 // Capture a frame and wait for it to synchronize with the encoder thread.
932 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
933 sink_.WaitForEncodedFrame(1);
934 // The encoder have been configured once when the first frame is received.
935 EXPECT_EQ(1, sink_.number_of_reconfigurations());
936 EXPECT_EQ(kVideoCodecVP9, fake_encoder_.codec_config().codecType);
937 EXPECT_EQ(kNumStreams, fake_encoder_.codec_config().numberOfSimulcastStreams);
938 EXPECT_EQ(kNumTl, fake_encoder_.codec_config().VP9()->numberOfTemporalLayers);
939 EXPECT_EQ(kNumSl, fake_encoder_.codec_config().VP9()->numberOfSpatialLayers);
940 // Resilience is on for temporal layers.
941 EXPECT_TRUE(fake_encoder_.codec_config().VP9()->resilienceOn);
942 video_stream_encoder_->Stop();
943}
944
mflodmancc3d4422017-08-03 08:27:51 -0700945TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -0700946 EXPECT_TRUE(video_source_.has_sinks());
947 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -0700948 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -0700949 &new_video_source,
950 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -0700951 EXPECT_FALSE(video_source_.has_sinks());
952 EXPECT_TRUE(new_video_source.has_sinks());
953
mflodmancc3d4422017-08-03 08:27:51 -0700954 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700955}
956
mflodmancc3d4422017-08-03 08:27:51 -0700957TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -0700958 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700959 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -0700960 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -0700961 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -0700962}
963
mflodmancc3d4422017-08-03 08:27:51 -0700964TEST_F(VideoStreamEncoderTest, SinkWantsFromOveruseDetector) {
965 const int kMaxDowngrades = VideoStreamEncoder::kMaxCpuResolutionDowngrades;
966 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -0700967
asapersson02465b82017-04-10 01:12:52 -0700968 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -0700969
970 int frame_width = 1280;
971 int frame_height = 720;
972
mflodmancc3d4422017-08-03 08:27:51 -0700973 // Trigger CPU overuse kMaxCpuDowngrades times. Every time, VideoStreamEncoder
974 // should request lower resolution.
asaperssond0de2952017-04-21 01:47:31 -0700975 for (int i = 1; i <= kMaxDowngrades; ++i) {
perkj803d97f2016-11-01 11:45:46 -0700976 video_source_.IncomingCapturedFrame(
977 CreateFrame(i, frame_width, frame_height));
sprang4847ae62017-06-27 07:06:52 -0700978 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -0700979
mflodmancc3d4422017-08-03 08:27:51 -0700980 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -0700981
sprang84a37592017-02-10 07:04:27 -0800982 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -0700983 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
perkj803d97f2016-11-01 11:45:46 -0700984 frame_width * frame_height);
asaperssond0de2952017-04-21 01:47:31 -0700985 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
986 EXPECT_EQ(i, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -0700987
988 frame_width /= 2;
989 frame_height /= 2;
990 }
991
kthelgason876222f2016-11-29 01:44:11 -0800992 // Trigger CPU overuse one more time. This should not trigger a request for
perkj803d97f2016-11-01 11:45:46 -0700993 // lower resolution.
994 rtc::VideoSinkWants current_wants = video_source_.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -0700995 video_source_.IncomingCapturedFrame(
996 CreateFrame(kMaxDowngrades + 1, frame_width, frame_height));
sprang4847ae62017-06-27 07:06:52 -0700997 WaitForEncodedFrame(kMaxDowngrades + 1);
mflodmancc3d4422017-08-03 08:27:51 -0700998 video_stream_encoder_->TriggerCpuOveruse();
sprang84a37592017-02-10 07:04:27 -0800999 EXPECT_EQ(video_source_.sink_wants().target_pixel_count,
1000 current_wants.target_pixel_count);
perkj803d97f2016-11-01 11:45:46 -07001001 EXPECT_EQ(video_source_.sink_wants().max_pixel_count,
1002 current_wants.max_pixel_count);
asaperssond0de2952017-04-21 01:47:31 -07001003 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1004 EXPECT_EQ(kMaxDowngrades,
1005 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001006
1007 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001008 video_stream_encoder_->TriggerCpuNormalUsage();
sprang84a37592017-02-10 07:04:27 -08001009 EXPECT_EQ(frame_width * frame_height * 5 / 3,
1010 video_source_.sink_wants().target_pixel_count.value_or(0));
1011 EXPECT_EQ(frame_width * frame_height * 4,
sprangc5d62e22017-04-02 23:53:04 -07001012 video_source_.sink_wants().max_pixel_count);
asaperssond0de2952017-04-21 01:47:31 -07001013 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1014 EXPECT_EQ(kMaxDowngrades + 1,
1015 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001016
mflodmancc3d4422017-08-03 08:27:51 -07001017 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001018}
1019
mflodmancc3d4422017-08-03 08:27:51 -07001020TEST_F(VideoStreamEncoderTest,
1021 TestMaxCpuResolutionDowngrades_BalancedMode_NoFpsLimit) {
1022 const int kMaxDowngrades = VideoStreamEncoder::kMaxCpuResolutionDowngrades;
asaperssonf7e294d2017-06-13 23:25:22 -07001023 const int kWidth = 1280;
1024 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001025 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001026
1027 // Enable kBalanced preference, no initial limitation.
1028 AdaptingFrameForwarder source;
1029 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001030 video_stream_encoder_->SetSource(
1031 &source,
1032 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001033 VerifyNoLimitation(source.sink_wants());
1034 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1035 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1036
1037 // Trigger adapt down kMaxCpuDowngrades times.
1038 int t = 1;
1039 for (int i = 1; i <= kMaxDowngrades; ++i) {
1040 source.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1041 sink_.WaitForEncodedFrame(t++);
mflodmancc3d4422017-08-03 08:27:51 -07001042 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07001043 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
1044 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1045 EXPECT_EQ(i, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1046 }
1047
1048 // Trigger adapt down, max cpu downgrades reach, expect no change.
1049 rtc::VideoSinkWants last_wants = source.sink_wants();
1050 source.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1051 sink_.WaitForEncodedFrame(t++);
mflodmancc3d4422017-08-03 08:27:51 -07001052 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07001053 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
1054 EXPECT_EQ(last_wants.max_pixel_count, source.sink_wants().max_pixel_count);
1055 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1056 EXPECT_EQ(kMaxDowngrades,
1057 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1058
1059 // Trigger adapt up kMaxCpuDowngrades times.
1060 for (int i = 1; i <= kMaxDowngrades; ++i) {
1061 source.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1062 sink_.WaitForEncodedFrame(t++);
mflodmancc3d4422017-08-03 08:27:51 -07001063 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07001064 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
1065 EXPECT_GT(source.sink_wants().max_pixel_count, last_wants.max_pixel_count);
1066 EXPECT_EQ(kMaxDowngrades + i,
1067 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1068 }
1069
1070 VerifyNoLimitation(source.sink_wants());
1071 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1072
mflodmancc3d4422017-08-03 08:27:51 -07001073 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001074}
mflodmancc3d4422017-08-03 08:27:51 -07001075TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
1076 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001077 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001078
sprangc5d62e22017-04-02 23:53:04 -07001079 const int kFrameWidth = 1280;
1080 const int kFrameHeight = 720;
1081 const int kFrameIntervalMs = 1000 / 30;
1082
1083 int frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -07001084
kthelgason5e13d412016-12-01 03:59:51 -08001085 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001086 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001087 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001088 frame_timestamp += kFrameIntervalMs;
1089
perkj803d97f2016-11-01 11:45:46 -07001090 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001091 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001092 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001093 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001094 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001095 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -07001096
asapersson0944a802017-04-07 00:57:58 -07001097 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -07001098 // wanted resolution.
1099 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
1100 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
1101 kFrameWidth * kFrameHeight);
1102 EXPECT_EQ(std::numeric_limits<int>::max(),
1103 video_source_.sink_wants().max_framerate_fps);
1104
1105 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -07001106 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001107 video_stream_encoder_->SetSource(
perkj803d97f2016-11-01 11:45:46 -07001108 &new_video_source,
1109 VideoSendStream::DegradationPreference::kMaintainResolution);
1110
sprangc5d62e22017-04-02 23:53:04 -07001111 // Initially no degradation registered.
asapersson02465b82017-04-10 01:12:52 -07001112 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001113
sprangc5d62e22017-04-02 23:53:04 -07001114 // Force an input frame rate to be available, or the adaptation call won't
1115 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -07001116 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -07001117 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -07001118 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -07001119 stats_proxy_->SetMockStats(stats);
1120
mflodmancc3d4422017-08-03 08:27:51 -07001121 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001122 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001123 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001124 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001125 frame_timestamp += kFrameIntervalMs;
1126
1127 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001128 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001129 EXPECT_EQ(std::numeric_limits<int>::max(),
1130 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001131 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001132
asapersson02465b82017-04-10 01:12:52 -07001133 // Turn off degradation completely.
mflodmancc3d4422017-08-03 08:27:51 -07001134 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001135 &new_video_source,
1136 VideoSendStream::DegradationPreference::kDegradationDisabled);
asapersson02465b82017-04-10 01:12:52 -07001137 VerifyNoLimitation(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001138
mflodmancc3d4422017-08-03 08:27:51 -07001139 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001140 new_video_source.IncomingCapturedFrame(
1141 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001142 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001143 frame_timestamp += kFrameIntervalMs;
1144
1145 // Still no degradation.
asapersson02465b82017-04-10 01:12:52 -07001146 VerifyNoLimitation(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001147
1148 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001149 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001150 &new_video_source,
1151 VideoSendStream::DegradationPreference::kMaintainFramerate);
1152 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1153 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001154 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001155 EXPECT_EQ(std::numeric_limits<int>::max(),
1156 new_video_source.sink_wants().max_framerate_fps);
1157
1158 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001159 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001160 &new_video_source,
1161 VideoSendStream::DegradationPreference::kMaintainResolution);
1162 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1163 EXPECT_EQ(std::numeric_limits<int>::max(),
1164 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001165 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001166
mflodmancc3d4422017-08-03 08:27:51 -07001167 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001168}
1169
mflodmancc3d4422017-08-03 08:27:51 -07001170TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
1171 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001172
asaperssonfab67072017-04-04 05:51:49 -07001173 const int kWidth = 1280;
1174 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001175 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001176 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001177 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1178 EXPECT_FALSE(stats.bw_limited_resolution);
1179 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1180
1181 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001182 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001183 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001184 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001185
1186 stats = stats_proxy_->GetStats();
1187 EXPECT_TRUE(stats.bw_limited_resolution);
1188 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1189
1190 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001191 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001192 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001193 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001194
1195 stats = stats_proxy_->GetStats();
1196 EXPECT_FALSE(stats.bw_limited_resolution);
1197 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1198 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1199
mflodmancc3d4422017-08-03 08:27:51 -07001200 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001201}
1202
mflodmancc3d4422017-08-03 08:27:51 -07001203TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
1204 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001205
1206 const int kWidth = 1280;
1207 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001208 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001209 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001210 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1211 EXPECT_FALSE(stats.cpu_limited_resolution);
1212 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1213
1214 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001215 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001216 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001217 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001218
1219 stats = stats_proxy_->GetStats();
1220 EXPECT_TRUE(stats.cpu_limited_resolution);
1221 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1222
1223 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001224 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001225 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001226 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001227
1228 stats = stats_proxy_->GetStats();
1229 EXPECT_FALSE(stats.cpu_limited_resolution);
1230 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001231 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001232
mflodmancc3d4422017-08-03 08:27:51 -07001233 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001234}
1235
mflodmancc3d4422017-08-03 08:27:51 -07001236TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
1237 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001238
asaperssonfab67072017-04-04 05:51:49 -07001239 const int kWidth = 1280;
1240 const int kHeight = 720;
1241 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001242 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001243 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001244 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001245 EXPECT_FALSE(stats.cpu_limited_resolution);
1246 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1247
asaperssonfab67072017-04-04 05:51:49 -07001248 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001249 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001250 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001251 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001252 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001253 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001254 EXPECT_TRUE(stats.cpu_limited_resolution);
1255 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1256
1257 // Set new source with adaptation still enabled.
1258 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001259 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001260 &new_video_source,
1261 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001262
asaperssonfab67072017-04-04 05:51:49 -07001263 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001264 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001265 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001266 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001267 EXPECT_TRUE(stats.cpu_limited_resolution);
1268 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1269
1270 // Set adaptation disabled.
mflodmancc3d4422017-08-03 08:27:51 -07001271 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001272 &new_video_source,
sprangc5d62e22017-04-02 23:53:04 -07001273 VideoSendStream::DegradationPreference::kDegradationDisabled);
kthelgason876222f2016-11-29 01:44:11 -08001274
asaperssonfab67072017-04-04 05:51:49 -07001275 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001276 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001277 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001278 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001279 EXPECT_FALSE(stats.cpu_limited_resolution);
1280 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1281
1282 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001283 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001284 &new_video_source,
1285 VideoSendStream::DegradationPreference::kMaintainFramerate);
kthelgason876222f2016-11-29 01:44:11 -08001286
asaperssonfab67072017-04-04 05:51:49 -07001287 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001288 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001289 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001290 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001291 EXPECT_TRUE(stats.cpu_limited_resolution);
1292 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1293
asaperssonfab67072017-04-04 05:51:49 -07001294 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001295 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001296 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001297 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001298 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001299 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001300 EXPECT_FALSE(stats.cpu_limited_resolution);
1301 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001302 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001303
mflodmancc3d4422017-08-03 08:27:51 -07001304 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001305}
1306
mflodmancc3d4422017-08-03 08:27:51 -07001307TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
1308 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001309
asaperssonfab67072017-04-04 05:51:49 -07001310 const int kWidth = 1280;
1311 const int kHeight = 720;
1312 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001313 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001314 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001315 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001316 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001317 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001318
1319 // Set new source with adaptation still enabled.
1320 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001321 video_stream_encoder_->SetSource(
1322 &new_video_source,
1323 VideoSendStream::DegradationPreference::kBalanced);
kthelgason876222f2016-11-29 01:44:11 -08001324
asaperssonfab67072017-04-04 05:51:49 -07001325 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001326 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001327 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001328 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001329 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001330 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001331
asaperssonfab67072017-04-04 05:51:49 -07001332 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001333 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001334 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001335 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001336 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001337 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001338 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001339 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001340
asaperssonfab67072017-04-04 05:51:49 -07001341 // Set new source with adaptation still enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001342 video_stream_encoder_->SetSource(
1343 &new_video_source,
1344 VideoSendStream::DegradationPreference::kBalanced);
kthelgason876222f2016-11-29 01:44:11 -08001345
asaperssonfab67072017-04-04 05:51:49 -07001346 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001347 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001348 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001349 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001350 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001351 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001352
asapersson02465b82017-04-10 01:12:52 -07001353 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001354 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001355 &new_video_source,
1356 VideoSendStream::DegradationPreference::kMaintainResolution);
1357
asaperssonfab67072017-04-04 05:51:49 -07001358 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001359 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001360 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001361 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001362 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001363 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1364 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001365
mflodmancc3d4422017-08-03 08:27:51 -07001366 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001367}
1368
mflodmancc3d4422017-08-03 08:27:51 -07001369TEST_F(VideoStreamEncoderTest,
1370 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
1371 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001372
1373 const int kWidth = 1280;
1374 const int kHeight = 720;
1375 video_source_.set_adaptation_enabled(true);
1376 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001377 WaitForEncodedFrame(1);
asapersson36e9eb42017-03-31 05:29:12 -07001378 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1379 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1380 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1381
1382 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001383 video_stream_encoder_->TriggerQualityLow();
asapersson36e9eb42017-03-31 05:29:12 -07001384 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001385 WaitForEncodedFrame(2);
asapersson36e9eb42017-03-31 05:29:12 -07001386 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1387 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1388 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1389
1390 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001391 video_stream_encoder_->TriggerCpuOveruse();
asapersson36e9eb42017-03-31 05:29:12 -07001392 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001393 WaitForEncodedFrame(3);
asapersson36e9eb42017-03-31 05:29:12 -07001394 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1395 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1396 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1397
1398 // Set source with adaptation still enabled but quality scaler is off.
1399 fake_encoder_.SetQualityScaling(false);
mflodmancc3d4422017-08-03 08:27:51 -07001400 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001401 &video_source_,
1402 VideoSendStream::DegradationPreference::kMaintainFramerate);
asapersson36e9eb42017-03-31 05:29:12 -07001403
1404 video_source_.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001405 WaitForEncodedFrame(4);
asapersson36e9eb42017-03-31 05:29:12 -07001406 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1407 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1408 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1409
mflodmancc3d4422017-08-03 08:27:51 -07001410 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001411}
1412
mflodmancc3d4422017-08-03 08:27:51 -07001413TEST_F(VideoStreamEncoderTest,
1414 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
1415 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001416
asapersson0944a802017-04-07 00:57:58 -07001417 const int kWidth = 1280;
1418 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001419 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001420
asaperssonfab67072017-04-04 05:51:49 -07001421 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001422 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001423 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001424 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001425 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001426 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1427
asapersson02465b82017-04-10 01:12:52 -07001428 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001429 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001430 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001431 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001432 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001433 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001434 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001435 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1436
1437 // Set new source with adaptation still enabled.
1438 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001439 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001440 &new_video_source,
1441 VideoSendStream::DegradationPreference::kMaintainFramerate);
perkj803d97f2016-11-01 11:45:46 -07001442
1443 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001444 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001445 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001446 stats = stats_proxy_->GetStats();
1447 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001448 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001449 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1450
sprangc5d62e22017-04-02 23:53:04 -07001451 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001452 video_stream_encoder_->SetSource(
perkj803d97f2016-11-01 11:45:46 -07001453 &new_video_source,
1454 VideoSendStream::DegradationPreference::kMaintainResolution);
1455 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001456 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001457 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001458 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001459 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001460 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001461 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001462 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1463
sprangc5d62e22017-04-02 23:53:04 -07001464 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001465 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001466 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1467 mock_stats.input_frame_rate = 30;
1468 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001469 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001470 stats_proxy_->ResetMockStats();
1471
1472 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001473 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001474 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001475
1476 // Framerate now adapted.
1477 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001478 EXPECT_FALSE(stats.cpu_limited_resolution);
1479 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001480 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1481
1482 // Disable CPU adaptation.
mflodmancc3d4422017-08-03 08:27:51 -07001483 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001484 &new_video_source,
1485 VideoSendStream::DegradationPreference::kDegradationDisabled);
1486 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001487 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001488 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001489
1490 stats = stats_proxy_->GetStats();
1491 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001492 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001493 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1494
1495 // Try to trigger overuse. Should not succeed.
1496 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001497 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001498 stats_proxy_->ResetMockStats();
1499
1500 stats = stats_proxy_->GetStats();
1501 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001502 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001503 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1504
1505 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001506 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001507 &video_source_,
1508 VideoSendStream::DegradationPreference::kMaintainFramerate);
asaperssonfab67072017-04-04 05:51:49 -07001509 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001510 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001511 stats = stats_proxy_->GetStats();
1512 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001513 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001514 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001515
1516 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001517 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001518 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001519 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001520 stats = stats_proxy_->GetStats();
1521 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001522 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001523 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1524
1525 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001526 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07001527 &new_video_source,
1528 VideoSendStream::DegradationPreference::kMaintainResolution);
1529 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001530 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001531 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001532 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001533 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001534 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001535 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001536 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1537
1538 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001539 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001540 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001541 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001542 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001543 stats = stats_proxy_->GetStats();
1544 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001545 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001546 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001547 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001548
mflodmancc3d4422017-08-03 08:27:51 -07001549 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001550}
1551
mflodmancc3d4422017-08-03 08:27:51 -07001552TEST_F(VideoStreamEncoderTest, StatsTracksPreferredBitrate) {
1553 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
Erik Språng08127a92016-11-16 16:41:30 +01001554
asaperssonfab67072017-04-04 05:51:49 -07001555 const int kWidth = 1280;
1556 const int kHeight = 720;
1557 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001558 WaitForEncodedFrame(1);
Erik Språng08127a92016-11-16 16:41:30 +01001559
1560 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1561 EXPECT_EQ(video_encoder_config_.max_bitrate_bps,
1562 stats.preferred_media_bitrate_bps);
1563
mflodmancc3d4422017-08-03 08:27:51 -07001564 video_stream_encoder_->Stop();
Erik Språng08127a92016-11-16 16:41:30 +01001565}
1566
mflodmancc3d4422017-08-03 08:27:51 -07001567TEST_F(VideoStreamEncoderTest,
1568 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001569 const int kWidth = 1280;
1570 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001571 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001572
asaperssonfab67072017-04-04 05:51:49 -07001573 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001574 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001575
asaperssonfab67072017-04-04 05:51:49 -07001576 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001577 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001578
asaperssonfab67072017-04-04 05:51:49 -07001579 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001580 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001581
asaperssonfab67072017-04-04 05:51:49 -07001582 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001583 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001584
kthelgason876222f2016-11-29 01:44:11 -08001585 // Expect a scale down.
1586 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001587 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001588
asapersson02465b82017-04-10 01:12:52 -07001589 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001590 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001591 video_stream_encoder_->SetSource(
kthelgason876222f2016-11-29 01:44:11 -08001592 &new_video_source,
1593 VideoSendStream::DegradationPreference::kMaintainResolution);
1594
asaperssonfab67072017-04-04 05:51:49 -07001595 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001596 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001597 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001598 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001599
asaperssonfab67072017-04-04 05:51:49 -07001600 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001601 EXPECT_EQ(std::numeric_limits<int>::max(),
1602 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001603
asaperssonfab67072017-04-04 05:51:49 -07001604 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001605 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001606 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001607 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001608
asapersson02465b82017-04-10 01:12:52 -07001609 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001610 EXPECT_EQ(std::numeric_limits<int>::max(),
1611 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001612
mflodmancc3d4422017-08-03 08:27:51 -07001613 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001614}
1615
mflodmancc3d4422017-08-03 08:27:51 -07001616TEST_F(VideoStreamEncoderTest,
1617 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001618 const int kWidth = 1280;
1619 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001620 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001621
1622 // Enable kMaintainFramerate preference, no initial limitation.
1623 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001624 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001625 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1626
1627 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001628 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001629 VerifyNoLimitation(source.sink_wants());
1630 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1631 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1632
1633 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001634 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001635 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001636 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1637 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1638 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1639
1640 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001641 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001642 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1643 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1644 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1645
mflodmancc3d4422017-08-03 08:27:51 -07001646 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001647}
1648
mflodmancc3d4422017-08-03 08:27:51 -07001649TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001650 const int kWidth = 1280;
1651 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001652 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001653
1654 // Enable kBalanced preference, no initial limitation.
1655 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001656 video_stream_encoder_->SetSource(
1657 &source,
1658 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001659 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1660 sink_.WaitForEncodedFrame(1);
1661 VerifyNoLimitation(source.sink_wants());
1662
1663 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001664 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001665 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1666 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1667 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1668 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1669
1670 // Trigger adapt down for same input resolution, expect no change.
1671 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1672 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001673 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001674 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1675 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1676 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1677
1678 // Trigger adapt down for larger input resolution, expect no change.
1679 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1680 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001681 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001682 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1683 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1684 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1685
mflodmancc3d4422017-08-03 08:27:51 -07001686 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001687}
1688
mflodmancc3d4422017-08-03 08:27:51 -07001689TEST_F(VideoStreamEncoderTest,
1690 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001691 const int kWidth = 1280;
1692 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001693 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001694
1695 // Enable kMaintainFramerate preference, no initial limitation.
1696 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001697 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001698 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1699
1700 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001701 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001702 VerifyNoLimitation(source.sink_wants());
1703 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1704 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1705
1706 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001707 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001708 VerifyNoLimitation(source.sink_wants());
1709 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1710 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1711
mflodmancc3d4422017-08-03 08:27:51 -07001712 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001713}
1714
mflodmancc3d4422017-08-03 08:27:51 -07001715TEST_F(VideoStreamEncoderTest,
1716 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001717 const int kWidth = 1280;
1718 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001719 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001720
1721 // Enable kMaintainResolution preference, no initial limitation.
1722 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001723 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001724 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
1725
1726 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001727 WaitForEncodedFrame(kWidth, kHeight);
asapersson02465b82017-04-10 01:12:52 -07001728 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001729 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001730 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1731
1732 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001733 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson02465b82017-04-10 01:12:52 -07001734 VerifyNoLimitation(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001735 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001736 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1737
mflodmancc3d4422017-08-03 08:27:51 -07001738 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001739}
1740
mflodmancc3d4422017-08-03 08:27:51 -07001741TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001742 const int kWidth = 1280;
1743 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001744 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001745
1746 // Enable kBalanced preference, no initial limitation.
1747 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001748 video_stream_encoder_->SetSource(
1749 &source,
1750 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001751
1752 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1753 sink_.WaitForEncodedFrame(kWidth, kHeight);
1754 VerifyNoLimitation(source.sink_wants());
1755 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1756 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1757 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1758
1759 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001760 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001761 VerifyNoLimitation(source.sink_wants());
1762 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1763 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1764 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1765
mflodmancc3d4422017-08-03 08:27:51 -07001766 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001767}
1768
mflodmancc3d4422017-08-03 08:27:51 -07001769TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07001770 const int kWidth = 1280;
1771 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001772 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001773
1774 // Enable kDegradationDisabled preference, no initial limitation.
1775 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001776 video_stream_encoder_->SetSource(
asapersson09f05612017-05-15 23:40:18 -07001777 &source, VideoSendStream::DegradationPreference::kDegradationDisabled);
1778
1779 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1780 sink_.WaitForEncodedFrame(kWidth, kHeight);
1781 VerifyNoLimitation(source.sink_wants());
1782 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1783 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1784 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1785
1786 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001787 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001788 VerifyNoLimitation(source.sink_wants());
1789 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1790 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1791 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1792
mflodmancc3d4422017-08-03 08:27:51 -07001793 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001794}
1795
mflodmancc3d4422017-08-03 08:27:51 -07001796TEST_F(VideoStreamEncoderTest,
1797 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001798 const int kWidth = 1280;
1799 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001800 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001801
1802 // Enable kMaintainFramerate preference, no initial limitation.
1803 AdaptingFrameForwarder source;
1804 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001805 video_stream_encoder_->SetSource(
asapersson02465b82017-04-10 01:12:52 -07001806 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1807
1808 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001809 WaitForEncodedFrame(1);
asapersson02465b82017-04-10 01:12:52 -07001810 VerifyNoLimitation(source.sink_wants());
1811 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1812 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1813
1814 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001815 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07001816 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001817 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001818 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001819 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1820 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1821
1822 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001823 video_stream_encoder_->TriggerQualityHigh();
asapersson02465b82017-04-10 01:12:52 -07001824 VerifyNoLimitation(source.sink_wants());
1825 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1826 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1827 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1828
mflodmancc3d4422017-08-03 08:27:51 -07001829 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001830}
1831
mflodmancc3d4422017-08-03 08:27:51 -07001832TEST_F(VideoStreamEncoderTest,
1833 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07001834 const int kWidth = 1280;
1835 const int kHeight = 720;
1836 const int kInputFps = 30;
mflodmancc3d4422017-08-03 08:27:51 -07001837 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07001838
1839 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1840 stats.input_frame_rate = kInputFps;
1841 stats_proxy_->SetMockStats(stats);
1842
1843 // Expect no scaling to begin with (preference: kMaintainFramerate).
1844 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1845 sink_.WaitForEncodedFrame(1);
1846 VerifyNoLimitation(video_source_.sink_wants());
1847
1848 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001849 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001850 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1851 sink_.WaitForEncodedFrame(2);
1852 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
1853
1854 // Enable kMaintainResolution preference.
1855 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001856 video_stream_encoder_->SetSource(
asapersson09f05612017-05-15 23:40:18 -07001857 &new_video_source,
1858 VideoSendStream::DegradationPreference::kMaintainResolution);
1859 VerifyNoLimitation(new_video_source.sink_wants());
1860
1861 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07001862 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07001863 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1864 sink_.WaitForEncodedFrame(3);
1865 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
1866
1867 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001868 video_stream_encoder_->TriggerQualityHigh();
asapersson09f05612017-05-15 23:40:18 -07001869 VerifyNoLimitation(new_video_source.sink_wants());
1870
mflodmancc3d4422017-08-03 08:27:51 -07001871 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07001872}
1873
mflodmancc3d4422017-08-03 08:27:51 -07001874TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07001875 const int kWidth = 1280;
1876 const int kHeight = 720;
1877 const size_t kNumFrames = 10;
1878
mflodmancc3d4422017-08-03 08:27:51 -07001879 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001880
asaperssond0de2952017-04-21 01:47:31 -07001881 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07001882 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07001883 video_source_.set_adaptation_enabled(true);
1884
1885 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1886 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1887
1888 int downscales = 0;
1889 for (size_t i = 1; i <= kNumFrames; i++) {
1890 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001891 WaitForEncodedFrame(i);
asaperssond0de2952017-04-21 01:47:31 -07001892
asaperssonfab67072017-04-04 05:51:49 -07001893 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07001894 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07001895 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07001896 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07001897
1898 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
1899 ++downscales;
1900
1901 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1902 EXPECT_EQ(downscales,
1903 stats_proxy_->GetStats().number_of_quality_adapt_changes);
1904 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08001905 }
mflodmancc3d4422017-08-03 08:27:51 -07001906 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001907}
1908
mflodmancc3d4422017-08-03 08:27:51 -07001909TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07001910 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
1911 const int kWidth = 1280;
1912 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001913 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07001914
1915 // Enable kMaintainFramerate preference, no initial limitation.
1916 AdaptingFrameForwarder source;
1917 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001918 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07001919 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
1920
1921 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001922 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001923 VerifyNoLimitation(source.sink_wants());
1924 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1925 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1926
1927 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001928 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001929 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001930 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07001931 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001932 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1933 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1934
1935 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001936 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07001937 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001938 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001939 VerifyNoLimitation(source.sink_wants());
1940 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1941 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1942
1943 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001944 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07001945 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001946 WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07001947 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001948 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1949 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1950
1951 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001952 video_stream_encoder_->TriggerCpuNormalUsage();
asapersson09f05612017-05-15 23:40:18 -07001953 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
1954 sink_.WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07001955 VerifyNoLimitation(source.sink_wants());
1956 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1957 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1958
mflodmancc3d4422017-08-03 08:27:51 -07001959 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07001960}
1961
mflodmancc3d4422017-08-03 08:27:51 -07001962TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07001963 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
1964 const int kWidth = 1280;
1965 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07001966 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001967
1968 // Enable kBalanced preference, no initial limitation.
1969 AdaptingFrameForwarder source;
1970 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07001971 video_stream_encoder_->SetSource(
1972 &source,
1973 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07001974
1975 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1976 sink_.WaitForEncodedFrame(kWidth, kHeight);
1977 VerifyNoLimitation(source.sink_wants());
1978 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1979 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1980
1981 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001982 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001983 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1984 sink_.WaitForEncodedFrame(2);
1985 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1986 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1987 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1988
1989 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07001990 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07001991 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
1992 sink_.WaitForEncodedFrame(kWidth, kHeight);
1993 VerifyNoLimitation(source.sink_wants());
1994 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1995 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1996
1997 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001998 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001999 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
2000 sink_.WaitForEncodedFrame(4);
2001 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2002 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2003 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2004
2005 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002006 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002007 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
2008 sink_.WaitForEncodedFrame(kWidth, kHeight);
2009 VerifyNoLimitation(source.sink_wants());
2010 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2011 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2012
mflodmancc3d4422017-08-03 08:27:51 -07002013 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002014}
2015
mflodmancc3d4422017-08-03 08:27:51 -07002016TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002017 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
2018 const int kWidth = 1280;
2019 const int kHeight = 720;
mflodmancc3d4422017-08-03 08:27:51 -07002020 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002021
2022 // Enable kMaintainFramerate preference, no initial limitation.
2023 AdaptingFrameForwarder source;
2024 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002025 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07002026 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
2027
2028 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002029 WaitForEncodedFrame(kWidth, kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002030 VerifyNoLimitation(source.sink_wants());
2031 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2032 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2033 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2034 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2035
2036 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002037 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002038 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002039 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07002040 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002041 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2042 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2043 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2044 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2045
2046 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07002047 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002048 source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002049 WaitForEncodedFrame(3);
asapersson09f05612017-05-15 23:40:18 -07002050 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2051 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07002052 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2053 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2054 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2055 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2056
2057 // Trigger cpu adapt down, max cpu downgrades reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002058 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002059 source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002060 WaitForEncodedFrame(4);
asapersson09f05612017-05-15 23:40:18 -07002061 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002062 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2063 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2064 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2065 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2066
2067 // Trigger quality adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002068 video_stream_encoder_->TriggerQualityLow();
asaperssond0de2952017-04-21 01:47:31 -07002069 source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002070 WaitForEncodedFrame(5);
asapersson09f05612017-05-15 23:40:18 -07002071 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002072 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2073 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2074 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2075 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2076
2077 // Trigger cpu adapt up, expect upscaled resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07002078 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07002079 source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002080 WaitForEncodedFrame(6);
asapersson09f05612017-05-15 23:40:18 -07002081 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002082 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2083 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2084 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2085 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2086
2087 // Trigger cpu adapt up, expect upscaled resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002088 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07002089 source.IncomingCapturedFrame(CreateFrame(7, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002090 WaitForEncodedFrame(7);
asapersson09f05612017-05-15 23:40:18 -07002091 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002092 last_wants = source.sink_wants();
2093 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2094 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2095 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2096 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2097
2098 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002099 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssond0de2952017-04-21 01:47:31 -07002100 source.IncomingCapturedFrame(CreateFrame(8, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002101 WaitForEncodedFrame(8);
asapersson09f05612017-05-15 23:40:18 -07002102 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002103 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2104 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2105 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2106 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2107
2108 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002109 video_stream_encoder_->TriggerQualityHigh();
asaperssond0de2952017-04-21 01:47:31 -07002110 source.IncomingCapturedFrame(CreateFrame(9, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002111 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002112 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002113 VerifyNoLimitation(source.sink_wants());
2114 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2115 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2116 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2117 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002118
mflodmancc3d4422017-08-03 08:27:51 -07002119 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002120}
2121
mflodmancc3d4422017-08-03 08:27:51 -07002122TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002123 const int kWidth = 640;
2124 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002125
mflodmancc3d4422017-08-03 08:27:51 -07002126 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002127
perkj803d97f2016-11-01 11:45:46 -07002128 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002129 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002130 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002131 }
2132
mflodmancc3d4422017-08-03 08:27:51 -07002133 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002134 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002135 video_source_.IncomingCapturedFrame(CreateFrame(
2136 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002137 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002138 }
2139
mflodmancc3d4422017-08-03 08:27:51 -07002140 video_stream_encoder_->Stop();
2141 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002142 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002143
perkj803d97f2016-11-01 11:45:46 -07002144 EXPECT_EQ(1,
2145 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2146 EXPECT_EQ(
2147 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2148}
2149
mflodmancc3d4422017-08-03 08:27:51 -07002150TEST_F(VideoStreamEncoderTest,
2151 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
2152 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002153 const int kWidth = 640;
2154 const int kHeight = 360;
2155
mflodmancc3d4422017-08-03 08:27:51 -07002156 video_stream_encoder_->SetSource(
asaperssonf4e44af2017-04-19 02:01:06 -07002157 &video_source_,
2158 VideoSendStream::DegradationPreference::kDegradationDisabled);
2159
2160 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2161 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002162 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002163 }
2164
mflodmancc3d4422017-08-03 08:27:51 -07002165 video_stream_encoder_->Stop();
2166 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002167 stats_proxy_.reset();
2168
2169 EXPECT_EQ(0,
2170 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2171}
2172
mflodmancc3d4422017-08-03 08:27:51 -07002173TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002174 MockBitrateObserver bitrate_observer;
mflodmancc3d4422017-08-03 08:27:51 -07002175 video_stream_encoder_->SetBitrateObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002176
2177 const int kDefaultFps = 30;
2178 const BitrateAllocation expected_bitrate =
2179 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002180 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002181
2182 // First called on bitrate updated, then again on first frame.
2183 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2184 .Times(2);
mflodmancc3d4422017-08-03 08:27:51 -07002185 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002186
2187 const int64_t kStartTimeMs = 1;
2188 video_source_.IncomingCapturedFrame(
2189 CreateFrame(kStartTimeMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002190 WaitForEncodedFrame(kStartTimeMs);
sprang57c2fff2017-01-16 06:24:02 -08002191
2192 // Not called on second frame.
2193 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2194 .Times(0);
2195 video_source_.IncomingCapturedFrame(
2196 CreateFrame(kStartTimeMs + 1, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002197 WaitForEncodedFrame(kStartTimeMs + 1);
sprang57c2fff2017-01-16 06:24:02 -08002198
2199 // Called after a process interval.
2200 const int64_t kProcessIntervalMs =
2201 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang4847ae62017-06-27 07:06:52 -07002202 fake_clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec *
2203 (kProcessIntervalMs + (1000 / kDefaultFps)));
sprang57c2fff2017-01-16 06:24:02 -08002204 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2205 .Times(1);
2206 video_source_.IncomingCapturedFrame(CreateFrame(
2207 kStartTimeMs + kProcessIntervalMs, codec_width_, codec_height_));
sprang4847ae62017-06-27 07:06:52 -07002208 WaitForEncodedFrame(kStartTimeMs + kProcessIntervalMs);
sprang57c2fff2017-01-16 06:24:02 -08002209
mflodmancc3d4422017-08-03 08:27:51 -07002210 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002211}
2212
mflodmancc3d4422017-08-03 08:27:51 -07002213TEST_F(VideoStreamEncoderTest,
2214 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002215 const int kFrameWidth = 1280;
2216 const int kFrameHeight = 720;
2217 const int kFramerate = 24;
2218
mflodmancc3d4422017-08-03 08:27:51 -07002219 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002220 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002221 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002222 &source, VideoSendStream::DegradationPreference::kMaintainResolution);
2223
2224 // Trigger initial configuration.
2225 VideoEncoderConfig video_encoder_config;
2226 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2227 video_encoder_config.number_of_streams = 1;
2228 video_encoder_config.video_stream_factory =
2229 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2230 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002231 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
2232 kMaxPayloadLength, false);
2233 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002234
Niels Möllereee7ced2017-12-01 11:25:01 +01002235 EXPECT_GT(source.sink_wants().max_framerate_fps, kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002236
2237 // Trigger overuse, max framerate should be reduced.
2238 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2239 stats.input_frame_rate = kFramerate;
2240 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002241 video_stream_encoder_->TriggerCpuOveruse();
2242 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möllereee7ced2017-12-01 11:25:01 +01002243
2244 int adapted_framerate = source.sink_wants().max_framerate_fps;
sprangfda496a2017-06-15 04:21:07 -07002245 EXPECT_LT(adapted_framerate, kFramerate);
2246
2247 // Change degradation preference to not enable framerate scaling. Target
2248 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002249 video_stream_encoder_->SetSource(
sprangfda496a2017-06-15 04:21:07 -07002250 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07002251 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möllereee7ced2017-12-01 11:25:01 +01002252 EXPECT_GT(source.sink_wants().max_framerate_fps, kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002253
mflodmancc3d4422017-08-03 08:27:51 -07002254 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002255}
2256
mflodmancc3d4422017-08-03 08:27:51 -07002257TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002258 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002259 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002260 const int kWidth = 640;
2261 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002262
asaperssonfab67072017-04-04 05:51:49 -07002263 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002264
2265 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002266 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002267
2268 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002269 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002270
sprangc5d62e22017-04-02 23:53:04 -07002271 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002272
asaperssonfab67072017-04-04 05:51:49 -07002273 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002274 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002275 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002276
2277 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002278 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002279
sprangc5d62e22017-04-02 23:53:04 -07002280 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002281
mflodmancc3d4422017-08-03 08:27:51 -07002282 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002283}
2284
mflodmancc3d4422017-08-03 08:27:51 -07002285TEST_F(VideoStreamEncoderTest,
2286 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002287 const int kTooLowBitrateForFrameSizeBps = 10000;
mflodmancc3d4422017-08-03 08:27:51 -07002288 video_stream_encoder_->OnBitrateUpdated(kTooLowBitrateForFrameSizeBps, 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002289 const int kWidth = 640;
2290 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002291
2292 // We expect the n initial frames to get dropped.
2293 int i;
2294 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002295 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002296 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002297 }
2298 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002299 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002300 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002301
2302 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002303 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002304
mflodmancc3d4422017-08-03 08:27:51 -07002305 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002306}
2307
mflodmancc3d4422017-08-03 08:27:51 -07002308TEST_F(VideoStreamEncoderTest,
2309 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002310 const int kWidth = 640;
2311 const int kHeight = 360;
mflodmancc3d4422017-08-03 08:27:51 -07002312 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002313
2314 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002315 video_stream_encoder_->SetSource(
kthelgason2bc68642017-02-07 07:02:22 -08002316 &video_source_,
2317 VideoSendStream::DegradationPreference::kMaintainResolution);
2318
asaperssonfab67072017-04-04 05:51:49 -07002319 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002320 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002321 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002322
mflodmancc3d4422017-08-03 08:27:51 -07002323 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002324}
2325
mflodmancc3d4422017-08-03 08:27:51 -07002326TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002327 const int kWidth = 640;
2328 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002329 fake_encoder_.SetQualityScaling(false);
mflodmancc3d4422017-08-03 08:27:51 -07002330 video_stream_encoder_->OnBitrateUpdated(kLowTargetBitrateBps, 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002331
kthelgasonb83797b2017-02-14 11:57:25 -08002332 // Force quality scaler reconfiguration by resetting the source.
mflodmancc3d4422017-08-03 08:27:51 -07002333 video_stream_encoder_->SetSource(
2334 &video_source_,
2335 VideoSendStream::DegradationPreference::kBalanced);
kthelgasonad9010c2017-02-14 00:46:51 -08002336
asaperssonfab67072017-04-04 05:51:49 -07002337 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002338 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002339 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002340
mflodmancc3d4422017-08-03 08:27:51 -07002341 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002342 fake_encoder_.SetQualityScaling(true);
2343}
2344
mflodmancc3d4422017-08-03 08:27:51 -07002345TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002346 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2347 const int kTooSmallWidth = 10;
2348 const int kTooSmallHeight = 10;
mflodmancc3d4422017-08-03 08:27:51 -07002349 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002350
2351 // Enable kMaintainFramerate preference, no initial limitation.
2352 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002353 video_stream_encoder_->SetSource(
asaperssond0de2952017-04-21 01:47:31 -07002354 &source, VideoSendStream::DegradationPreference::kMaintainFramerate);
2355 VerifyNoLimitation(source.sink_wants());
2356 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2357
2358 // Trigger adapt down, too small frame, expect no change.
2359 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002360 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002361 video_stream_encoder_->TriggerCpuOveruse();
asaperssond0de2952017-04-21 01:47:31 -07002362 VerifyNoLimitation(source.sink_wants());
2363 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2364 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2365
mflodmancc3d4422017-08-03 08:27:51 -07002366 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002367}
2368
mflodmancc3d4422017-08-03 08:27:51 -07002369TEST_F(VideoStreamEncoderTest,
2370 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002371 const int kTooSmallWidth = 10;
2372 const int kTooSmallHeight = 10;
2373 const int kFpsLimit = 7;
mflodmancc3d4422017-08-03 08:27:51 -07002374 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002375
2376 // Enable kBalanced preference, no initial limitation.
2377 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002378 video_stream_encoder_->SetSource(
2379 &source,
2380 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002381 VerifyNoLimitation(source.sink_wants());
2382 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2383 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2384
2385 // Trigger adapt down, expect limited framerate.
2386 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002387 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002388 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002389 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2390 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2391 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2392 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2393
2394 // Trigger adapt down, too small frame, expect no change.
2395 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002396 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002397 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002398 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2399 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2400 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2401 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2402
mflodmancc3d4422017-08-03 08:27:51 -07002403 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002404}
2405
mflodmancc3d4422017-08-03 08:27:51 -07002406TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002407 fake_encoder_.ForceInitEncodeFailure(true);
mflodmancc3d4422017-08-03 08:27:51 -07002408 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
emircanbbcc3562017-08-18 00:28:40 -07002409 ResetEncoder("VP8", 2, 1, 1, true, false);
asapersson02465b82017-04-10 01:12:52 -07002410 const int kFrameWidth = 1280;
2411 const int kFrameHeight = 720;
2412 video_source_.IncomingCapturedFrame(
2413 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002414 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002415 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002416}
2417
sprangb1ca0732017-02-01 08:38:12 -08002418// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002419TEST_F(VideoStreamEncoderTest,
2420 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
2421 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002422
2423 const int kFrameWidth = 1280;
2424 const int kFrameHeight = 720;
2425 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002426 // requested by
2427 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002428 video_source_.set_adaptation_enabled(true);
2429
2430 video_source_.IncomingCapturedFrame(
2431 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002432 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002433
2434 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002435 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002436 video_source_.IncomingCapturedFrame(
2437 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002438 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002439
asaperssonfab67072017-04-04 05:51:49 -07002440 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002441 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002442 video_source_.IncomingCapturedFrame(
2443 CreateFrame(3, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002444 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002445
mflodmancc3d4422017-08-03 08:27:51 -07002446 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002447}
sprangfe627f32017-03-29 08:24:59 -07002448
mflodmancc3d4422017-08-03 08:27:51 -07002449TEST_F(VideoStreamEncoderTest,
2450 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002451 const int kFrameWidth = 1280;
2452 const int kFrameHeight = 720;
sprang4847ae62017-06-27 07:06:52 -07002453 int kFrameIntervalMs = rtc::kNumMillisecsPerSec / max_framerate_;
sprangc5d62e22017-04-02 23:53:04 -07002454
mflodmancc3d4422017-08-03 08:27:51 -07002455 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2456 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07002457 &video_source_,
2458 VideoSendStream::DegradationPreference::kMaintainResolution);
2459 video_source_.set_adaptation_enabled(true);
2460
sprang4847ae62017-06-27 07:06:52 -07002461 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002462
2463 video_source_.IncomingCapturedFrame(
2464 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002465 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002466
2467 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07002468 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002469
2470 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07002471 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002472 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002473 video_source_.IncomingCapturedFrame(
2474 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002475 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002476 }
2477
2478 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07002479 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002480 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002481 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002482 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002483 video_source_.IncomingCapturedFrame(
2484 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002485 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002486 ++num_frames_dropped;
2487 } else {
2488 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2489 }
2490 }
2491
sprang4847ae62017-06-27 07:06:52 -07002492 // Add some slack to account for frames dropped by the frame dropper.
2493 const int kErrorMargin = 1;
2494 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002495 kErrorMargin);
2496
2497 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07002498 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002499 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002500 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002501 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002502 video_source_.IncomingCapturedFrame(
2503 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002504 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002505 ++num_frames_dropped;
2506 } else {
2507 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2508 }
2509 }
sprang4847ae62017-06-27 07:06:52 -07002510 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07002511 kErrorMargin);
2512
2513 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07002514 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002515 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002516 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002517 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002518 video_source_.IncomingCapturedFrame(
2519 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002520 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002521 ++num_frames_dropped;
2522 } else {
2523 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2524 }
2525 }
sprang4847ae62017-06-27 07:06:52 -07002526 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07002527 kErrorMargin);
2528
2529 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07002530 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07002531 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07002532 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002533 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002534 video_source_.IncomingCapturedFrame(
2535 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002536 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07002537 ++num_frames_dropped;
2538 } else {
2539 sink_.CheckLastFrameSizeMathces(kFrameWidth, kFrameHeight);
2540 }
2541 }
2542 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
2543
mflodmancc3d4422017-08-03 08:27:51 -07002544 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002545}
2546
mflodmancc3d4422017-08-03 08:27:51 -07002547TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07002548 const int kFramerateFps = 5;
2549 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
2550 const int kMinFpsFrameInterval = rtc::kNumMillisecsPerSec / kMinFramerateFps;
2551 const int kFrameWidth = 1280;
2552 const int kFrameHeight = 720;
2553
sprang4847ae62017-06-27 07:06:52 -07002554 // Reconfigure encoder with two temporal layers and screensharing, which will
2555 // disable frame dropping and make testing easier.
emircanbbcc3562017-08-18 00:28:40 -07002556 ResetEncoder("VP8", 1, 2, 1, true, true);
sprang4847ae62017-06-27 07:06:52 -07002557
mflodmancc3d4422017-08-03 08:27:51 -07002558 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
2559 video_stream_encoder_->SetSource(
sprangc5d62e22017-04-02 23:53:04 -07002560 &video_source_,
2561 VideoSendStream::DegradationPreference::kMaintainResolution);
2562 video_source_.set_adaptation_enabled(true);
2563
sprang4847ae62017-06-27 07:06:52 -07002564 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07002565
2566 // Trigger overuse as much as we can.
mflodmancc3d4422017-08-03 08:27:51 -07002567 for (int i = 0; i < VideoStreamEncoder::kMaxCpuResolutionDowngrades; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07002568 // Insert frames to get a new fps estimate...
2569 for (int j = 0; j < kFramerateFps; ++j) {
2570 video_source_.IncomingCapturedFrame(
2571 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
2572 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07002573 }
2574 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07002575 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07002576 }
2577
2578 // Drain any frame in the pipeline.
sprang4847ae62017-06-27 07:06:52 -07002579 WaitForFrame(kDefaultTimeoutMs);
sprangc5d62e22017-04-02 23:53:04 -07002580
2581 // Insert frames at min fps, all should go through.
2582 for (int i = 0; i < 10; ++i) {
2583 timestamp_ms += kMinFpsFrameInterval;
sprangc5d62e22017-04-02 23:53:04 -07002584 video_source_.IncomingCapturedFrame(
2585 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002586 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07002587 }
asaperssonf7e294d2017-06-13 23:25:22 -07002588
mflodmancc3d4422017-08-03 08:27:51 -07002589 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07002590}
asaperssonf7e294d2017-06-13 23:25:22 -07002591
mflodmancc3d4422017-08-03 08:27:51 -07002592TEST_F(VideoStreamEncoderTest,
2593 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002594 const int kWidth = 1280;
2595 const int kHeight = 720;
2596 const int64_t kFrameIntervalMs = 150;
2597 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002598 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002599
2600 // Enable kBalanced preference, no initial limitation.
2601 AdaptingFrameForwarder source;
2602 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002603 video_stream_encoder_->SetSource(
2604 &source,
2605 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002606 timestamp_ms += kFrameIntervalMs;
2607 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002608 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002609 VerifyNoLimitation(source.sink_wants());
2610 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2611 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2612 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2613
2614 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002615 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002616 timestamp_ms += kFrameIntervalMs;
2617 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002618 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002619 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2620 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2621 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2622 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2623
2624 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002625 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002626 timestamp_ms += kFrameIntervalMs;
2627 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002628 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002629 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2630 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2631 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2632 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2633
2634 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002635 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002636 timestamp_ms += kFrameIntervalMs;
2637 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002638 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002639 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2640 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2641 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2642 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2643
2644 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002645 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002646 timestamp_ms += kFrameIntervalMs;
2647 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002648 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002649 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2650 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2651 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2652 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2653
2654 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002655 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002656 timestamp_ms += kFrameIntervalMs;
2657 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002658 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002659 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2660 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2661 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2662 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2663
2664 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002665 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002666 timestamp_ms += kFrameIntervalMs;
2667 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002668 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002669 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2670 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2671 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2672 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2673
2674 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07002675 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002676 timestamp_ms += kFrameIntervalMs;
2677 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002678 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002679 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2680 rtc::VideoSinkWants last_wants = source.sink_wants();
2681 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2682 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2683 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2684
2685 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002686 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002687 timestamp_ms += kFrameIntervalMs;
2688 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002689 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002690 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
2691 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2692 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2693 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2694
2695 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002696 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002697 timestamp_ms += kFrameIntervalMs;
2698 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002699 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002700 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2701 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2702 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2703 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2704
2705 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07002706 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002707 timestamp_ms += kFrameIntervalMs;
2708 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002709 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002710 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2711 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2712 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2713 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2714
2715 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002716 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002717 timestamp_ms += kFrameIntervalMs;
2718 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002719 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002720 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
2721 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2722 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2723 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2724
2725 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002726 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002727 timestamp_ms += kFrameIntervalMs;
2728 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002729 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002730 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2731 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2732 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2733 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2734
2735 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002736 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002737 timestamp_ms += kFrameIntervalMs;
2738 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002739 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002740 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2741 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2742 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2743 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2744
2745 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002746 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002747 timestamp_ms += kFrameIntervalMs;
2748 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002749 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002750 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2751 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2752 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2753 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2754
2755 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002756 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002757 timestamp_ms += kFrameIntervalMs;
2758 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002759 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002760 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2761 VerifyNoLimitation(source.sink_wants());
2762 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2763 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2764 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2765
2766 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002767 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002768 VerifyNoLimitation(source.sink_wants());
2769 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2770
mflodmancc3d4422017-08-03 08:27:51 -07002771 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002772}
2773
mflodmancc3d4422017-08-03 08:27:51 -07002774TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07002775 const int kWidth = 1280;
2776 const int kHeight = 720;
2777 const int64_t kFrameIntervalMs = 150;
2778 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002779 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002780
2781 // Enable kBalanced preference, no initial limitation.
2782 AdaptingFrameForwarder source;
2783 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002784 video_stream_encoder_->SetSource(
2785 &source,
2786 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002787 timestamp_ms += kFrameIntervalMs;
2788 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002789 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002790 VerifyNoLimitation(source.sink_wants());
2791 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2792 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2793 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2794 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2795 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2796 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2797
2798 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002799 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002800 timestamp_ms += kFrameIntervalMs;
2801 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002802 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002803 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2804 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2805 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2806 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2807 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2808 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2809 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2810
2811 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002812 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002813 timestamp_ms += kFrameIntervalMs;
2814 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002815 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002816 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
2817 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2818 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2819 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2820 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2821 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2822 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2823
2824 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002825 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002826 timestamp_ms += kFrameIntervalMs;
2827 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002828 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002829 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
2830 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2831 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2832 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2833 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2834 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2835 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2836
2837 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002838 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002839 timestamp_ms += kFrameIntervalMs;
2840 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002841 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002842 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
2843 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2844 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2845 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2846 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2847 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2848 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2849
2850 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002851 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002852 timestamp_ms += kFrameIntervalMs;
2853 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002854 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002855 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2856 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2857 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2858 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2859 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2860 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2861 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2862
2863 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002864 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002865 timestamp_ms += kFrameIntervalMs;
2866 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002867 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002868 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2869 VerifyNoLimitation(source.sink_wants());
2870 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2871 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2872 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2873 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2874 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2875 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2876
2877 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002878 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002879 VerifyNoLimitation(source.sink_wants());
2880 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2881 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2882
mflodmancc3d4422017-08-03 08:27:51 -07002883 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002884}
2885
mflodmancc3d4422017-08-03 08:27:51 -07002886TEST_F(VideoStreamEncoderTest,
2887 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07002888 const int kWidth = 640;
2889 const int kHeight = 360;
2890 const int kFpsLimit = 15;
2891 const int64_t kFrameIntervalMs = 150;
2892 int64_t timestamp_ms = kFrameIntervalMs;
mflodmancc3d4422017-08-03 08:27:51 -07002893 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002894
2895 // Enable kBalanced preference, no initial limitation.
2896 AdaptingFrameForwarder source;
2897 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002898 video_stream_encoder_->SetSource(
2899 &source,
2900 VideoSendStream::DegradationPreference::kBalanced);
asaperssonf7e294d2017-06-13 23:25:22 -07002901 timestamp_ms += kFrameIntervalMs;
2902 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002903 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07002904 VerifyNoLimitation(source.sink_wants());
2905 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2906 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2907 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2908 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2909 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2910 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2911
2912 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002913 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07002914 timestamp_ms += kFrameIntervalMs;
2915 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002916 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002917 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2918 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2919 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2920 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2921 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2922 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2923 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2924
2925 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002926 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002927 timestamp_ms += kFrameIntervalMs;
2928 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002929 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002930 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
2931 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2932 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2933 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2934 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
2935 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2936 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2937
2938 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07002939 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07002940 timestamp_ms += kFrameIntervalMs;
2941 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002942 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002943 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
2944 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2945 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2946 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2947 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2948 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2949 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2950
2951 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07002952 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002953 timestamp_ms += kFrameIntervalMs;
2954 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002955 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002956 VerifyNoLimitation(source.sink_wants());
2957 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2958 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2959 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2960 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2961 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2962 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2963
2964 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002965 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07002966 VerifyNoLimitation(source.sink_wants());
2967 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2968 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2969
mflodmancc3d4422017-08-03 08:27:51 -07002970 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002971}
2972
mflodmancc3d4422017-08-03 08:27:51 -07002973TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07002974 // Simulates simulcast behavior and makes highest stream resolutions divisible
2975 // by 4.
2976 class CroppingVideoStreamFactory
2977 : public VideoEncoderConfig::VideoStreamFactoryInterface {
2978 public:
2979 explicit CroppingVideoStreamFactory(size_t num_temporal_layers,
2980 int framerate)
2981 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
2982 EXPECT_GT(num_temporal_layers, 0u);
2983 EXPECT_GT(framerate, 0);
2984 }
2985
2986 private:
2987 std::vector<VideoStream> CreateEncoderStreams(
2988 int width,
2989 int height,
2990 const VideoEncoderConfig& encoder_config) override {
2991 std::vector<VideoStream> streams =
2992 test::CreateVideoStreams(width - width % 4, height - height % 4,
2993 encoder_config);
2994 for (VideoStream& stream : streams) {
2995 stream.temporal_layer_thresholds_bps.resize(num_temporal_layers_ - 1);
2996 stream.max_framerate = framerate_;
2997 }
2998 return streams;
2999 }
3000
3001 const size_t num_temporal_layers_;
3002 const int framerate_;
3003 };
3004
3005 const int kFrameWidth = 1920;
3006 const int kFrameHeight = 1080;
3007 // 3/4 of 1920.
3008 const int kAdaptedFrameWidth = 1440;
3009 // 3/4 of 1080 rounded down to multiple of 4.
3010 const int kAdaptedFrameHeight = 808;
3011 const int kFramerate = 24;
3012
mflodmancc3d4422017-08-03 08:27:51 -07003013 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003014 // Trigger reconfigure encoder (without resetting the entire instance).
3015 VideoEncoderConfig video_encoder_config;
3016 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3017 video_encoder_config.number_of_streams = 1;
3018 video_encoder_config.video_stream_factory =
3019 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003020 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
3021 kMaxPayloadLength, false);
3022 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003023
3024 video_source_.set_adaptation_enabled(true);
3025
3026 video_source_.IncomingCapturedFrame(
3027 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003028 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003029
3030 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003031 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003032 video_source_.IncomingCapturedFrame(
3033 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003034 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003035
mflodmancc3d4422017-08-03 08:27:51 -07003036 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003037}
3038
mflodmancc3d4422017-08-03 08:27:51 -07003039TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003040 const int kFrameWidth = 1280;
3041 const int kFrameHeight = 720;
3042 const int kLowFps = 2;
3043 const int kHighFps = 30;
3044
mflodmancc3d4422017-08-03 08:27:51 -07003045 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003046
3047 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3048 max_framerate_ = kLowFps;
3049
3050 // Insert 2 seconds of 2fps video.
3051 for (int i = 0; i < kLowFps * 2; ++i) {
3052 video_source_.IncomingCapturedFrame(
3053 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3054 WaitForEncodedFrame(timestamp_ms);
3055 timestamp_ms += 1000 / kLowFps;
3056 }
3057
3058 // Make sure encoder is updated with new target.
mflodmancc3d4422017-08-03 08:27:51 -07003059 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003060 video_source_.IncomingCapturedFrame(
3061 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3062 WaitForEncodedFrame(timestamp_ms);
3063 timestamp_ms += 1000 / kLowFps;
3064
3065 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3066
3067 // Insert 30fps frames for just a little more than the forced update period.
3068 const int kVcmTimerIntervalFrames =
3069 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3070 const int kFrameIntervalMs = 1000 / kHighFps;
3071 max_framerate_ = kHighFps;
3072 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3073 video_source_.IncomingCapturedFrame(
3074 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3075 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3076 // be dropped if the encoder hans't been updated with the new higher target
3077 // framerate yet, causing it to overshoot the target bitrate and then
3078 // suffering the wrath of the media optimizer.
3079 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3080 timestamp_ms += kFrameIntervalMs;
3081 }
3082
3083 // Don expect correct measurement just yet, but it should be higher than
3084 // before.
3085 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3086
mflodmancc3d4422017-08-03 08:27:51 -07003087 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003088}
3089
mflodmancc3d4422017-08-03 08:27:51 -07003090TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003091 const int kFrameWidth = 1280;
3092 const int kFrameHeight = 720;
3093 const int kTargetBitrateBps = 1000000;
3094
3095 MockBitrateObserver bitrate_observer;
mflodmancc3d4422017-08-03 08:27:51 -07003096 video_stream_encoder_->SetBitrateObserver(&bitrate_observer);
sprang4847ae62017-06-27 07:06:52 -07003097
3098 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3099 // Initial bitrate update.
mflodmancc3d4422017-08-03 08:27:51 -07003100 video_stream_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
3101 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003102
3103 // Insert a first video frame, causes another bitrate update.
3104 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3105 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3106 video_source_.IncomingCapturedFrame(
3107 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3108 WaitForEncodedFrame(timestamp_ms);
3109
3110 // Next, simulate video suspension due to pacer queue overrun.
mflodmancc3d4422017-08-03 08:27:51 -07003111 video_stream_encoder_->OnBitrateUpdated(0, 0, 1);
sprang4847ae62017-06-27 07:06:52 -07003112
3113 // Skip ahead until a new periodic parameter update should have occured.
3114 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
3115 fake_clock_.AdvanceTimeMicros(
3116 vcm::VCMProcessTimer::kDefaultProcessIntervalMs *
3117 rtc::kNumMicrosecsPerMillisec);
3118
3119 // Bitrate observer should not be called.
3120 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3121 video_source_.IncomingCapturedFrame(
3122 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3123 ExpectDroppedFrame();
3124
mflodmancc3d4422017-08-03 08:27:51 -07003125 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003126}
ilnik6b826ef2017-06-16 06:53:48 -07003127
perkj26091b12016-09-01 01:17:40 -07003128} // namespace webrtc