blob: 7214a64b9873c59ad5084bb7ddaa9287a926e604 [file] [log] [blame]
perkj26091b12016-09-01 01:17:40 -07001/*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Erik Språng4529fbc2018-10-12 10:30:31 +020011#include "video/video_stream_encoder.h"
12
sprangfe627f32017-03-29 08:24:59 -070013#include <algorithm>
perkj803d97f2016-11-01 11:45:46 -070014#include <limits>
Danil Chapovalovd3ba2362019-04-10 17:01:23 +020015#include <memory>
Per512ecb32016-09-23 15:52:06 +020016#include <utility>
17
Mirta Dvornicic28f0eb22019-05-28 16:30:16 +020018#include "absl/memory/memory.h"
Danil Chapovalovd3ba2362019-04-10 17:01:23 +020019#include "api/task_queue/default_task_queue_factory.h"
Jiawei Ouc2ebe212018-11-08 10:02:56 -080020#include "api/video/builtin_video_bitrate_allocator_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "api/video/i420_buffer.h"
Erik Språngf93eda12019-01-16 17:10:57 +010022#include "api/video/video_bitrate_allocation.h"
Elad Alon370f93a2019-06-11 14:57:57 +020023#include "api/video_codecs/video_encoder.h"
Erik Språng4529fbc2018-10-12 10:30:31 +020024#include "api/video_codecs/vp8_temporal_layers.h"
Elad Aloncde8ab22019-03-20 11:56:20 +010025#include "api/video_codecs/vp8_temporal_layers_factory.h"
Mirta Dvornicic28f0eb22019-05-28 16:30:16 +020026#include "common_video/h264/h264_common.h"
Noah Richards51db4212019-06-12 06:59:12 -070027#include "common_video/include/video_frame_buffer.h"
Steve Anton10542f22019-01-11 09:11:00 -080028#include "media/base/video_adapter.h"
Sergey Silkin86684962018-03-28 19:32:37 +020029#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020030#include "modules/video_coding/utility/default_video_bitrate_allocator.h"
Åsa Perssonc29cb2c2019-03-25 12:06:59 +010031#include "modules/video_coding/utility/simulcast_rate_allocator.h"
Steve Anton10542f22019-01-11 09:11:00 -080032#include "rtc_base/fake_clock.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020033#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080034#include "rtc_base/ref_counted_object.h"
Erik Språng7ca375c2019-02-06 16:20:17 +010035#include "system_wrappers/include/field_trial.h"
Mirko Bonadei17f48782018-09-28 08:51:10 +020036#include "system_wrappers/include/metrics.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020037#include "system_wrappers/include/sleep.h"
38#include "test/encoder_settings.h"
39#include "test/fake_encoder.h"
Kári Tristan Helgason639602a2018-08-02 10:51:40 +020040#include "test/field_trial.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020041#include "test/frame_generator.h"
42#include "test/gmock.h"
43#include "test/gtest.h"
Niels Möllercbcbc222018-09-28 09:07:24 +020044#include "test/video_encoder_proxy_factory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020045#include "video/send_statistics_proxy.h"
perkj26091b12016-09-01 01:17:40 -070046
47namespace webrtc {
48
sprangb1ca0732017-02-01 08:38:12 -080049using ScaleReason = AdaptationObserverInterface::AdaptReason;
sprang57c2fff2017-01-16 06:24:02 -080050using ::testing::_;
kthelgason876222f2016-11-29 01:44:11 -080051
perkj803d97f2016-11-01 11:45:46 -070052namespace {
Åsa Persson8c1bf952018-09-13 10:42:19 +020053const int kMinPixelsPerFrame = 320 * 180;
54const int kMinFramerateFps = 2;
55const int kMinBalancedFramerateFps = 7;
56const int64_t kFrameTimeoutMs = 100;
asapersson5f7226f2016-11-25 04:37:00 -080057const size_t kMaxPayloadLength = 1440;
Erik Språngd7329ca2019-02-21 21:19:53 +010058const uint32_t kTargetBitrateBps = 1000000;
59const uint32_t kSimulcastTargetBitrateBps = 3150000;
60const uint32_t kLowTargetBitrateBps = kTargetBitrateBps / 10;
kthelgason2bc68642017-02-07 07:02:22 -080061const int kMaxInitialFramedrop = 4;
sprangfda496a2017-06-15 04:21:07 -070062const int kDefaultFramerate = 30;
Åsa Persson8c1bf952018-09-13 10:42:19 +020063const int64_t kFrameIntervalMs = rtc::kNumMillisecsPerSec / kDefaultFramerate;
asapersson5f7226f2016-11-25 04:37:00 -080064
Mirta Dvornicic28f0eb22019-05-28 16:30:16 +020065uint8_t optimal_sps[] = {0, 0, 0, 1, H264::NaluType::kSps,
66 0x00, 0x00, 0x03, 0x03, 0xF4,
67 0x05, 0x03, 0xC7, 0xE0, 0x1B,
68 0x41, 0x10, 0x8D, 0x00};
69
perkj803d97f2016-11-01 11:45:46 -070070class TestBuffer : public webrtc::I420Buffer {
71 public:
72 TestBuffer(rtc::Event* event, int width, int height)
73 : I420Buffer(width, height), event_(event) {}
74
75 private:
76 friend class rtc::RefCountedObject<TestBuffer>;
77 ~TestBuffer() override {
78 if (event_)
79 event_->Set();
80 }
81 rtc::Event* const event_;
82};
83
Noah Richards51db4212019-06-12 06:59:12 -070084// A fake native buffer that can't be converted to I420.
85class FakeNativeBuffer : public webrtc::VideoFrameBuffer {
86 public:
87 FakeNativeBuffer(rtc::Event* event, int width, int height)
88 : event_(event), width_(width), height_(height) {}
89 webrtc::VideoFrameBuffer::Type type() const override { return Type::kNative; }
90 int width() const override { return width_; }
91 int height() const override { return height_; }
92 rtc::scoped_refptr<webrtc::I420BufferInterface> ToI420() override {
93 return nullptr;
94 }
95
96 private:
97 friend class rtc::RefCountedObject<FakeNativeBuffer>;
98 ~FakeNativeBuffer() override {
99 if (event_)
100 event_->Set();
101 }
102 rtc::Event* const event_;
103 const int width_;
104 const int height_;
105};
106
Niels Möller7dc26b72017-12-06 10:27:48 +0100107class CpuOveruseDetectorProxy : public OveruseFrameDetector {
108 public:
Niels Möllerd1f7eb62018-03-28 16:40:58 +0200109 explicit CpuOveruseDetectorProxy(CpuOveruseMetricsObserver* metrics_observer)
110 : OveruseFrameDetector(metrics_observer),
Niels Möller7dc26b72017-12-06 10:27:48 +0100111 last_target_framerate_fps_(-1) {}
112 virtual ~CpuOveruseDetectorProxy() {}
113
114 void OnTargetFramerateUpdated(int framerate_fps) override {
115 rtc::CritScope cs(&lock_);
116 last_target_framerate_fps_ = framerate_fps;
117 OveruseFrameDetector::OnTargetFramerateUpdated(framerate_fps);
118 }
119
120 int GetLastTargetFramerate() {
121 rtc::CritScope cs(&lock_);
122 return last_target_framerate_fps_;
123 }
124
Niels Möller4db138e2018-04-19 09:04:13 +0200125 CpuOveruseOptions GetOptions() { return options_; }
126
Niels Möller7dc26b72017-12-06 10:27:48 +0100127 private:
128 rtc::CriticalSection lock_;
129 int last_target_framerate_fps_ RTC_GUARDED_BY(lock_);
130};
131
mflodmancc3d4422017-08-03 08:27:51 -0700132class VideoStreamEncoderUnderTest : public VideoStreamEncoder {
perkj803d97f2016-11-01 11:45:46 -0700133 public:
Niels Möller213618e2018-07-24 09:29:58 +0200134 VideoStreamEncoderUnderTest(SendStatisticsProxy* stats_proxy,
Danil Chapovalovd3ba2362019-04-10 17:01:23 +0200135 const VideoStreamEncoderSettings& settings,
136 TaskQueueFactory* task_queue_factory)
Sebastian Jansson572c60f2019-03-04 18:30:41 +0100137 : VideoStreamEncoder(Clock::GetRealTimeClock(),
138 1 /* number_of_cores */,
Yves Gerey665174f2018-06-19 15:03:05 +0200139 stats_proxy,
140 settings,
Yves Gerey665174f2018-06-19 15:03:05 +0200141 std::unique_ptr<OveruseFrameDetector>(
142 overuse_detector_proxy_ =
Sebastian Jansson74682c12019-03-01 11:50:20 +0100143 new CpuOveruseDetectorProxy(stats_proxy)),
Danil Chapovalovd3ba2362019-04-10 17:01:23 +0200144 task_queue_factory) {}
perkj803d97f2016-11-01 11:45:46 -0700145
sprangb1ca0732017-02-01 08:38:12 -0800146 void PostTaskAndWait(bool down, AdaptReason reason) {
Niels Möllerc572ff32018-11-07 08:43:50 +0100147 rtc::Event event;
kthelgason876222f2016-11-29 01:44:11 -0800148 encoder_queue()->PostTask([this, &event, reason, down] {
sprangb1ca0732017-02-01 08:38:12 -0800149 down ? AdaptDown(reason) : AdaptUp(reason);
perkj803d97f2016-11-01 11:45:46 -0700150 event.Set();
151 });
perkj070ba852017-02-16 15:46:27 -0800152 ASSERT_TRUE(event.Wait(5000));
perkj803d97f2016-11-01 11:45:46 -0700153 }
154
kthelgason2fc52542017-03-03 00:24:41 -0800155 // This is used as a synchronisation mechanism, to make sure that the
156 // encoder queue is not blocked before we start sending it frames.
157 void WaitUntilTaskQueueIsIdle() {
Niels Möllerc572ff32018-11-07 08:43:50 +0100158 rtc::Event event;
Yves Gerey665174f2018-06-19 15:03:05 +0200159 encoder_queue()->PostTask([&event] { event.Set(); });
kthelgason2fc52542017-03-03 00:24:41 -0800160 ASSERT_TRUE(event.Wait(5000));
161 }
162
sprangb1ca0732017-02-01 08:38:12 -0800163 void TriggerCpuOveruse() { PostTaskAndWait(true, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800164
sprangb1ca0732017-02-01 08:38:12 -0800165 void TriggerCpuNormalUsage() { PostTaskAndWait(false, AdaptReason::kCpu); }
kthelgason876222f2016-11-29 01:44:11 -0800166
sprangb1ca0732017-02-01 08:38:12 -0800167 void TriggerQualityLow() { PostTaskAndWait(true, AdaptReason::kQuality); }
kthelgason876222f2016-11-29 01:44:11 -0800168
sprangb1ca0732017-02-01 08:38:12 -0800169 void TriggerQualityHigh() { PostTaskAndWait(false, AdaptReason::kQuality); }
sprangfda496a2017-06-15 04:21:07 -0700170
Niels Möller7dc26b72017-12-06 10:27:48 +0100171 CpuOveruseDetectorProxy* overuse_detector_proxy_;
perkj803d97f2016-11-01 11:45:46 -0700172};
173
asapersson5f7226f2016-11-25 04:37:00 -0800174class VideoStreamFactory
175 : public VideoEncoderConfig::VideoStreamFactoryInterface {
176 public:
sprangfda496a2017-06-15 04:21:07 -0700177 explicit VideoStreamFactory(size_t num_temporal_layers, int framerate)
178 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
asapersson5f7226f2016-11-25 04:37:00 -0800179 EXPECT_GT(num_temporal_layers, 0u);
sprangfda496a2017-06-15 04:21:07 -0700180 EXPECT_GT(framerate, 0);
asapersson5f7226f2016-11-25 04:37:00 -0800181 }
182
183 private:
184 std::vector<VideoStream> CreateEncoderStreams(
185 int width,
186 int height,
187 const VideoEncoderConfig& encoder_config) override {
188 std::vector<VideoStream> streams =
189 test::CreateVideoStreams(width, height, encoder_config);
190 for (VideoStream& stream : streams) {
Sergey Silkina796a7e2018-03-01 15:11:29 +0100191 stream.num_temporal_layers = num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700192 stream.max_framerate = framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800193 }
194 return streams;
195 }
sprangfda496a2017-06-15 04:21:07 -0700196
asapersson5f7226f2016-11-25 04:37:00 -0800197 const size_t num_temporal_layers_;
sprangfda496a2017-06-15 04:21:07 -0700198 const int framerate_;
asapersson5f7226f2016-11-25 04:37:00 -0800199};
200
Noah Richards51db4212019-06-12 06:59:12 -0700201// Simulates simulcast behavior and makes highest stream resolutions divisible
202// by 4.
203class CroppingVideoStreamFactory
204 : public VideoEncoderConfig::VideoStreamFactoryInterface {
205 public:
206 explicit CroppingVideoStreamFactory(size_t num_temporal_layers, int framerate)
207 : num_temporal_layers_(num_temporal_layers), framerate_(framerate) {
208 EXPECT_GT(num_temporal_layers, 0u);
209 EXPECT_GT(framerate, 0);
210 }
211
212 private:
213 std::vector<VideoStream> CreateEncoderStreams(
214 int width,
215 int height,
216 const VideoEncoderConfig& encoder_config) override {
217 std::vector<VideoStream> streams = test::CreateVideoStreams(
218 width - width % 4, height - height % 4, encoder_config);
219 for (VideoStream& stream : streams) {
220 stream.num_temporal_layers = num_temporal_layers_;
221 stream.max_framerate = framerate_;
222 }
223 return streams;
224 }
225
226 const size_t num_temporal_layers_;
227 const int framerate_;
228};
229
sprangb1ca0732017-02-01 08:38:12 -0800230class AdaptingFrameForwarder : public test::FrameForwarder {
231 public:
232 AdaptingFrameForwarder() : adaptation_enabled_(false) {}
asaperssonfab67072017-04-04 05:51:49 -0700233 ~AdaptingFrameForwarder() override {}
sprangb1ca0732017-02-01 08:38:12 -0800234
235 void set_adaptation_enabled(bool enabled) {
236 rtc::CritScope cs(&crit_);
237 adaptation_enabled_ = enabled;
238 }
239
asaperssonfab67072017-04-04 05:51:49 -0700240 bool adaption_enabled() const {
sprangb1ca0732017-02-01 08:38:12 -0800241 rtc::CritScope cs(&crit_);
242 return adaptation_enabled_;
243 }
244
asapersson09f05612017-05-15 23:40:18 -0700245 rtc::VideoSinkWants last_wants() const {
246 rtc::CritScope cs(&crit_);
247 return last_wants_;
248 }
249
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200250 absl::optional<int> last_sent_width() const { return last_width_; }
251 absl::optional<int> last_sent_height() const { return last_height_; }
Jonathan Yubc771b72017-12-08 17:04:29 -0800252
sprangb1ca0732017-02-01 08:38:12 -0800253 void IncomingCapturedFrame(const VideoFrame& video_frame) override {
254 int cropped_width = 0;
255 int cropped_height = 0;
256 int out_width = 0;
257 int out_height = 0;
sprangc5d62e22017-04-02 23:53:04 -0700258 if (adaption_enabled()) {
259 if (adapter_.AdaptFrameResolution(
260 video_frame.width(), video_frame.height(),
261 video_frame.timestamp_us() * 1000, &cropped_width,
262 &cropped_height, &out_width, &out_height)) {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100263 VideoFrame adapted_frame =
264 VideoFrame::Builder()
265 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
266 nullptr, out_width, out_height))
267 .set_timestamp_rtp(99)
268 .set_timestamp_ms(99)
269 .set_rotation(kVideoRotation_0)
270 .build();
sprangc5d62e22017-04-02 23:53:04 -0700271 adapted_frame.set_ntp_time_ms(video_frame.ntp_time_ms());
272 test::FrameForwarder::IncomingCapturedFrame(adapted_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800273 last_width_.emplace(adapted_frame.width());
274 last_height_.emplace(adapted_frame.height());
275 } else {
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200276 last_width_ = absl::nullopt;
277 last_height_ = absl::nullopt;
sprangc5d62e22017-04-02 23:53:04 -0700278 }
sprangb1ca0732017-02-01 08:38:12 -0800279 } else {
280 test::FrameForwarder::IncomingCapturedFrame(video_frame);
Jonathan Yubc771b72017-12-08 17:04:29 -0800281 last_width_.emplace(video_frame.width());
282 last_height_.emplace(video_frame.height());
sprangb1ca0732017-02-01 08:38:12 -0800283 }
284 }
285
286 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
287 const rtc::VideoSinkWants& wants) override {
288 rtc::CritScope cs(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700289 last_wants_ = sink_wants();
sprangc5d62e22017-04-02 23:53:04 -0700290 adapter_.OnResolutionFramerateRequest(wants.target_pixel_count,
291 wants.max_pixel_count,
292 wants.max_framerate_fps);
sprangb1ca0732017-02-01 08:38:12 -0800293 test::FrameForwarder::AddOrUpdateSink(sink, wants);
294 }
sprangb1ca0732017-02-01 08:38:12 -0800295 cricket::VideoAdapter adapter_;
danilchapa37de392017-09-09 04:17:22 -0700296 bool adaptation_enabled_ RTC_GUARDED_BY(crit_);
297 rtc::VideoSinkWants last_wants_ RTC_GUARDED_BY(crit_);
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200298 absl::optional<int> last_width_;
299 absl::optional<int> last_height_;
sprangb1ca0732017-02-01 08:38:12 -0800300};
sprangc5d62e22017-04-02 23:53:04 -0700301
Niels Möller213618e2018-07-24 09:29:58 +0200302// TODO(nisse): Mock only VideoStreamEncoderObserver.
sprangc5d62e22017-04-02 23:53:04 -0700303class MockableSendStatisticsProxy : public SendStatisticsProxy {
304 public:
305 MockableSendStatisticsProxy(Clock* clock,
306 const VideoSendStream::Config& config,
307 VideoEncoderConfig::ContentType content_type)
308 : SendStatisticsProxy(clock, config, content_type) {}
309
310 VideoSendStream::Stats GetStats() override {
311 rtc::CritScope cs(&lock_);
312 if (mock_stats_)
313 return *mock_stats_;
314 return SendStatisticsProxy::GetStats();
315 }
316
Niels Möller213618e2018-07-24 09:29:58 +0200317 int GetInputFrameRate() const override {
318 rtc::CritScope cs(&lock_);
319 if (mock_stats_)
320 return mock_stats_->input_frame_rate;
321 return SendStatisticsProxy::GetInputFrameRate();
322 }
sprangc5d62e22017-04-02 23:53:04 -0700323 void SetMockStats(const VideoSendStream::Stats& stats) {
324 rtc::CritScope cs(&lock_);
325 mock_stats_.emplace(stats);
326 }
327
328 void ResetMockStats() {
329 rtc::CritScope cs(&lock_);
330 mock_stats_.reset();
331 }
332
333 private:
334 rtc::CriticalSection lock_;
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200335 absl::optional<VideoSendStream::Stats> mock_stats_ RTC_GUARDED_BY(lock_);
sprangc5d62e22017-04-02 23:53:04 -0700336};
337
sprang4847ae62017-06-27 07:06:52 -0700338class MockBitrateObserver : public VideoBitrateAllocationObserver {
339 public:
Erik Språng566124a2018-04-23 12:32:22 +0200340 MOCK_METHOD1(OnBitrateAllocationUpdated, void(const VideoBitrateAllocation&));
sprang4847ae62017-06-27 07:06:52 -0700341};
342
perkj803d97f2016-11-01 11:45:46 -0700343} // namespace
344
mflodmancc3d4422017-08-03 08:27:51 -0700345class VideoStreamEncoderTest : public ::testing::Test {
perkj26091b12016-09-01 01:17:40 -0700346 public:
347 static const int kDefaultTimeoutMs = 30 * 1000;
348
mflodmancc3d4422017-08-03 08:27:51 -0700349 VideoStreamEncoderTest()
perkj26091b12016-09-01 01:17:40 -0700350 : video_send_config_(VideoSendStream::Config(nullptr)),
perkjfa10b552016-10-02 23:45:26 -0700351 codec_width_(320),
352 codec_height_(240),
Åsa Persson8c1bf952018-09-13 10:42:19 +0200353 max_framerate_(kDefaultFramerate),
Danil Chapovalovd3ba2362019-04-10 17:01:23 +0200354 task_queue_factory_(CreateDefaultTaskQueueFactory()),
perkj26091b12016-09-01 01:17:40 -0700355 fake_encoder_(),
Niels Möller4db138e2018-04-19 09:04:13 +0200356 encoder_factory_(&fake_encoder_),
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800357 bitrate_allocator_factory_(CreateBuiltinVideoBitrateAllocatorFactory()),
sprangc5d62e22017-04-02 23:53:04 -0700358 stats_proxy_(new MockableSendStatisticsProxy(
perkj803d97f2016-11-01 11:45:46 -0700359 Clock::GetRealTimeClock(),
360 video_send_config_,
361 webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo)),
perkj26091b12016-09-01 01:17:40 -0700362 sink_(&fake_encoder_) {}
363
364 void SetUp() override {
perkj803d97f2016-11-01 11:45:46 -0700365 metrics::Reset();
perkj26091b12016-09-01 01:17:40 -0700366 video_send_config_ = VideoSendStream::Config(nullptr);
Niels Möller4db138e2018-04-19 09:04:13 +0200367 video_send_config_.encoder_settings.encoder_factory = &encoder_factory_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800368 video_send_config_.encoder_settings.bitrate_allocator_factory =
369 bitrate_allocator_factory_.get();
Niels Möller259a4972018-04-05 15:36:51 +0200370 video_send_config_.rtp.payload_name = "FAKE";
371 video_send_config_.rtp.payload_type = 125;
perkj26091b12016-09-01 01:17:40 -0700372
Per512ecb32016-09-23 15:52:06 +0200373 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200374 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
sprang4847ae62017-06-27 07:06:52 -0700375 video_encoder_config.video_stream_factory =
376 new rtc::RefCountedObject<VideoStreamFactory>(1, max_framerate_);
Erik Språng08127a92016-11-16 16:41:30 +0100377 video_encoder_config_ = video_encoder_config.Copy();
sprang4847ae62017-06-27 07:06:52 -0700378
379 // Framerate limit is specified by the VideoStreamFactory.
380 std::vector<VideoStream> streams =
381 video_encoder_config.video_stream_factory->CreateEncoderStreams(
382 codec_width_, codec_height_, video_encoder_config);
383 max_framerate_ = streams[0].max_framerate;
Sebastian Jansson40889f32019-04-17 12:11:20 +0200384 fake_clock_.SetTime(Timestamp::us(1234));
sprang4847ae62017-06-27 07:06:52 -0700385
Niels Möllerf1338562018-04-26 09:51:47 +0200386 ConfigureEncoder(std::move(video_encoder_config));
asapersson5f7226f2016-11-25 04:37:00 -0800387 }
388
Niels Möllerf1338562018-04-26 09:51:47 +0200389 void ConfigureEncoder(VideoEncoderConfig video_encoder_config) {
mflodmancc3d4422017-08-03 08:27:51 -0700390 if (video_stream_encoder_)
391 video_stream_encoder_->Stop();
392 video_stream_encoder_.reset(new VideoStreamEncoderUnderTest(
Danil Chapovalovd3ba2362019-04-10 17:01:23 +0200393 stats_proxy_.get(), video_send_config_.encoder_settings,
394 task_queue_factory_.get()));
mflodmancc3d4422017-08-03 08:27:51 -0700395 video_stream_encoder_->SetSink(&sink_, false /* rotation_applied */);
396 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -0700397 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -0700398 video_stream_encoder_->SetStartBitrate(kTargetBitrateBps);
399 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +0200400 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -0700401 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
asapersson5f7226f2016-11-25 04:37:00 -0800402 }
403
404 void ResetEncoder(const std::string& payload_name,
405 size_t num_streams,
406 size_t num_temporal_layers,
emircanbbcc3562017-08-18 00:28:40 -0700407 unsigned char num_spatial_layers,
sprang4847ae62017-06-27 07:06:52 -0700408 bool screenshare) {
Niels Möller259a4972018-04-05 15:36:51 +0200409 video_send_config_.rtp.payload_name = payload_name;
asapersson5f7226f2016-11-25 04:37:00 -0800410
411 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +0200412 video_encoder_config.codec_type = PayloadStringToCodecType(payload_name);
asapersson5f7226f2016-11-25 04:37:00 -0800413 video_encoder_config.number_of_streams = num_streams;
Erik Språngd7329ca2019-02-21 21:19:53 +0100414 video_encoder_config.max_bitrate_bps =
415 num_streams == 1 ? kTargetBitrateBps : kSimulcastTargetBitrateBps;
asapersson5f7226f2016-11-25 04:37:00 -0800416 video_encoder_config.video_stream_factory =
sprangfda496a2017-06-15 04:21:07 -0700417 new rtc::RefCountedObject<VideoStreamFactory>(num_temporal_layers,
418 kDefaultFramerate);
sprang4847ae62017-06-27 07:06:52 -0700419 video_encoder_config.content_type =
420 screenshare ? VideoEncoderConfig::ContentType::kScreen
421 : VideoEncoderConfig::ContentType::kRealtimeVideo;
emircanbbcc3562017-08-18 00:28:40 -0700422 if (payload_name == "VP9") {
423 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
424 vp9_settings.numberOfSpatialLayers = num_spatial_layers;
425 video_encoder_config.encoder_specific_settings =
426 new rtc::RefCountedObject<
427 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
428 }
Niels Möllerf1338562018-04-26 09:51:47 +0200429 ConfigureEncoder(std::move(video_encoder_config));
perkj26091b12016-09-01 01:17:40 -0700430 }
431
sprang57c2fff2017-01-16 06:24:02 -0800432 VideoFrame CreateFrame(int64_t ntp_time_ms,
433 rtc::Event* destruction_event) const {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100434 VideoFrame frame =
435 VideoFrame::Builder()
436 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
437 destruction_event, codec_width_, codec_height_))
438 .set_timestamp_rtp(99)
439 .set_timestamp_ms(99)
440 .set_rotation(kVideoRotation_0)
441 .build();
sprang57c2fff2017-01-16 06:24:02 -0800442 frame.set_ntp_time_ms(ntp_time_ms);
perkj26091b12016-09-01 01:17:40 -0700443 return frame;
444 }
445
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100446 VideoFrame CreateFrameWithUpdatedPixel(int64_t ntp_time_ms,
447 rtc::Event* destruction_event,
448 int offset_x) const {
449 VideoFrame frame =
450 VideoFrame::Builder()
451 .set_video_frame_buffer(new rtc::RefCountedObject<TestBuffer>(
452 destruction_event, codec_width_, codec_height_))
453 .set_timestamp_rtp(99)
454 .set_timestamp_ms(99)
455 .set_rotation(kVideoRotation_0)
456 .set_update_rect({offset_x, 0, 1, 1})
457 .build();
458 frame.set_ntp_time_ms(ntp_time_ms);
459 return frame;
460 }
461
sprang57c2fff2017-01-16 06:24:02 -0800462 VideoFrame CreateFrame(int64_t ntp_time_ms, int width, int height) const {
Artem Titov1ebfb6a2019-01-03 23:49:37 +0100463 VideoFrame frame =
464 VideoFrame::Builder()
465 .set_video_frame_buffer(
466 new rtc::RefCountedObject<TestBuffer>(nullptr, width, height))
467 .set_timestamp_rtp(99)
468 .set_timestamp_ms(99)
469 .set_rotation(kVideoRotation_0)
470 .build();
sprang57c2fff2017-01-16 06:24:02 -0800471 frame.set_ntp_time_ms(ntp_time_ms);
sprangc5d62e22017-04-02 23:53:04 -0700472 frame.set_timestamp_us(ntp_time_ms * 1000);
perkj803d97f2016-11-01 11:45:46 -0700473 return frame;
474 }
475
Noah Richards51db4212019-06-12 06:59:12 -0700476 VideoFrame CreateFakeNativeFrame(int64_t ntp_time_ms,
477 rtc::Event* destruction_event,
478 int width,
479 int height) const {
480 VideoFrame frame =
481 VideoFrame::Builder()
482 .set_video_frame_buffer(new rtc::RefCountedObject<FakeNativeBuffer>(
483 destruction_event, width, height))
484 .set_timestamp_rtp(99)
485 .set_timestamp_ms(99)
486 .set_rotation(kVideoRotation_0)
487 .build();
488 frame.set_ntp_time_ms(ntp_time_ms);
489 return frame;
490 }
491
492 VideoFrame CreateFakeNativeFrame(int64_t ntp_time_ms,
493 rtc::Event* destruction_event) const {
494 return CreateFakeNativeFrame(ntp_time_ms, destruction_event, codec_width_,
495 codec_height_);
496 }
497
Åsa Perssonc29cb2c2019-03-25 12:06:59 +0100498 void VerifyAllocatedBitrate(const VideoBitrateAllocation& expected_bitrate) {
499 MockBitrateObserver bitrate_observer;
500 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
501
502 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
503 .Times(1);
504 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kTargetBitrateBps),
Erik Språng4c6ca302019-04-08 15:14:01 +0200505 DataRate::bps(kTargetBitrateBps), 0,
506 0);
Åsa Perssonc29cb2c2019-03-25 12:06:59 +0100507
508 video_source_.IncomingCapturedFrame(
509 CreateFrame(1, codec_width_, codec_height_));
510 WaitForEncodedFrame(1);
511 }
512
asapersson02465b82017-04-10 01:12:52 -0700513 void VerifyNoLimitation(const rtc::VideoSinkWants& wants) {
asapersson02465b82017-04-10 01:12:52 -0700514 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700515 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
516 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700517 }
518
asapersson09f05612017-05-15 23:40:18 -0700519 void VerifyFpsEqResolutionEq(const rtc::VideoSinkWants& wants1,
520 const rtc::VideoSinkWants& wants2) {
521 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
522 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
523 }
524
Åsa Persson8c1bf952018-09-13 10:42:19 +0200525 void VerifyFpsMaxResolutionMax(const rtc::VideoSinkWants& wants) {
526 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
527 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
528 EXPECT_FALSE(wants.target_pixel_count);
529 }
530
asapersson09f05612017-05-15 23:40:18 -0700531 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants1,
532 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200533 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700534 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
535 EXPECT_GT(wants1.max_pixel_count, 0);
536 }
537
538 void VerifyFpsMaxResolutionGt(const rtc::VideoSinkWants& wants1,
539 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200540 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asapersson09f05612017-05-15 23:40:18 -0700541 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
542 }
543
asaperssonf7e294d2017-06-13 23:25:22 -0700544 void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
545 const rtc::VideoSinkWants& wants2) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200546 EXPECT_EQ(kDefaultFramerate, wants1.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -0700547 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
548 }
549
550 void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
551 const rtc::VideoSinkWants& wants2) {
552 EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
553 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
554 }
555
556 void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
557 const rtc::VideoSinkWants& wants2) {
558 EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
559 EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
560 }
561
562 void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
563 const rtc::VideoSinkWants& wants2) {
564 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
565 EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
566 EXPECT_GT(wants1.max_pixel_count, 0);
567 }
568
569 void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
570 const rtc::VideoSinkWants& wants2) {
571 EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
572 EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
573 }
574
asapersson09f05612017-05-15 23:40:18 -0700575 void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
576 int pixel_count) {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200577 EXPECT_EQ(kDefaultFramerate, wants.max_framerate_fps);
asapersson02465b82017-04-10 01:12:52 -0700578 EXPECT_LT(wants.max_pixel_count, pixel_count);
579 EXPECT_GT(wants.max_pixel_count, 0);
asapersson09f05612017-05-15 23:40:18 -0700580 }
581
582 void VerifyFpsLtResolutionMax(const rtc::VideoSinkWants& wants, int fps) {
583 EXPECT_LT(wants.max_framerate_fps, fps);
584 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
585 EXPECT_FALSE(wants.target_pixel_count);
asapersson02465b82017-04-10 01:12:52 -0700586 }
587
asaperssonf7e294d2017-06-13 23:25:22 -0700588 void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
589 int expected_fps) {
590 EXPECT_EQ(expected_fps, wants.max_framerate_fps);
591 EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
592 EXPECT_FALSE(wants.target_pixel_count);
593 }
594
Jonathan Yubc771b72017-12-08 17:04:29 -0800595 void VerifyBalancedModeFpsRange(const rtc::VideoSinkWants& wants,
596 int last_frame_pixels) {
597 // Balanced mode should always scale FPS to the desired range before
598 // attempting to scale resolution.
599 int fps_limit = wants.max_framerate_fps;
600 if (last_frame_pixels <= 320 * 240) {
601 EXPECT_TRUE(7 <= fps_limit && fps_limit <= 10);
602 } else if (last_frame_pixels <= 480 * 270) {
603 EXPECT_TRUE(10 <= fps_limit && fps_limit <= 15);
604 } else if (last_frame_pixels <= 640 * 480) {
605 EXPECT_LE(15, fps_limit);
606 } else {
Åsa Persson8c1bf952018-09-13 10:42:19 +0200607 EXPECT_EQ(kDefaultFramerate, fps_limit);
Jonathan Yubc771b72017-12-08 17:04:29 -0800608 }
609 }
610
sprang4847ae62017-06-27 07:06:52 -0700611 void WaitForEncodedFrame(int64_t expected_ntp_time) {
612 sink_.WaitForEncodedFrame(expected_ntp_time);
Sebastian Jansson40889f32019-04-17 12:11:20 +0200613 fake_clock_.AdvanceTime(TimeDelta::seconds(1) / max_framerate_);
sprang4847ae62017-06-27 07:06:52 -0700614 }
615
616 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time, int64_t timeout_ms) {
617 bool ok = sink_.TimedWaitForEncodedFrame(expected_ntp_time, timeout_ms);
Sebastian Jansson40889f32019-04-17 12:11:20 +0200618 fake_clock_.AdvanceTime(TimeDelta::seconds(1) / max_framerate_);
sprang4847ae62017-06-27 07:06:52 -0700619 return ok;
620 }
621
622 void WaitForEncodedFrame(uint32_t expected_width, uint32_t expected_height) {
623 sink_.WaitForEncodedFrame(expected_width, expected_height);
Sebastian Jansson40889f32019-04-17 12:11:20 +0200624 fake_clock_.AdvanceTime(TimeDelta::seconds(1) / max_framerate_);
sprang4847ae62017-06-27 07:06:52 -0700625 }
626
627 void ExpectDroppedFrame() {
628 sink_.ExpectDroppedFrame();
Sebastian Jansson40889f32019-04-17 12:11:20 +0200629 fake_clock_.AdvanceTime(TimeDelta::seconds(1) / max_framerate_);
sprang4847ae62017-06-27 07:06:52 -0700630 }
631
632 bool WaitForFrame(int64_t timeout_ms) {
633 bool ok = sink_.WaitForFrame(timeout_ms);
Sebastian Jansson40889f32019-04-17 12:11:20 +0200634 fake_clock_.AdvanceTime(TimeDelta::seconds(1) / max_framerate_);
sprang4847ae62017-06-27 07:06:52 -0700635 return ok;
636 }
637
perkj26091b12016-09-01 01:17:40 -0700638 class TestEncoder : public test::FakeEncoder {
639 public:
Niels Möllerc572ff32018-11-07 08:43:50 +0100640 TestEncoder() : FakeEncoder(Clock::GetRealTimeClock()) {}
perkj26091b12016-09-01 01:17:40 -0700641
asaperssonfab67072017-04-04 05:51:49 -0700642 VideoCodec codec_config() const {
brandtre78d2662017-01-16 05:57:16 -0800643 rtc::CritScope lock(&crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700644 return config_;
645 }
646
647 void BlockNextEncode() {
brandtre78d2662017-01-16 05:57:16 -0800648 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700649 block_next_encode_ = true;
650 }
651
Erik Språngaed30702018-11-05 12:57:17 +0100652 VideoEncoder::EncoderInfo GetEncoderInfo() const override {
kthelgason2fc52542017-03-03 00:24:41 -0800653 rtc::CritScope lock(&local_crit_sect_);
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100654 EncoderInfo info;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100655 if (initialized_ == EncoderState::kInitialized) {
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100656 if (quality_scaling_) {
657 info.scaling_settings =
658 VideoEncoder::ScalingSettings(1, 2, kMinPixelsPerFrame);
659 }
660 info.is_hardware_accelerated = is_hardware_accelerated_;
Åsa Perssonc29cb2c2019-03-25 12:06:59 +0100661 for (int i = 0; i < kMaxSpatialLayers; ++i) {
662 if (temporal_layers_supported_[i]) {
663 int num_layers = temporal_layers_supported_[i].value() ? 2 : 1;
664 info.fps_allocation[i].resize(num_layers);
665 }
666 }
Erik Språngaed30702018-11-05 12:57:17 +0100667 }
668 return info;
kthelgason876222f2016-11-29 01:44:11 -0800669 }
670
Erik Språngb7cb7b52019-02-26 15:52:33 +0100671 int32_t RegisterEncodeCompleteCallback(
672 EncodedImageCallback* callback) override {
673 rtc::CritScope lock(&local_crit_sect_);
674 encoded_image_callback_ = callback;
675 return FakeEncoder::RegisterEncodeCompleteCallback(callback);
676 }
677
perkjfa10b552016-10-02 23:45:26 -0700678 void ContinueEncode() { continue_encode_event_.Set(); }
679
680 void CheckLastTimeStampsMatch(int64_t ntp_time_ms,
681 uint32_t timestamp) const {
brandtre78d2662017-01-16 05:57:16 -0800682 rtc::CritScope lock(&local_crit_sect_);
perkjfa10b552016-10-02 23:45:26 -0700683 EXPECT_EQ(timestamp_, timestamp);
684 EXPECT_EQ(ntp_time_ms_, ntp_time_ms);
685 }
686
kthelgason2fc52542017-03-03 00:24:41 -0800687 void SetQualityScaling(bool b) {
688 rtc::CritScope lock(&local_crit_sect_);
689 quality_scaling_ = b;
690 }
kthelgasonad9010c2017-02-14 00:46:51 -0800691
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100692 void SetIsHardwareAccelerated(bool is_hardware_accelerated) {
693 rtc::CritScope lock(&local_crit_sect_);
694 is_hardware_accelerated_ = is_hardware_accelerated;
695 }
696
Åsa Perssonc29cb2c2019-03-25 12:06:59 +0100697 void SetTemporalLayersSupported(size_t spatial_idx, bool supported) {
698 RTC_DCHECK_LT(spatial_idx, kMaxSpatialLayers);
699 rtc::CritScope lock(&local_crit_sect_);
700 temporal_layers_supported_[spatial_idx] = supported;
701 }
702
sprangfe627f32017-03-29 08:24:59 -0700703 void ForceInitEncodeFailure(bool force_failure) {
704 rtc::CritScope lock(&local_crit_sect_);
705 force_init_encode_failed_ = force_failure;
706 }
707
Niels Möller6bb5ab92019-01-11 11:11:10 +0100708 void SimulateOvershoot(double rate_factor) {
709 rtc::CritScope lock(&local_crit_sect_);
710 rate_factor_ = rate_factor;
711 }
712
Erik Språngd7329ca2019-02-21 21:19:53 +0100713 uint32_t GetLastFramerate() const {
Niels Möller6bb5ab92019-01-11 11:11:10 +0100714 rtc::CritScope lock(&local_crit_sect_);
715 return last_framerate_;
716 }
717
Erik Språngd7329ca2019-02-21 21:19:53 +0100718 VideoFrame::UpdateRect GetLastUpdateRect() const {
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100719 rtc::CritScope lock(&local_crit_sect_);
720 return last_update_rect_;
721 }
722
Niels Möller87e2d782019-03-07 10:18:23 +0100723 const std::vector<VideoFrameType>& LastFrameTypes() const {
Erik Språngd7329ca2019-02-21 21:19:53 +0100724 rtc::CritScope lock(&local_crit_sect_);
725 return last_frame_types_;
726 }
727
728 void InjectFrame(const VideoFrame& input_image, bool keyframe) {
Niels Möller87e2d782019-03-07 10:18:23 +0100729 const std::vector<VideoFrameType> frame_type = {
Niels Möller8f7ce222019-03-21 15:43:58 +0100730 keyframe ? VideoFrameType::kVideoFrameKey
731 : VideoFrameType::kVideoFrameDelta};
Erik Språngd7329ca2019-02-21 21:19:53 +0100732 {
733 rtc::CritScope lock(&local_crit_sect_);
734 last_frame_types_ = frame_type;
735 }
Niels Möllerb859b322019-03-07 12:40:01 +0100736 FakeEncoder::Encode(input_image, &frame_type);
Erik Språngd7329ca2019-02-21 21:19:53 +0100737 }
738
Erik Språngb7cb7b52019-02-26 15:52:33 +0100739 void InjectEncodedImage(const EncodedImage& image) {
740 rtc::CritScope lock(&local_crit_sect_);
741 encoded_image_callback_->OnEncodedImage(image, nullptr, nullptr);
742 }
743
Mirta Dvornicic28f0eb22019-05-28 16:30:16 +0200744 void InjectEncodedImage(const EncodedImage& image,
745 const CodecSpecificInfo* codec_specific_info,
746 const RTPFragmentationHeader* fragmentation) {
747 rtc::CritScope lock(&local_crit_sect_);
748 encoded_image_callback_->OnEncodedImage(image, codec_specific_info,
749 fragmentation);
750 }
751
Erik Språngd7329ca2019-02-21 21:19:53 +0100752 void ExpectNullFrame() {
753 rtc::CritScope lock(&local_crit_sect_);
754 expect_null_frame_ = true;
755 }
756
757 absl::optional<VideoBitrateAllocation> GetAndResetLastBitrateAllocation() {
758 auto allocation = last_bitrate_allocation_;
759 last_bitrate_allocation_.reset();
760 return allocation;
761 }
762
perkjfa10b552016-10-02 23:45:26 -0700763 private:
perkj26091b12016-09-01 01:17:40 -0700764 int32_t Encode(const VideoFrame& input_image,
Niels Möller87e2d782019-03-07 10:18:23 +0100765 const std::vector<VideoFrameType>* frame_types) override {
perkj26091b12016-09-01 01:17:40 -0700766 bool block_encode;
767 {
brandtre78d2662017-01-16 05:57:16 -0800768 rtc::CritScope lock(&local_crit_sect_);
Erik Språngd7329ca2019-02-21 21:19:53 +0100769 if (expect_null_frame_) {
770 EXPECT_EQ(input_image.timestamp(), 0u);
771 EXPECT_EQ(input_image.width(), 1);
772 last_frame_types_ = *frame_types;
773 expect_null_frame_ = false;
774 } else {
775 EXPECT_GT(input_image.timestamp(), timestamp_);
776 EXPECT_GT(input_image.ntp_time_ms(), ntp_time_ms_);
777 EXPECT_EQ(input_image.timestamp(), input_image.ntp_time_ms() * 90);
778 }
perkj26091b12016-09-01 01:17:40 -0700779
780 timestamp_ = input_image.timestamp();
781 ntp_time_ms_ = input_image.ntp_time_ms();
perkj803d97f2016-11-01 11:45:46 -0700782 last_input_width_ = input_image.width();
783 last_input_height_ = input_image.height();
perkj26091b12016-09-01 01:17:40 -0700784 block_encode = block_next_encode_;
785 block_next_encode_ = false;
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100786 last_update_rect_ = input_image.update_rect();
Erik Språngd7329ca2019-02-21 21:19:53 +0100787 last_frame_types_ = *frame_types;
perkj26091b12016-09-01 01:17:40 -0700788 }
Niels Möllerb859b322019-03-07 12:40:01 +0100789 int32_t result = FakeEncoder::Encode(input_image, frame_types);
perkj26091b12016-09-01 01:17:40 -0700790 if (block_encode)
perkja49cbd32016-09-16 07:53:41 -0700791 EXPECT_TRUE(continue_encode_event_.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -0700792 return result;
793 }
794
sprangfe627f32017-03-29 08:24:59 -0700795 int32_t InitEncode(const VideoCodec* config,
Elad Alon370f93a2019-06-11 14:57:57 +0200796 const Settings& settings) override {
797 int res = FakeEncoder::InitEncode(config, settings);
sprangfe627f32017-03-29 08:24:59 -0700798 rtc::CritScope lock(&local_crit_sect_);
Erik Språngb7cb7b52019-02-26 15:52:33 +0100799 EXPECT_EQ(initialized_, EncoderState::kUninitialized);
Erik Språng82fad3d2018-03-21 09:57:23 +0100800 if (config->codecType == kVideoCodecVP8) {
sprangfe627f32017-03-29 08:24:59 -0700801 // Simulate setting up temporal layers, in order to validate the life
802 // cycle of these objects.
Elad Aloncde8ab22019-03-20 11:56:20 +0100803 Vp8TemporalLayersFactory factory;
Elad Alona2795842019-06-07 23:10:00 +0200804 frame_buffer_controller_ = factory.Create(*config, settings);
sprangfe627f32017-03-29 08:24:59 -0700805 }
Erik Språngb7cb7b52019-02-26 15:52:33 +0100806 if (force_init_encode_failed_) {
807 initialized_ = EncoderState::kInitializationFailed;
sprangfe627f32017-03-29 08:24:59 -0700808 return -1;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100809 }
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100810
Erik Språngb7cb7b52019-02-26 15:52:33 +0100811 initialized_ = EncoderState::kInitialized;
sprangfe627f32017-03-29 08:24:59 -0700812 return res;
813 }
814
Erik Språngb7cb7b52019-02-26 15:52:33 +0100815 int32_t Release() override {
816 rtc::CritScope lock(&local_crit_sect_);
817 EXPECT_NE(initialized_, EncoderState::kUninitialized);
818 initialized_ = EncoderState::kUninitialized;
819 return FakeEncoder::Release();
820 }
821
Erik Språng16cb8f52019-04-12 13:59:09 +0200822 void SetRates(const RateControlParameters& parameters) {
Niels Möller6bb5ab92019-01-11 11:11:10 +0100823 rtc::CritScope lock(&local_crit_sect_);
824 VideoBitrateAllocation adjusted_rate_allocation;
825 for (size_t si = 0; si < kMaxSpatialLayers; ++si) {
826 for (size_t ti = 0; ti < kMaxTemporalStreams; ++ti) {
Erik Språng16cb8f52019-04-12 13:59:09 +0200827 if (parameters.bitrate.HasBitrate(si, ti)) {
Niels Möller6bb5ab92019-01-11 11:11:10 +0100828 adjusted_rate_allocation.SetBitrate(
829 si, ti,
Erik Språng16cb8f52019-04-12 13:59:09 +0200830 static_cast<uint32_t>(parameters.bitrate.GetBitrate(si, ti) *
Niels Möller6bb5ab92019-01-11 11:11:10 +0100831 rate_factor_));
832 }
833 }
834 }
Erik Språng16cb8f52019-04-12 13:59:09 +0200835 last_framerate_ = static_cast<uint32_t>(parameters.framerate_fps + 0.5);
836 last_bitrate_allocation_ = parameters.bitrate;
837 RateControlParameters adjusted_paramters = parameters;
838 adjusted_paramters.bitrate = adjusted_rate_allocation;
839 FakeEncoder::SetRates(adjusted_paramters);
Niels Möller6bb5ab92019-01-11 11:11:10 +0100840 }
841
brandtre78d2662017-01-16 05:57:16 -0800842 rtc::CriticalSection local_crit_sect_;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100843 enum class EncoderState {
844 kUninitialized,
845 kInitializationFailed,
846 kInitialized
847 } initialized_ RTC_GUARDED_BY(local_crit_sect_) =
848 EncoderState::kUninitialized;
danilchapa37de392017-09-09 04:17:22 -0700849 bool block_next_encode_ RTC_GUARDED_BY(local_crit_sect_) = false;
perkj26091b12016-09-01 01:17:40 -0700850 rtc::Event continue_encode_event_;
danilchapa37de392017-09-09 04:17:22 -0700851 uint32_t timestamp_ RTC_GUARDED_BY(local_crit_sect_) = 0;
852 int64_t ntp_time_ms_ RTC_GUARDED_BY(local_crit_sect_) = 0;
853 int last_input_width_ RTC_GUARDED_BY(local_crit_sect_) = 0;
854 int last_input_height_ RTC_GUARDED_BY(local_crit_sect_) = 0;
855 bool quality_scaling_ RTC_GUARDED_BY(local_crit_sect_) = true;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +0100856 bool is_hardware_accelerated_ RTC_GUARDED_BY(local_crit_sect_) = false;
Elad Aloncde8ab22019-03-20 11:56:20 +0100857 std::unique_ptr<Vp8FrameBufferController> frame_buffer_controller_
danilchapa37de392017-09-09 04:17:22 -0700858 RTC_GUARDED_BY(local_crit_sect_);
Åsa Perssonc29cb2c2019-03-25 12:06:59 +0100859 absl::optional<bool>
860 temporal_layers_supported_[kMaxSpatialLayers] RTC_GUARDED_BY(
861 local_crit_sect_);
danilchapa37de392017-09-09 04:17:22 -0700862 bool force_init_encode_failed_ RTC_GUARDED_BY(local_crit_sect_) = false;
Niels Möller6bb5ab92019-01-11 11:11:10 +0100863 double rate_factor_ RTC_GUARDED_BY(local_crit_sect_) = 1.0;
864 uint32_t last_framerate_ RTC_GUARDED_BY(local_crit_sect_) = 0;
Erik Språngd7329ca2019-02-21 21:19:53 +0100865 absl::optional<VideoBitrateAllocation> last_bitrate_allocation_;
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +0100866 VideoFrame::UpdateRect last_update_rect_
867 RTC_GUARDED_BY(local_crit_sect_) = {0, 0, 0, 0};
Niels Möller87e2d782019-03-07 10:18:23 +0100868 std::vector<VideoFrameType> last_frame_types_;
Erik Språngd7329ca2019-02-21 21:19:53 +0100869 bool expect_null_frame_ = false;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100870 EncodedImageCallback* encoded_image_callback_
871 RTC_GUARDED_BY(local_crit_sect_) = nullptr;
perkj26091b12016-09-01 01:17:40 -0700872 };
873
mflodmancc3d4422017-08-03 08:27:51 -0700874 class TestSink : public VideoStreamEncoder::EncoderSink {
perkj26091b12016-09-01 01:17:40 -0700875 public:
876 explicit TestSink(TestEncoder* test_encoder)
Niels Möllerc572ff32018-11-07 08:43:50 +0100877 : test_encoder_(test_encoder) {}
perkj26091b12016-09-01 01:17:40 -0700878
perkj26091b12016-09-01 01:17:40 -0700879 void WaitForEncodedFrame(int64_t expected_ntp_time) {
sprang4847ae62017-06-27 07:06:52 -0700880 EXPECT_TRUE(
881 TimedWaitForEncodedFrame(expected_ntp_time, kDefaultTimeoutMs));
882 }
883
884 bool TimedWaitForEncodedFrame(int64_t expected_ntp_time,
885 int64_t timeout_ms) {
perkj26091b12016-09-01 01:17:40 -0700886 uint32_t timestamp = 0;
sprang4847ae62017-06-27 07:06:52 -0700887 if (!encoded_frame_event_.Wait(timeout_ms))
888 return false;
perkj26091b12016-09-01 01:17:40 -0700889 {
890 rtc::CritScope lock(&crit_);
sprangb1ca0732017-02-01 08:38:12 -0800891 timestamp = last_timestamp_;
perkj26091b12016-09-01 01:17:40 -0700892 }
893 test_encoder_->CheckLastTimeStampsMatch(expected_ntp_time, timestamp);
sprang4847ae62017-06-27 07:06:52 -0700894 return true;
perkj26091b12016-09-01 01:17:40 -0700895 }
896
sprangb1ca0732017-02-01 08:38:12 -0800897 void WaitForEncodedFrame(uint32_t expected_width,
898 uint32_t expected_height) {
sprangc5d62e22017-04-02 23:53:04 -0700899 EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs));
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100900 CheckLastFrameSizeMatches(expected_width, expected_height);
sprangc5d62e22017-04-02 23:53:04 -0700901 }
902
Åsa Perssonc74d8da2017-12-04 14:13:56 +0100903 void CheckLastFrameSizeMatches(uint32_t expected_width,
sprangc5d62e22017-04-02 23:53:04 -0700904 uint32_t expected_height) {
sprangb1ca0732017-02-01 08:38:12 -0800905 uint32_t width = 0;
906 uint32_t height = 0;
sprangb1ca0732017-02-01 08:38:12 -0800907 {
908 rtc::CritScope lock(&crit_);
909 width = last_width_;
910 height = last_height_;
911 }
912 EXPECT_EQ(expected_height, height);
913 EXPECT_EQ(expected_width, width);
914 }
915
Ilya Nikolaevskiyba96e2f2019-06-04 15:15:14 +0200916 void CheckLastFrameRotationMatches(VideoRotation expected_rotation) {
917 VideoRotation rotation;
918 {
919 rtc::CritScope lock(&crit_);
920 rotation = last_rotation_;
921 }
922 EXPECT_EQ(expected_rotation, rotation);
923 }
924
kthelgason2fc52542017-03-03 00:24:41 -0800925 void ExpectDroppedFrame() { EXPECT_FALSE(encoded_frame_event_.Wait(100)); }
kthelgason2bc68642017-02-07 07:02:22 -0800926
sprangc5d62e22017-04-02 23:53:04 -0700927 bool WaitForFrame(int64_t timeout_ms) {
928 return encoded_frame_event_.Wait(timeout_ms);
929 }
930
perkj26091b12016-09-01 01:17:40 -0700931 void SetExpectNoFrames() {
932 rtc::CritScope lock(&crit_);
933 expect_frames_ = false;
934 }
935
asaperssonfab67072017-04-04 05:51:49 -0700936 int number_of_reconfigurations() const {
Per512ecb32016-09-23 15:52:06 +0200937 rtc::CritScope lock(&crit_);
938 return number_of_reconfigurations_;
939 }
940
asaperssonfab67072017-04-04 05:51:49 -0700941 int last_min_transmit_bitrate() const {
Per512ecb32016-09-23 15:52:06 +0200942 rtc::CritScope lock(&crit_);
943 return min_transmit_bitrate_bps_;
944 }
945
Erik Språngd7329ca2019-02-21 21:19:53 +0100946 void SetNumExpectedLayers(size_t num_layers) {
947 rtc::CritScope lock(&crit_);
948 num_expected_layers_ = num_layers;
949 }
950
Erik Språngb7cb7b52019-02-26 15:52:33 +0100951 int64_t GetLastCaptureTimeMs() const {
952 rtc::CritScope lock(&crit_);
953 return last_capture_time_ms_;
954 }
955
Mirta Dvornicic28f0eb22019-05-28 16:30:16 +0200956 std::vector<uint8_t> GetLastEncodedImageData() {
957 rtc::CritScope lock(&crit_);
958 return std::move(last_encoded_image_data_);
959 }
960
961 RTPFragmentationHeader GetLastFragmentation() {
962 rtc::CritScope lock(&crit_);
963 return std::move(last_fragmentation_);
964 }
965
perkj26091b12016-09-01 01:17:40 -0700966 private:
sergeyu2cb155a2016-11-04 11:39:29 -0700967 Result OnEncodedImage(
968 const EncodedImage& encoded_image,
969 const CodecSpecificInfo* codec_specific_info,
970 const RTPFragmentationHeader* fragmentation) override {
Per512ecb32016-09-23 15:52:06 +0200971 rtc::CritScope lock(&crit_);
972 EXPECT_TRUE(expect_frames_);
Mirta Dvornicic28f0eb22019-05-28 16:30:16 +0200973 last_encoded_image_data_ = std::vector<uint8_t>(
974 encoded_image.data(), encoded_image.data() + encoded_image.size());
975 if (fragmentation) {
976 last_fragmentation_.CopyFrom(*fragmentation);
977 }
Erik Språngd7329ca2019-02-21 21:19:53 +0100978 uint32_t timestamp = encoded_image.Timestamp();
979 if (last_timestamp_ != timestamp) {
980 num_received_layers_ = 1;
981 } else {
982 ++num_received_layers_;
983 }
984 last_timestamp_ = timestamp;
Erik Språngb7cb7b52019-02-26 15:52:33 +0100985 last_capture_time_ms_ = encoded_image.capture_time_ms_;
sprangb1ca0732017-02-01 08:38:12 -0800986 last_width_ = encoded_image._encodedWidth;
987 last_height_ = encoded_image._encodedHeight;
Ilya Nikolaevskiyba96e2f2019-06-04 15:15:14 +0200988 last_rotation_ = encoded_image.rotation_;
Erik Språngd7329ca2019-02-21 21:19:53 +0100989 if (num_received_layers_ == num_expected_layers_) {
990 encoded_frame_event_.Set();
991 }
sprangb1ca0732017-02-01 08:38:12 -0800992 return Result(Result::OK, last_timestamp_);
Per512ecb32016-09-23 15:52:06 +0200993 }
994
Rasmus Brandtc402dbe2019-02-04 11:09:46 +0100995 void OnEncoderConfigurationChanged(
996 std::vector<VideoStream> streams,
997 VideoEncoderConfig::ContentType content_type,
998 int min_transmit_bitrate_bps) override {
Per512ecb32016-09-23 15:52:06 +0200999 rtc::CriticalSection crit_;
1000 ++number_of_reconfigurations_;
1001 min_transmit_bitrate_bps_ = min_transmit_bitrate_bps;
1002 }
1003
perkj26091b12016-09-01 01:17:40 -07001004 rtc::CriticalSection crit_;
1005 TestEncoder* test_encoder_;
1006 rtc::Event encoded_frame_event_;
Mirta Dvornicic28f0eb22019-05-28 16:30:16 +02001007 std::vector<uint8_t> last_encoded_image_data_;
1008 RTPFragmentationHeader last_fragmentation_;
sprangb1ca0732017-02-01 08:38:12 -08001009 uint32_t last_timestamp_ = 0;
Erik Språngb7cb7b52019-02-26 15:52:33 +01001010 int64_t last_capture_time_ms_ = 0;
sprangb1ca0732017-02-01 08:38:12 -08001011 uint32_t last_height_ = 0;
1012 uint32_t last_width_ = 0;
Ilya Nikolaevskiyba96e2f2019-06-04 15:15:14 +02001013 VideoRotation last_rotation_ = kVideoRotation_0;
Erik Språngd7329ca2019-02-21 21:19:53 +01001014 size_t num_expected_layers_ = 1;
1015 size_t num_received_layers_ = 0;
perkj26091b12016-09-01 01:17:40 -07001016 bool expect_frames_ = true;
Per512ecb32016-09-23 15:52:06 +02001017 int number_of_reconfigurations_ = 0;
1018 int min_transmit_bitrate_bps_ = 0;
perkj26091b12016-09-01 01:17:40 -07001019 };
1020
1021 VideoSendStream::Config video_send_config_;
Erik Språng08127a92016-11-16 16:41:30 +01001022 VideoEncoderConfig video_encoder_config_;
Per512ecb32016-09-23 15:52:06 +02001023 int codec_width_;
1024 int codec_height_;
sprang4847ae62017-06-27 07:06:52 -07001025 int max_framerate_;
Danil Chapovalovd3ba2362019-04-10 17:01:23 +02001026 const std::unique_ptr<TaskQueueFactory> task_queue_factory_;
perkj26091b12016-09-01 01:17:40 -07001027 TestEncoder fake_encoder_;
Niels Möllercbcbc222018-09-28 09:07:24 +02001028 test::VideoEncoderProxyFactory encoder_factory_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -08001029 std::unique_ptr<VideoBitrateAllocatorFactory> bitrate_allocator_factory_;
sprangc5d62e22017-04-02 23:53:04 -07001030 std::unique_ptr<MockableSendStatisticsProxy> stats_proxy_;
perkj26091b12016-09-01 01:17:40 -07001031 TestSink sink_;
sprangb1ca0732017-02-01 08:38:12 -08001032 AdaptingFrameForwarder video_source_;
mflodmancc3d4422017-08-03 08:27:51 -07001033 std::unique_ptr<VideoStreamEncoderUnderTest> video_stream_encoder_;
sprang4847ae62017-06-27 07:06:52 -07001034 rtc::ScopedFakeClock fake_clock_;
perkj26091b12016-09-01 01:17:40 -07001035};
1036
mflodmancc3d4422017-08-03 08:27:51 -07001037TEST_F(VideoStreamEncoderTest, EncodeOneFrame) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001038 video_stream_encoder_->OnBitrateUpdated(
1039 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möllerc572ff32018-11-07 08:43:50 +01001040 rtc::Event frame_destroyed_event;
perkja49cbd32016-09-16 07:53:41 -07001041 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
sprang4847ae62017-06-27 07:06:52 -07001042 WaitForEncodedFrame(1);
perkja49cbd32016-09-16 07:53:41 -07001043 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
mflodmancc3d4422017-08-03 08:27:51 -07001044 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -07001045}
1046
mflodmancc3d4422017-08-03 08:27:51 -07001047TEST_F(VideoStreamEncoderTest, DropsFramesBeforeFirstOnBitrateUpdated) {
perkj26091b12016-09-01 01:17:40 -07001048 // Dropped since no target bitrate has been set.
Niels Möllerc572ff32018-11-07 08:43:50 +01001049 rtc::Event frame_destroyed_event;
Sebastian Janssona3177052018-04-10 13:05:49 +02001050 // The encoder will cache up to one frame for a short duration. Adding two
1051 // frames means that the first frame will be dropped and the second frame will
1052 // be sent when the encoder is enabled.
perkja49cbd32016-09-16 07:53:41 -07001053 video_source_.IncomingCapturedFrame(CreateFrame(1, &frame_destroyed_event));
Sebastian Janssona3177052018-04-10 13:05:49 +02001054 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
perkja49cbd32016-09-16 07:53:41 -07001055 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -07001056
Erik Språng4c6ca302019-04-08 15:14:01 +02001057 video_stream_encoder_->OnBitrateUpdated(
1058 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkj26091b12016-09-01 01:17:40 -07001059
Sebastian Janssona3177052018-04-10 13:05:49 +02001060 // The pending frame should be received.
sprang4847ae62017-06-27 07:06:52 -07001061 WaitForEncodedFrame(2);
Sebastian Janssona3177052018-04-10 13:05:49 +02001062 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
1063
1064 WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001065 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -07001066}
1067
mflodmancc3d4422017-08-03 08:27:51 -07001068TEST_F(VideoStreamEncoderTest, DropsFramesWhenRateSetToZero) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001069 video_stream_encoder_->OnBitrateUpdated(
1070 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkja49cbd32016-09-16 07:53:41 -07001071 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001072 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -07001073
Erik Språng4c6ca302019-04-08 15:14:01 +02001074 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(0), DataRate::bps(0), 0,
Erik Språng610c7632019-03-06 15:37:33 +01001075 0);
Sebastian Janssona3177052018-04-10 13:05:49 +02001076 // The encoder will cache up to one frame for a short duration. Adding two
1077 // frames means that the first frame will be dropped and the second frame will
1078 // be sent when the encoder is resumed.
perkja49cbd32016-09-16 07:53:41 -07001079 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
Sebastian Janssona3177052018-04-10 13:05:49 +02001080 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -07001081
Erik Språng4c6ca302019-04-08 15:14:01 +02001082 video_stream_encoder_->OnBitrateUpdated(
1083 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
sprang4847ae62017-06-27 07:06:52 -07001084 WaitForEncodedFrame(3);
Sebastian Janssona3177052018-04-10 13:05:49 +02001085 video_source_.IncomingCapturedFrame(CreateFrame(4, nullptr));
1086 WaitForEncodedFrame(4);
mflodmancc3d4422017-08-03 08:27:51 -07001087 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -07001088}
1089
mflodmancc3d4422017-08-03 08:27:51 -07001090TEST_F(VideoStreamEncoderTest, DropsFramesWithSameOrOldNtpTimestamp) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001091 video_stream_encoder_->OnBitrateUpdated(
1092 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkja49cbd32016-09-16 07:53:41 -07001093 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001094 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -07001095
1096 // This frame will be dropped since it has the same ntp timestamp.
perkja49cbd32016-09-16 07:53:41 -07001097 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
perkj26091b12016-09-01 01:17:40 -07001098
perkja49cbd32016-09-16 07:53:41 -07001099 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001100 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001101 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -07001102}
1103
mflodmancc3d4422017-08-03 08:27:51 -07001104TEST_F(VideoStreamEncoderTest, DropsFrameAfterStop) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001105 video_stream_encoder_->OnBitrateUpdated(
1106 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkj26091b12016-09-01 01:17:40 -07001107
perkja49cbd32016-09-16 07:53:41 -07001108 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001109 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -07001110
mflodmancc3d4422017-08-03 08:27:51 -07001111 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -07001112 sink_.SetExpectNoFrames();
Niels Möllerc572ff32018-11-07 08:43:50 +01001113 rtc::Event frame_destroyed_event;
perkja49cbd32016-09-16 07:53:41 -07001114 video_source_.IncomingCapturedFrame(CreateFrame(2, &frame_destroyed_event));
1115 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
perkj26091b12016-09-01 01:17:40 -07001116}
1117
mflodmancc3d4422017-08-03 08:27:51 -07001118TEST_F(VideoStreamEncoderTest, DropsPendingFramesOnSlowEncode) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001119 video_stream_encoder_->OnBitrateUpdated(
1120 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkj26091b12016-09-01 01:17:40 -07001121
1122 fake_encoder_.BlockNextEncode();
perkja49cbd32016-09-16 07:53:41 -07001123 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001124 WaitForEncodedFrame(1);
perkj26091b12016-09-01 01:17:40 -07001125 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
1126 // call to ContinueEncode.
perkja49cbd32016-09-16 07:53:41 -07001127 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
1128 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
perkj26091b12016-09-01 01:17:40 -07001129 fake_encoder_.ContinueEncode();
sprang4847ae62017-06-27 07:06:52 -07001130 WaitForEncodedFrame(3);
perkj26091b12016-09-01 01:17:40 -07001131
mflodmancc3d4422017-08-03 08:27:51 -07001132 video_stream_encoder_->Stop();
perkj26091b12016-09-01 01:17:40 -07001133}
1134
Noah Richards51db4212019-06-12 06:59:12 -07001135TEST_F(VideoStreamEncoderTest, DropFrameWithFailedI420Conversion) {
1136 video_stream_encoder_->OnBitrateUpdated(
1137 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
1138
1139 rtc::Event frame_destroyed_event;
1140 video_source_.IncomingCapturedFrame(
1141 CreateFakeNativeFrame(1, &frame_destroyed_event));
1142 ExpectDroppedFrame();
1143 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
1144 video_stream_encoder_->Stop();
1145}
1146
1147TEST_F(VideoStreamEncoderTest, DropFrameWithFailedI420ConversionWithCrop) {
1148 // Use the cropping factory.
1149 video_encoder_config_.video_stream_factory =
1150 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, 30);
1151 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config_),
1152 kMaxPayloadLength);
1153 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
1154
1155 // Capture a frame at codec_width_/codec_height_.
1156 video_stream_encoder_->OnBitrateUpdated(
1157 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
1158 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
1159 WaitForEncodedFrame(1);
1160 // The encoder will have been configured once.
1161 EXPECT_EQ(1, sink_.number_of_reconfigurations());
1162 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
1163 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
1164
1165 // Now send in a fake frame that needs to be cropped as the width/height
1166 // aren't divisible by 4 (see CreateEncoderStreams above).
1167 rtc::Event frame_destroyed_event;
1168 video_source_.IncomingCapturedFrame(CreateFakeNativeFrame(
1169 2, &frame_destroyed_event, codec_width_ + 1, codec_height_ + 1));
1170 ExpectDroppedFrame();
1171 EXPECT_TRUE(frame_destroyed_event.Wait(kDefaultTimeoutMs));
1172 video_stream_encoder_->Stop();
1173}
1174
mflodmancc3d4422017-08-03 08:27:51 -07001175TEST_F(VideoStreamEncoderTest,
1176 ConfigureEncoderTriggersOnEncoderConfigurationChanged) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001177 video_stream_encoder_->OnBitrateUpdated(
1178 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Per21d45d22016-10-30 21:37:57 +01001179 EXPECT_EQ(0, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +02001180
1181 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +02001182 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001183 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +01001184 // The encoder will have been configured once when the first frame is
1185 // received.
1186 EXPECT_EQ(1, sink_.number_of_reconfigurations());
Per512ecb32016-09-23 15:52:06 +02001187
1188 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02001189 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
Per512ecb32016-09-23 15:52:06 +02001190 video_encoder_config.min_transmit_bitrate_bps = 9999;
mflodmancc3d4422017-08-03 08:27:51 -07001191 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001192 kMaxPayloadLength);
Per512ecb32016-09-23 15:52:06 +02001193
1194 // Capture a frame and wait for it to synchronize with the encoder thread.
Perf8c5f2b2016-09-23 16:24:55 +02001195 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001196 WaitForEncodedFrame(2);
Per21d45d22016-10-30 21:37:57 +01001197 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkj3b703ed2016-09-29 23:25:40 -07001198 EXPECT_EQ(9999, sink_.last_min_transmit_bitrate());
perkj26105b42016-09-29 22:39:10 -07001199
mflodmancc3d4422017-08-03 08:27:51 -07001200 video_stream_encoder_->Stop();
perkj26105b42016-09-29 22:39:10 -07001201}
1202
mflodmancc3d4422017-08-03 08:27:51 -07001203TEST_F(VideoStreamEncoderTest, FrameResolutionChangeReconfigureEncoder) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001204 video_stream_encoder_->OnBitrateUpdated(
1205 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkjfa10b552016-10-02 23:45:26 -07001206
1207 // Capture a frame and wait for it to synchronize with the encoder thread.
1208 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001209 WaitForEncodedFrame(1);
Per21d45d22016-10-30 21:37:57 +01001210 // The encoder will have been configured once.
1211 EXPECT_EQ(1, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -07001212 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
1213 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
1214
1215 codec_width_ *= 2;
1216 codec_height_ *= 2;
1217 // Capture a frame with a higher resolution and wait for it to synchronize
1218 // with the encoder thread.
1219 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
sprang4847ae62017-06-27 07:06:52 -07001220 WaitForEncodedFrame(2);
perkjfa10b552016-10-02 23:45:26 -07001221 EXPECT_EQ(codec_width_, fake_encoder_.codec_config().width);
1222 EXPECT_EQ(codec_height_, fake_encoder_.codec_config().height);
Per21d45d22016-10-30 21:37:57 +01001223 EXPECT_EQ(2, sink_.number_of_reconfigurations());
perkjfa10b552016-10-02 23:45:26 -07001224
mflodmancc3d4422017-08-03 08:27:51 -07001225 video_stream_encoder_->Stop();
perkjfa10b552016-10-02 23:45:26 -07001226}
1227
mflodmancc3d4422017-08-03 08:27:51 -07001228TEST_F(VideoStreamEncoderTest, SwitchSourceDeregisterEncoderAsSink) {
perkj803d97f2016-11-01 11:45:46 -07001229 EXPECT_TRUE(video_source_.has_sinks());
1230 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001231 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001232 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001233 EXPECT_FALSE(video_source_.has_sinks());
1234 EXPECT_TRUE(new_video_source.has_sinks());
1235
mflodmancc3d4422017-08-03 08:27:51 -07001236 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001237}
1238
mflodmancc3d4422017-08-03 08:27:51 -07001239TEST_F(VideoStreamEncoderTest, SinkWantsRotationApplied) {
perkj803d97f2016-11-01 11:45:46 -07001240 EXPECT_FALSE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -07001241 video_stream_encoder_->SetSink(&sink_, true /*rotation_applied*/);
perkj803d97f2016-11-01 11:45:46 -07001242 EXPECT_TRUE(video_source_.sink_wants().rotation_applied);
mflodmancc3d4422017-08-03 08:27:51 -07001243 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001244}
1245
Jonathan Yubc771b72017-12-08 17:04:29 -08001246TEST_F(VideoStreamEncoderTest, TestCpuDowngrades_BalancedMode) {
1247 const int kFramerateFps = 30;
asaperssonf7e294d2017-06-13 23:25:22 -07001248 const int kWidth = 1280;
1249 const int kHeight = 720;
Jonathan Yubc771b72017-12-08 17:04:29 -08001250
1251 // We rely on the automatic resolution adaptation, but we handle framerate
1252 // adaptation manually by mocking the stats proxy.
1253 video_source_.set_adaptation_enabled(true);
asaperssonf7e294d2017-06-13 23:25:22 -07001254
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001255 // Enable BALANCED preference, no initial limitation.
Erik Språng4c6ca302019-04-08 15:14:01 +02001256 video_stream_encoder_->OnBitrateUpdated(
1257 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001258 video_stream_encoder_->SetSource(&video_source_,
1259 webrtc::DegradationPreference::BALANCED);
Jonathan Yubc771b72017-12-08 17:04:29 -08001260 VerifyNoLimitation(video_source_.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001261 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001262 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asaperssonf7e294d2017-06-13 23:25:22 -07001263 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1264
Jonathan Yubc771b72017-12-08 17:04:29 -08001265 // Adapt down as far as possible.
1266 rtc::VideoSinkWants last_wants;
1267 int64_t t = 1;
1268 int loop_count = 0;
1269 do {
1270 ++loop_count;
1271 last_wants = video_source_.sink_wants();
1272
1273 // Simulate the framerate we've been asked to adapt to.
1274 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
1275 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
1276 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1277 mock_stats.input_frame_rate = fps;
1278 stats_proxy_->SetMockStats(mock_stats);
1279
1280 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1281 sink_.WaitForEncodedFrame(t);
1282 t += frame_interval_ms;
1283
mflodmancc3d4422017-08-03 08:27:51 -07001284 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08001285 VerifyBalancedModeFpsRange(
1286 video_source_.sink_wants(),
1287 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1288 } while (video_source_.sink_wants().max_pixel_count <
1289 last_wants.max_pixel_count ||
1290 video_source_.sink_wants().max_framerate_fps <
1291 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001292
Jonathan Yubc771b72017-12-08 17:04:29 -08001293 // Verify that we've adapted all the way down.
1294 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001295 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001296 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
1297 EXPECT_EQ(loop_count - 1,
asaperssonf7e294d2017-06-13 23:25:22 -07001298 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
Jonathan Yubc771b72017-12-08 17:04:29 -08001299 EXPECT_EQ(kMinPixelsPerFrame, *video_source_.last_sent_width() *
1300 *video_source_.last_sent_height());
1301 EXPECT_EQ(kMinBalancedFramerateFps,
1302 video_source_.sink_wants().max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001303
Jonathan Yubc771b72017-12-08 17:04:29 -08001304 // Adapt back up the same number of times we adapted down.
1305 for (int i = 0; i < loop_count - 1; ++i) {
1306 last_wants = video_source_.sink_wants();
1307
1308 // Simulate the framerate we've been asked to adapt to.
1309 const int fps = std::min(kFramerateFps, last_wants.max_framerate_fps);
1310 const int frame_interval_ms = rtc::kNumMillisecsPerSec / fps;
1311 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1312 mock_stats.input_frame_rate = fps;
1313 stats_proxy_->SetMockStats(mock_stats);
1314
1315 video_source_.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
1316 sink_.WaitForEncodedFrame(t);
1317 t += frame_interval_ms;
1318
mflodmancc3d4422017-08-03 08:27:51 -07001319 video_stream_encoder_->TriggerCpuNormalUsage();
Jonathan Yubc771b72017-12-08 17:04:29 -08001320 VerifyBalancedModeFpsRange(
1321 video_source_.sink_wants(),
1322 *video_source_.last_sent_width() * *video_source_.last_sent_height());
1323 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count >
1324 last_wants.max_pixel_count ||
1325 video_source_.sink_wants().max_framerate_fps >
1326 last_wants.max_framerate_fps);
asaperssonf7e294d2017-06-13 23:25:22 -07001327 }
1328
Åsa Persson8c1bf952018-09-13 10:42:19 +02001329 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08001330 stats_proxy_->ResetMockStats();
asaperssonf7e294d2017-06-13 23:25:22 -07001331 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08001332 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
1333 EXPECT_EQ((loop_count - 1) * 2,
1334 stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonf7e294d2017-06-13 23:25:22 -07001335
mflodmancc3d4422017-08-03 08:27:51 -07001336 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001337}
mflodmancc3d4422017-08-03 08:27:51 -07001338TEST_F(VideoStreamEncoderTest, SinkWantsStoredByDegradationPreference) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001339 video_stream_encoder_->OnBitrateUpdated(
1340 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001341 VerifyNoLimitation(video_source_.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001342
sprangc5d62e22017-04-02 23:53:04 -07001343 const int kFrameWidth = 1280;
1344 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07001345
Åsa Persson8c1bf952018-09-13 10:42:19 +02001346 int64_t frame_timestamp = 1;
perkj803d97f2016-11-01 11:45:46 -07001347
kthelgason5e13d412016-12-01 03:59:51 -08001348 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001349 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001350 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001351 frame_timestamp += kFrameIntervalMs;
1352
perkj803d97f2016-11-01 11:45:46 -07001353 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001354 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001355 video_source_.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001356 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001357 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001358 frame_timestamp += kFrameIntervalMs;
sprang3ea3c772017-03-30 07:23:48 -07001359
asapersson0944a802017-04-07 00:57:58 -07001360 // Default degradation preference is maintain-framerate, so will lower max
sprangc5d62e22017-04-02 23:53:04 -07001361 // wanted resolution.
1362 EXPECT_FALSE(video_source_.sink_wants().target_pixel_count);
1363 EXPECT_LT(video_source_.sink_wants().max_pixel_count,
1364 kFrameWidth * kFrameHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001365 EXPECT_EQ(kDefaultFramerate, video_source_.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001366
1367 // Set new source, switch to maintain-resolution.
perkj803d97f2016-11-01 11:45:46 -07001368 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001369 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001370 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001371
sprangc5d62e22017-04-02 23:53:04 -07001372 // Initially no degradation registered.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001373 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001374
sprangc5d62e22017-04-02 23:53:04 -07001375 // Force an input frame rate to be available, or the adaptation call won't
1376 // know what framerate to adapt form.
asapersson02465b82017-04-10 01:12:52 -07001377 const int kInputFps = 30;
sprangc5d62e22017-04-02 23:53:04 -07001378 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson02465b82017-04-10 01:12:52 -07001379 stats.input_frame_rate = kInputFps;
sprangc5d62e22017-04-02 23:53:04 -07001380 stats_proxy_->SetMockStats(stats);
1381
mflodmancc3d4422017-08-03 08:27:51 -07001382 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07001383 new_video_source.IncomingCapturedFrame(
sprangc5d62e22017-04-02 23:53:04 -07001384 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001385 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001386 frame_timestamp += kFrameIntervalMs;
1387
1388 // Some framerate constraint should be set.
sprang84a37592017-02-10 07:04:27 -08001389 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
sprangc5d62e22017-04-02 23:53:04 -07001390 EXPECT_EQ(std::numeric_limits<int>::max(),
1391 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001392 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
sprangc5d62e22017-04-02 23:53:04 -07001393
asapersson02465b82017-04-10 01:12:52 -07001394 // Turn off degradation completely.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001395 video_stream_encoder_->SetSource(&new_video_source,
1396 webrtc::DegradationPreference::DISABLED);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001397 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
sprangc5d62e22017-04-02 23:53:04 -07001398
mflodmancc3d4422017-08-03 08:27:51 -07001399 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001400 new_video_source.IncomingCapturedFrame(
1401 CreateFrame(frame_timestamp, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07001402 WaitForEncodedFrame(frame_timestamp);
sprangc5d62e22017-04-02 23:53:04 -07001403 frame_timestamp += kFrameIntervalMs;
1404
1405 // Still no degradation.
Åsa Persson8c1bf952018-09-13 10:42:19 +02001406 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
perkj803d97f2016-11-01 11:45:46 -07001407
1408 // Calling SetSource with resolution scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001409 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001410 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
sprangc5d62e22017-04-02 23:53:04 -07001411 EXPECT_LT(new_video_source.sink_wants().max_pixel_count,
1412 kFrameWidth * kFrameHeight);
sprang84a37592017-02-10 07:04:27 -08001413 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001414 EXPECT_EQ(kDefaultFramerate, new_video_source.sink_wants().max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07001415
1416 // Calling SetSource with framerate scaling enabled apply the old SinkWants.
mflodmancc3d4422017-08-03 08:27:51 -07001417 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001418 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001419 EXPECT_FALSE(new_video_source.sink_wants().target_pixel_count);
1420 EXPECT_EQ(std::numeric_limits<int>::max(),
1421 new_video_source.sink_wants().max_pixel_count);
asapersson02465b82017-04-10 01:12:52 -07001422 EXPECT_LT(new_video_source.sink_wants().max_framerate_fps, kInputFps);
perkj803d97f2016-11-01 11:45:46 -07001423
mflodmancc3d4422017-08-03 08:27:51 -07001424 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001425}
1426
mflodmancc3d4422017-08-03 08:27:51 -07001427TEST_F(VideoStreamEncoderTest, StatsTracksQualityAdaptationStats) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001428 video_stream_encoder_->OnBitrateUpdated(
1429 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001430
asaperssonfab67072017-04-04 05:51:49 -07001431 const int kWidth = 1280;
1432 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001433 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001434 WaitForEncodedFrame(1);
asaperssonfab67072017-04-04 05:51:49 -07001435 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1436 EXPECT_FALSE(stats.bw_limited_resolution);
1437 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
1438
1439 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001440 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001441 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001442 WaitForEncodedFrame(2);
asaperssonfab67072017-04-04 05:51:49 -07001443
1444 stats = stats_proxy_->GetStats();
1445 EXPECT_TRUE(stats.bw_limited_resolution);
1446 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1447
1448 // Trigger adapt up.
mflodmancc3d4422017-08-03 08:27:51 -07001449 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001450 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001451 WaitForEncodedFrame(3);
asaperssonfab67072017-04-04 05:51:49 -07001452
1453 stats = stats_proxy_->GetStats();
1454 EXPECT_FALSE(stats.bw_limited_resolution);
1455 EXPECT_EQ(2, stats.number_of_quality_adapt_changes);
1456 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1457
mflodmancc3d4422017-08-03 08:27:51 -07001458 video_stream_encoder_->Stop();
asaperssonfab67072017-04-04 05:51:49 -07001459}
1460
mflodmancc3d4422017-08-03 08:27:51 -07001461TEST_F(VideoStreamEncoderTest, StatsTracksCpuAdaptationStats) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001462 video_stream_encoder_->OnBitrateUpdated(
1463 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07001464
1465 const int kWidth = 1280;
1466 const int kHeight = 720;
asaperssonfab67072017-04-04 05:51:49 -07001467 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001468 WaitForEncodedFrame(1);
perkj803d97f2016-11-01 11:45:46 -07001469 VideoSendStream::Stats stats = stats_proxy_->GetStats();
1470 EXPECT_FALSE(stats.cpu_limited_resolution);
1471 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1472
1473 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001474 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001475 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001476 WaitForEncodedFrame(2);
perkj803d97f2016-11-01 11:45:46 -07001477
1478 stats = stats_proxy_->GetStats();
1479 EXPECT_TRUE(stats.cpu_limited_resolution);
1480 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1481
1482 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001483 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001484 video_source_.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001485 WaitForEncodedFrame(3);
perkj803d97f2016-11-01 11:45:46 -07001486
1487 stats = stats_proxy_->GetStats();
1488 EXPECT_FALSE(stats.cpu_limited_resolution);
1489 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -07001490 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001491
mflodmancc3d4422017-08-03 08:27:51 -07001492 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001493}
1494
mflodmancc3d4422017-08-03 08:27:51 -07001495TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsCpuAdaptation) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001496 video_stream_encoder_->OnBitrateUpdated(
1497 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001498
asaperssonfab67072017-04-04 05:51:49 -07001499 const int kWidth = 1280;
1500 const int kHeight = 720;
1501 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001502 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001503 VideoSendStream::Stats stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001504 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001505 EXPECT_FALSE(stats.cpu_limited_resolution);
1506 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1507
asaperssonfab67072017-04-04 05:51:49 -07001508 // Trigger CPU overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001509 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001510 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001511 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001512 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001513 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001514 EXPECT_TRUE(stats.cpu_limited_resolution);
1515 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1516
1517 // Set new source with adaptation still enabled.
1518 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001519 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001520 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001521
asaperssonfab67072017-04-04 05:51:49 -07001522 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001523 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001524 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001525 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001526 EXPECT_TRUE(stats.cpu_limited_resolution);
1527 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1528
1529 // Set adaptation disabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001530 video_stream_encoder_->SetSource(&new_video_source,
1531 webrtc::DegradationPreference::DISABLED);
kthelgason876222f2016-11-29 01:44:11 -08001532
asaperssonfab67072017-04-04 05:51:49 -07001533 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001534 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001535 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001536 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001537 EXPECT_FALSE(stats.cpu_limited_resolution);
1538 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1539
1540 // Set adaptation back to enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001541 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001542 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
kthelgason876222f2016-11-29 01:44:11 -08001543
asaperssonfab67072017-04-04 05:51:49 -07001544 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001545 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001546 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001547 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001548 EXPECT_TRUE(stats.cpu_limited_resolution);
1549 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1550
asaperssonfab67072017-04-04 05:51:49 -07001551 // Trigger CPU normal use.
mflodmancc3d4422017-08-03 08:27:51 -07001552 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001553 new_video_source.IncomingCapturedFrame(CreateFrame(6, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001554 WaitForEncodedFrame(6);
kthelgason876222f2016-11-29 01:44:11 -08001555 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001556 EXPECT_FALSE(stats.bw_limited_resolution);
kthelgason876222f2016-11-29 01:44:11 -08001557 EXPECT_FALSE(stats.cpu_limited_resolution);
1558 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001559 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001560
mflodmancc3d4422017-08-03 08:27:51 -07001561 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001562}
1563
mflodmancc3d4422017-08-03 08:27:51 -07001564TEST_F(VideoStreamEncoderTest, SwitchingSourceKeepsQualityAdaptation) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001565 video_stream_encoder_->OnBitrateUpdated(
1566 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001567
asaperssonfab67072017-04-04 05:51:49 -07001568 const int kWidth = 1280;
1569 const int kHeight = 720;
1570 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001571 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001572 VideoSendStream::Stats stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001573 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001574 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001575 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001576
1577 // Set new source with adaptation still enabled.
1578 test::FrameForwarder new_video_source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001579 video_stream_encoder_->SetSource(&new_video_source,
1580 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001581
asaperssonfab67072017-04-04 05:51:49 -07001582 new_video_source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001583 WaitForEncodedFrame(2);
kthelgason876222f2016-11-29 01:44:11 -08001584 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001585 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001586 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001587 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001588
asaperssonfab67072017-04-04 05:51:49 -07001589 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001590 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001591 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001592 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001593 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001594 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001595 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001596 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001597
asaperssonfab67072017-04-04 05:51:49 -07001598 // Set new source with adaptation still enabled.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001599 video_stream_encoder_->SetSource(&new_video_source,
1600 webrtc::DegradationPreference::BALANCED);
kthelgason876222f2016-11-29 01:44:11 -08001601
asaperssonfab67072017-04-04 05:51:49 -07001602 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001603 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001604 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001605 EXPECT_TRUE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001606 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001607 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001608
asapersson02465b82017-04-10 01:12:52 -07001609 // Disable resolution scaling.
mflodmancc3d4422017-08-03 08:27:51 -07001610 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001611 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001612
asaperssonfab67072017-04-04 05:51:49 -07001613 new_video_source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001614 WaitForEncodedFrame(5);
kthelgason876222f2016-11-29 01:44:11 -08001615 stats = stats_proxy_->GetStats();
kthelgason876222f2016-11-29 01:44:11 -08001616 EXPECT_FALSE(stats.bw_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001617 EXPECT_FALSE(stats.bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -07001618 EXPECT_EQ(1, stats.number_of_quality_adapt_changes);
1619 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
kthelgason876222f2016-11-29 01:44:11 -08001620
mflodmancc3d4422017-08-03 08:27:51 -07001621 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001622}
1623
mflodmancc3d4422017-08-03 08:27:51 -07001624TEST_F(VideoStreamEncoderTest,
1625 QualityAdaptationStatsAreResetWhenScalerIsDisabled) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001626 video_stream_encoder_->OnBitrateUpdated(
1627 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson36e9eb42017-03-31 05:29:12 -07001628
1629 const int kWidth = 1280;
1630 const int kHeight = 720;
Åsa Persson8c1bf952018-09-13 10:42:19 +02001631 int64_t timestamp_ms = kFrameIntervalMs;
asapersson36e9eb42017-03-31 05:29:12 -07001632 video_source_.set_adaptation_enabled(true);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001633 video_source_.IncomingCapturedFrame(
1634 CreateFrame(timestamp_ms, kWidth, kHeight));
1635 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001636 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1637 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1638 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1639
1640 // Trigger adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001641 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001642 timestamp_ms += kFrameIntervalMs;
1643 video_source_.IncomingCapturedFrame(
1644 CreateFrame(timestamp_ms, kWidth, kHeight));
1645 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001646 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1647 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1648 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1649
1650 // Trigger overuse.
mflodmancc3d4422017-08-03 08:27:51 -07001651 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001652 timestamp_ms += kFrameIntervalMs;
1653 video_source_.IncomingCapturedFrame(
1654 CreateFrame(timestamp_ms, kWidth, kHeight));
1655 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001656 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1657 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1658 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1659
Niels Möller4db138e2018-04-19 09:04:13 +02001660 // Leave source unchanged, but disable quality scaler.
asapersson36e9eb42017-03-31 05:29:12 -07001661 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02001662
1663 VideoEncoderConfig video_encoder_config;
1664 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
1665 // Make format different, to force recreation of encoder.
1666 video_encoder_config.video_format.parameters["foo"] = "foo";
1667 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02001668 kMaxPayloadLength);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001669 timestamp_ms += kFrameIntervalMs;
1670 video_source_.IncomingCapturedFrame(
1671 CreateFrame(timestamp_ms, kWidth, kHeight));
1672 WaitForEncodedFrame(timestamp_ms);
asapersson36e9eb42017-03-31 05:29:12 -07001673 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1674 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
1675 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1676
mflodmancc3d4422017-08-03 08:27:51 -07001677 video_stream_encoder_->Stop();
asapersson36e9eb42017-03-31 05:29:12 -07001678}
1679
mflodmancc3d4422017-08-03 08:27:51 -07001680TEST_F(VideoStreamEncoderTest,
1681 StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
Erik Språng4c6ca302019-04-08 15:14:01 +02001682 video_stream_encoder_->OnBitrateUpdated(
1683 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
perkj803d97f2016-11-01 11:45:46 -07001684
asapersson0944a802017-04-07 00:57:58 -07001685 const int kWidth = 1280;
1686 const int kHeight = 720;
sprang84a37592017-02-10 07:04:27 -08001687 int sequence = 1;
perkj803d97f2016-11-01 11:45:46 -07001688
asaperssonfab67072017-04-04 05:51:49 -07001689 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001690 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001691 VideoSendStream::Stats stats = stats_proxy_->GetStats();
sprang84a37592017-02-10 07:04:27 -08001692 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001693 EXPECT_FALSE(stats.cpu_limited_framerate);
sprang84a37592017-02-10 07:04:27 -08001694 EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
1695
asapersson02465b82017-04-10 01:12:52 -07001696 // Trigger CPU overuse, should now adapt down.
mflodmancc3d4422017-08-03 08:27:51 -07001697 video_stream_encoder_->TriggerCpuOveruse();
asaperssonfab67072017-04-04 05:51:49 -07001698 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001699 WaitForEncodedFrame(sequence++);
sprang84a37592017-02-10 07:04:27 -08001700 stats = stats_proxy_->GetStats();
perkj803d97f2016-11-01 11:45:46 -07001701 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001702 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001703 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1704
1705 // Set new source with adaptation still enabled.
1706 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001707 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001708 &new_video_source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
perkj803d97f2016-11-01 11:45:46 -07001709
1710 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001711 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001712 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001713 stats = stats_proxy_->GetStats();
1714 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001715 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001716 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1717
sprangc5d62e22017-04-02 23:53:04 -07001718 // Set cpu adaptation by frame dropping.
mflodmancc3d4422017-08-03 08:27:51 -07001719 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001720 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
perkj803d97f2016-11-01 11:45:46 -07001721 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001722 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001723 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001724 stats = stats_proxy_->GetStats();
sprangc5d62e22017-04-02 23:53:04 -07001725 // Not adapted at first.
perkj803d97f2016-11-01 11:45:46 -07001726 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -07001727 EXPECT_FALSE(stats.cpu_limited_framerate);
perkj803d97f2016-11-01 11:45:46 -07001728 EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
1729
sprangc5d62e22017-04-02 23:53:04 -07001730 // Force an input frame rate to be available, or the adaptation call won't
asapersson09f05612017-05-15 23:40:18 -07001731 // know what framerate to adapt from.
sprangc5d62e22017-04-02 23:53:04 -07001732 VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
1733 mock_stats.input_frame_rate = 30;
1734 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001735 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001736 stats_proxy_->ResetMockStats();
1737
1738 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001739 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001740 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001741
1742 // Framerate now adapted.
1743 stats = stats_proxy_->GetStats();
asapersson09f05612017-05-15 23:40:18 -07001744 EXPECT_FALSE(stats.cpu_limited_resolution);
1745 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001746 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1747
1748 // Disable CPU adaptation.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001749 video_stream_encoder_->SetSource(&new_video_source,
1750 webrtc::DegradationPreference::DISABLED);
sprangc5d62e22017-04-02 23:53:04 -07001751 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001752 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001753 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001754
1755 stats = stats_proxy_->GetStats();
1756 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001757 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001758 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1759
1760 // Try to trigger overuse. Should not succeed.
1761 stats_proxy_->SetMockStats(mock_stats);
mflodmancc3d4422017-08-03 08:27:51 -07001762 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07001763 stats_proxy_->ResetMockStats();
1764
1765 stats = stats_proxy_->GetStats();
1766 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001767 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001768 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
1769
1770 // Switch back the source with resolution adaptation enabled.
mflodmancc3d4422017-08-03 08:27:51 -07001771 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001772 &video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssonfab67072017-04-04 05:51:49 -07001773 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001774 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001775 stats = stats_proxy_->GetStats();
1776 EXPECT_TRUE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001777 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001778 EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001779
1780 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001781 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonfab67072017-04-04 05:51:49 -07001782 video_source_.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001783 WaitForEncodedFrame(sequence++);
perkj803d97f2016-11-01 11:45:46 -07001784 stats = stats_proxy_->GetStats();
1785 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001786 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001787 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1788
1789 // Back to the source with adaptation off, set it back to maintain-resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001790 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001791 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07001792 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001793 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001794 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001795 stats = stats_proxy_->GetStats();
asapersson13874762017-06-07 00:01:02 -07001796 // Disabled, since we previously switched the source to disabled.
sprangc5d62e22017-04-02 23:53:04 -07001797 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001798 EXPECT_TRUE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001799 EXPECT_EQ(3, stats.number_of_cpu_adapt_changes);
1800
1801 // Trigger CPU normal usage.
mflodmancc3d4422017-08-03 08:27:51 -07001802 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07001803 new_video_source.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07001804 CreateFrame(sequence, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001805 WaitForEncodedFrame(sequence++);
sprangc5d62e22017-04-02 23:53:04 -07001806 stats = stats_proxy_->GetStats();
1807 EXPECT_FALSE(stats.cpu_limited_resolution);
asapersson13874762017-06-07 00:01:02 -07001808 EXPECT_FALSE(stats.cpu_limited_framerate);
sprangc5d62e22017-04-02 23:53:04 -07001809 EXPECT_EQ(4, stats.number_of_cpu_adapt_changes);
asapersson02465b82017-04-10 01:12:52 -07001810 EXPECT_EQ(0, stats.number_of_quality_adapt_changes);
perkj803d97f2016-11-01 11:45:46 -07001811
mflodmancc3d4422017-08-03 08:27:51 -07001812 video_stream_encoder_->Stop();
perkj803d97f2016-11-01 11:45:46 -07001813}
1814
mflodmancc3d4422017-08-03 08:27:51 -07001815TEST_F(VideoStreamEncoderTest,
1816 ScalingUpAndDownDoesNothingWithMaintainResolution) {
asaperssonfab67072017-04-04 05:51:49 -07001817 const int kWidth = 1280;
1818 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02001819 video_stream_encoder_->OnBitrateUpdated(
1820 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
kthelgason876222f2016-11-29 01:44:11 -08001821
asaperssonfab67072017-04-04 05:51:49 -07001822 // Expect no scaling to begin with.
asapersson02465b82017-04-10 01:12:52 -07001823 VerifyNoLimitation(video_source_.sink_wants());
kthelgason876222f2016-11-29 01:44:11 -08001824
asaperssonfab67072017-04-04 05:51:49 -07001825 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001826 WaitForEncodedFrame(1);
kthelgason876222f2016-11-29 01:44:11 -08001827
asaperssonfab67072017-04-04 05:51:49 -07001828 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001829 video_stream_encoder_->TriggerQualityLow();
kthelgason5e13d412016-12-01 03:59:51 -08001830
asaperssonfab67072017-04-04 05:51:49 -07001831 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001832 WaitForEncodedFrame(2);
kthelgason5e13d412016-12-01 03:59:51 -08001833
kthelgason876222f2016-11-29 01:44:11 -08001834 // Expect a scale down.
1835 EXPECT_TRUE(video_source_.sink_wants().max_pixel_count);
asaperssonfab67072017-04-04 05:51:49 -07001836 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason876222f2016-11-29 01:44:11 -08001837
asapersson02465b82017-04-10 01:12:52 -07001838 // Set resolution scaling disabled.
kthelgason876222f2016-11-29 01:44:11 -08001839 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07001840 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001841 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason876222f2016-11-29 01:44:11 -08001842
asaperssonfab67072017-04-04 05:51:49 -07001843 // Trigger scale down.
mflodmancc3d4422017-08-03 08:27:51 -07001844 video_stream_encoder_->TriggerQualityLow();
asaperssonfab67072017-04-04 05:51:49 -07001845 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001846 WaitForEncodedFrame(3);
kthelgason876222f2016-11-29 01:44:11 -08001847
asaperssonfab67072017-04-04 05:51:49 -07001848 // Expect no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001849 EXPECT_EQ(std::numeric_limits<int>::max(),
1850 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001851
asaperssonfab67072017-04-04 05:51:49 -07001852 // Trigger scale up.
mflodmancc3d4422017-08-03 08:27:51 -07001853 video_stream_encoder_->TriggerQualityHigh();
asaperssonfab67072017-04-04 05:51:49 -07001854 new_video_source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001855 WaitForEncodedFrame(4);
kthelgason876222f2016-11-29 01:44:11 -08001856
asapersson02465b82017-04-10 01:12:52 -07001857 // Expect nothing to change, still no scaling.
sprangc5d62e22017-04-02 23:53:04 -07001858 EXPECT_EQ(std::numeric_limits<int>::max(),
1859 new_video_source.sink_wants().max_pixel_count);
kthelgason876222f2016-11-29 01:44:11 -08001860
mflodmancc3d4422017-08-03 08:27:51 -07001861 video_stream_encoder_->Stop();
kthelgason876222f2016-11-29 01:44:11 -08001862}
1863
mflodmancc3d4422017-08-03 08:27:51 -07001864TEST_F(VideoStreamEncoderTest,
1865 SkipsSameAdaptDownRequest_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001866 const int kWidth = 1280;
1867 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02001868 video_stream_encoder_->OnBitrateUpdated(
1869 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001870
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001871 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001872 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001873 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001874 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001875
1876 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001877 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001878 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001879 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1880 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1881
1882 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001883 video_stream_encoder_->TriggerCpuOveruse();
asapersson09f05612017-05-15 23:40:18 -07001884 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07001885 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1886 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1887 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1888
1889 // Trigger adapt down for same input resolution, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001890 video_stream_encoder_->TriggerCpuOveruse();
asapersson02465b82017-04-10 01:12:52 -07001891 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1892 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
1893 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1894
mflodmancc3d4422017-08-03 08:27:51 -07001895 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001896}
1897
mflodmancc3d4422017-08-03 08:27:51 -07001898TEST_F(VideoStreamEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001899 const int kWidth = 1280;
1900 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02001901 video_stream_encoder_->OnBitrateUpdated(
1902 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001903
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001904 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001905 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001906 video_stream_encoder_->SetSource(&source,
1907 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07001908 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
1909 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001910 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07001911
1912 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07001913 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001914 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
1915 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1916 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1917 const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
1918
1919 // Trigger adapt down for same input resolution, expect no change.
1920 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
1921 sink_.WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07001922 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001923 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1924 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1925 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1926
1927 // Trigger adapt down for larger input resolution, expect no change.
1928 source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
1929 sink_.WaitForEncodedFrame(3);
mflodmancc3d4422017-08-03 08:27:51 -07001930 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07001931 EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
1932 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
1933 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
1934
mflodmancc3d4422017-08-03 08:27:51 -07001935 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07001936}
1937
mflodmancc3d4422017-08-03 08:27:51 -07001938TEST_F(VideoStreamEncoderTest,
1939 NoChangeForInitialNormalUsage_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07001940 const int kWidth = 1280;
1941 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02001942 video_stream_encoder_->OnBitrateUpdated(
1943 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001944
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001945 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001946 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001947 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001948 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07001949
1950 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001951 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001952 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001953 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1954 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1955
1956 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001957 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001958 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07001959 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
1960 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1961
mflodmancc3d4422017-08-03 08:27:51 -07001962 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001963}
1964
mflodmancc3d4422017-08-03 08:27:51 -07001965TEST_F(VideoStreamEncoderTest,
1966 NoChangeForInitialNormalUsage_MaintainResolutionMode) {
asapersson02465b82017-04-10 01:12:52 -07001967 const int kWidth = 1280;
1968 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02001969 video_stream_encoder_->OnBitrateUpdated(
1970 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07001971
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001972 // Enable MAINTAIN_RESOLUTION preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07001973 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07001974 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001975 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
asapersson02465b82017-04-10 01:12:52 -07001976
1977 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07001978 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02001979 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001980 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001981 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1982
1983 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07001984 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02001985 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07001986 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
asapersson02465b82017-04-10 01:12:52 -07001987 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
1988
mflodmancc3d4422017-08-03 08:27:51 -07001989 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07001990}
1991
mflodmancc3d4422017-08-03 08:27:51 -07001992TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07001993 const int kWidth = 1280;
1994 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02001995 video_stream_encoder_->OnBitrateUpdated(
1996 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07001997
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07001998 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07001999 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002000 video_stream_encoder_->SetSource(&source,
2001 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002002
2003 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2004 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002005 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002006 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2007 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2008 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2009
2010 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002011 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002012 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002013 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2014 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2015 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2016
mflodmancc3d4422017-08-03 08:27:51 -07002017 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002018}
2019
mflodmancc3d4422017-08-03 08:27:51 -07002020TEST_F(VideoStreamEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
asapersson09f05612017-05-15 23:40:18 -07002021 const int kWidth = 1280;
2022 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02002023 video_stream_encoder_->OnBitrateUpdated(
2024 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002025
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002026 // Enable DISABLED preference, no initial limitation.
asapersson09f05612017-05-15 23:40:18 -07002027 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002028 video_stream_encoder_->SetSource(&source,
2029 webrtc::DegradationPreference::DISABLED);
asapersson09f05612017-05-15 23:40:18 -07002030
2031 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2032 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002033 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07002034 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2035 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2036 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2037
2038 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07002039 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002040 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07002041 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2042 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
2043 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2044
mflodmancc3d4422017-08-03 08:27:51 -07002045 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07002046}
2047
mflodmancc3d4422017-08-03 08:27:51 -07002048TEST_F(VideoStreamEncoderTest,
2049 AdaptsResolutionForLowQuality_MaintainFramerateMode) {
asapersson02465b82017-04-10 01:12:52 -07002050 const int kWidth = 1280;
2051 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02002052 video_stream_encoder_->OnBitrateUpdated(
2053 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson02465b82017-04-10 01:12:52 -07002054
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002055 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asapersson02465b82017-04-10 01:12:52 -07002056 AdaptingFrameForwarder source;
2057 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002058 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002059 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asapersson02465b82017-04-10 01:12:52 -07002060
2061 source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002062 WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002063 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07002064 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2065 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2066
2067 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002068 video_stream_encoder_->TriggerQualityLow();
asapersson02465b82017-04-10 01:12:52 -07002069 source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002070 WaitForEncodedFrame(2);
asapersson09f05612017-05-15 23:40:18 -07002071 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asapersson02465b82017-04-10 01:12:52 -07002072 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2073 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2074
2075 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002076 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002077 VerifyFpsMaxResolutionMax(source.sink_wants());
asapersson02465b82017-04-10 01:12:52 -07002078 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2079 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2080 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2081
mflodmancc3d4422017-08-03 08:27:51 -07002082 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002083}
2084
mflodmancc3d4422017-08-03 08:27:51 -07002085TEST_F(VideoStreamEncoderTest,
2086 AdaptsFramerateForLowQuality_MaintainResolutionMode) {
asapersson09f05612017-05-15 23:40:18 -07002087 const int kWidth = 1280;
2088 const int kHeight = 720;
2089 const int kInputFps = 30;
Erik Språng4c6ca302019-04-08 15:14:01 +02002090 video_stream_encoder_->OnBitrateUpdated(
2091 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002092
2093 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2094 stats.input_frame_rate = kInputFps;
2095 stats_proxy_->SetMockStats(stats);
2096
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002097 // Expect no scaling to begin with (preference: MAINTAIN_FRAMERATE).
asapersson09f05612017-05-15 23:40:18 -07002098 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2099 sink_.WaitForEncodedFrame(1);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002100 VerifyFpsMaxResolutionMax(video_source_.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07002101
2102 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002103 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07002104 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
2105 sink_.WaitForEncodedFrame(2);
2106 VerifyFpsMaxResolutionLt(video_source_.sink_wants(), kWidth * kHeight);
2107
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002108 // Enable MAINTAIN_RESOLUTION preference.
asapersson09f05612017-05-15 23:40:18 -07002109 test::FrameForwarder new_video_source;
mflodmancc3d4422017-08-03 08:27:51 -07002110 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002111 &new_video_source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002112 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07002113
2114 // Trigger adapt down, expect reduced framerate.
mflodmancc3d4422017-08-03 08:27:51 -07002115 video_stream_encoder_->TriggerQualityLow();
asapersson09f05612017-05-15 23:40:18 -07002116 new_video_source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
2117 sink_.WaitForEncodedFrame(3);
2118 VerifyFpsLtResolutionMax(new_video_source.sink_wants(), kInputFps);
2119
2120 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002121 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002122 VerifyFpsMaxResolutionMax(new_video_source.sink_wants());
asapersson09f05612017-05-15 23:40:18 -07002123
mflodmancc3d4422017-08-03 08:27:51 -07002124 video_stream_encoder_->Stop();
asapersson09f05612017-05-15 23:40:18 -07002125}
2126
mflodmancc3d4422017-08-03 08:27:51 -07002127TEST_F(VideoStreamEncoderTest, DoesNotScaleBelowSetResolutionLimit) {
asaperssond0de2952017-04-21 01:47:31 -07002128 const int kWidth = 1280;
2129 const int kHeight = 720;
2130 const size_t kNumFrames = 10;
2131
Erik Språng4c6ca302019-04-08 15:14:01 +02002132 video_stream_encoder_->OnBitrateUpdated(
2133 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
kthelgason5e13d412016-12-01 03:59:51 -08002134
asaperssond0de2952017-04-21 01:47:31 -07002135 // Enable adapter, expected input resolutions when downscaling:
asapersson142fcc92017-08-17 08:58:54 -07002136 // 1280x720 -> 960x540 -> 640x360 -> 480x270 -> 320x180 (kMinPixelsPerFrame)
asaperssond0de2952017-04-21 01:47:31 -07002137 video_source_.set_adaptation_enabled(true);
2138
2139 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2140 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2141
2142 int downscales = 0;
2143 for (size_t i = 1; i <= kNumFrames; i++) {
Åsa Persson8c1bf952018-09-13 10:42:19 +02002144 video_source_.IncomingCapturedFrame(
2145 CreateFrame(i * kFrameIntervalMs, kWidth, kHeight));
2146 WaitForEncodedFrame(i * kFrameIntervalMs);
asaperssond0de2952017-04-21 01:47:31 -07002147
asaperssonfab67072017-04-04 05:51:49 -07002148 // Trigger scale down.
asaperssond0de2952017-04-21 01:47:31 -07002149 rtc::VideoSinkWants last_wants = video_source_.sink_wants();
mflodmancc3d4422017-08-03 08:27:51 -07002150 video_stream_encoder_->TriggerQualityLow();
sprangc5d62e22017-04-02 23:53:04 -07002151 EXPECT_GE(video_source_.sink_wants().max_pixel_count, kMinPixelsPerFrame);
asaperssond0de2952017-04-21 01:47:31 -07002152
2153 if (video_source_.sink_wants().max_pixel_count < last_wants.max_pixel_count)
2154 ++downscales;
2155
2156 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2157 EXPECT_EQ(downscales,
2158 stats_proxy_->GetStats().number_of_quality_adapt_changes);
2159 EXPECT_GT(downscales, 0);
kthelgason5e13d412016-12-01 03:59:51 -08002160 }
mflodmancc3d4422017-08-03 08:27:51 -07002161 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002162}
2163
mflodmancc3d4422017-08-03 08:27:51 -07002164TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002165 AdaptsResolutionUpAndDownTwiceOnOveruse_MaintainFramerateMode) {
2166 const int kWidth = 1280;
2167 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02002168 video_stream_encoder_->OnBitrateUpdated(
2169 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002170
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002171 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002172 AdaptingFrameForwarder source;
2173 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002174 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002175 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002176
Åsa Persson8c1bf952018-09-13 10:42:19 +02002177 int64_t timestamp_ms = kFrameIntervalMs;
2178 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002179 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002180 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002181 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2182 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2183
2184 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002185 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002186 timestamp_ms += kFrameIntervalMs;
2187 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2188 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002189 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002190 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2191 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2192
2193 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002194 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002195 timestamp_ms += kFrameIntervalMs;
2196 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002197 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002198 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002199 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2200 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2201
2202 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002203 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002204 timestamp_ms += kFrameIntervalMs;
2205 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2206 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002207 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002208 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2209 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2210
2211 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002212 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002213 timestamp_ms += kFrameIntervalMs;
2214 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asapersson09f05612017-05-15 23:40:18 -07002215 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002216 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002217 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2218 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2219
mflodmancc3d4422017-08-03 08:27:51 -07002220 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002221}
2222
mflodmancc3d4422017-08-03 08:27:51 -07002223TEST_F(VideoStreamEncoderTest,
asaperssonf7e294d2017-06-13 23:25:22 -07002224 AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
2225 const int kWidth = 1280;
2226 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02002227 video_stream_encoder_->OnBitrateUpdated(
2228 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002229
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002230 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002231 AdaptingFrameForwarder source;
2232 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002233 video_stream_encoder_->SetSource(&source,
2234 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002235
Åsa Persson8c1bf952018-09-13 10:42:19 +02002236 int64_t timestamp_ms = kFrameIntervalMs;
2237 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07002238 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002239 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002240 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2241 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2242
2243 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002244 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002245 timestamp_ms += kFrameIntervalMs;
2246 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2247 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002248 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2249 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2250 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2251
2252 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002253 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002254 timestamp_ms += kFrameIntervalMs;
2255 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07002256 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002257 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002258 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2259 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2260
2261 // Trigger adapt down, expect scaled down resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002262 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002263 timestamp_ms += kFrameIntervalMs;
2264 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2265 sink_.WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07002266 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
2267 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2268 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2269
2270 // Trigger adapt up, expect no restriction.
mflodmancc3d4422017-08-03 08:27:51 -07002271 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002272 timestamp_ms += kFrameIntervalMs;
2273 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
asaperssonf7e294d2017-06-13 23:25:22 -07002274 sink_.WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002275 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07002276 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2277 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2278
mflodmancc3d4422017-08-03 08:27:51 -07002279 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002280}
2281
mflodmancc3d4422017-08-03 08:27:51 -07002282TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002283 AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
2284 const int kWidth = 1280;
2285 const int kHeight = 720;
Erik Språng4c6ca302019-04-08 15:14:01 +02002286 video_stream_encoder_->OnBitrateUpdated(
2287 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002288
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002289 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002290 AdaptingFrameForwarder source;
2291 source.set_adaptation_enabled(true);
mflodmancc3d4422017-08-03 08:27:51 -07002292 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002293 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002294
Åsa Persson8c1bf952018-09-13 10:42:19 +02002295 int64_t timestamp_ms = kFrameIntervalMs;
2296 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002297 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02002298 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002299 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2300 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2301 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2302 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2303
2304 // Trigger cpu adapt down, expect scaled down resolution (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002305 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002306 timestamp_ms += kFrameIntervalMs;
2307 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2308 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002309 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
asaperssond0de2952017-04-21 01:47:31 -07002310 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2311 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2312 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2313 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2314
2315 // Trigger cpu adapt down, expect scaled down resolution (640x360).
mflodmancc3d4422017-08-03 08:27:51 -07002316 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002317 timestamp_ms += kFrameIntervalMs;
2318 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2319 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002320 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002321 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2322 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2323 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2324 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2325
Jonathan Yubc771b72017-12-08 17:04:29 -08002326 // Trigger cpu adapt down, expect scaled down resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002327 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002328 timestamp_ms += kFrameIntervalMs;
2329 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2330 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002331 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002332 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2333 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002334 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002335 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2336
Jonathan Yubc771b72017-12-08 17:04:29 -08002337 // Trigger quality adapt down, expect scaled down resolution (320x180).
mflodmancc3d4422017-08-03 08:27:51 -07002338 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002339 timestamp_ms += kFrameIntervalMs;
2340 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2341 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002342 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002343 rtc::VideoSinkWants last_wants = source.sink_wants();
asaperssond0de2952017-04-21 01:47:31 -07002344 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2345 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2346 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2347 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2348
Jonathan Yubc771b72017-12-08 17:04:29 -08002349 // Trigger quality adapt down, expect no change (min resolution reached).
2350 video_stream_encoder_->TriggerQualityLow();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002351 timestamp_ms += kFrameIntervalMs;
2352 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2353 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002354 VerifyFpsMaxResolutionEq(source.sink_wants(), last_wants);
2355 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2356 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2357 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2358 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2359
2360 // Trigger cpu adapt up, expect upscaled resolution (480x270).
mflodmancc3d4422017-08-03 08:27:51 -07002361 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002362 timestamp_ms += kFrameIntervalMs;
2363 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2364 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002365 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Jonathan Yubc771b72017-12-08 17:04:29 -08002366 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2367 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2368 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2369 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2370
2371 // Trigger cpu adapt up, expect upscaled resolution (640x360).
2372 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002373 timestamp_ms += kFrameIntervalMs;
2374 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2375 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002376 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
2377 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
2378 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
2379 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2380 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2381
2382 // Trigger cpu adapt up, expect upscaled resolution (960x540).
2383 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002384 timestamp_ms += kFrameIntervalMs;
2385 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2386 WaitForEncodedFrame(timestamp_ms);
Jonathan Yubc771b72017-12-08 17:04:29 -08002387 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
asaperssond0de2952017-04-21 01:47:31 -07002388 last_wants = source.sink_wants();
2389 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2390 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002391 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002392 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2393
2394 // Trigger cpu adapt up, no cpu downgrades, expect no change (960x540).
mflodmancc3d4422017-08-03 08:27:51 -07002395 video_stream_encoder_->TriggerCpuNormalUsage();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002396 timestamp_ms += kFrameIntervalMs;
2397 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
2398 WaitForEncodedFrame(timestamp_ms);
asapersson09f05612017-05-15 23:40:18 -07002399 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
asaperssond0de2952017-04-21 01:47:31 -07002400 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2401 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002402 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002403 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2404
2405 // Trigger quality adapt up, expect no restriction (1280x720).
mflodmancc3d4422017-08-03 08:27:51 -07002406 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002407 timestamp_ms += kFrameIntervalMs;
2408 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002409 WaitForEncodedFrame(kWidth, kHeight);
asapersson09f05612017-05-15 23:40:18 -07002410 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02002411 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002412 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2413 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
Jonathan Yubc771b72017-12-08 17:04:29 -08002414 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssond0de2952017-04-21 01:47:31 -07002415 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
kthelgason5e13d412016-12-01 03:59:51 -08002416
mflodmancc3d4422017-08-03 08:27:51 -07002417 video_stream_encoder_->Stop();
kthelgason5e13d412016-12-01 03:59:51 -08002418}
2419
mflodmancc3d4422017-08-03 08:27:51 -07002420TEST_F(VideoStreamEncoderTest, CpuLimitedHistogramIsReported) {
asaperssonfab67072017-04-04 05:51:49 -07002421 const int kWidth = 640;
2422 const int kHeight = 360;
perkj803d97f2016-11-01 11:45:46 -07002423
Erik Språng4c6ca302019-04-08 15:14:01 +02002424 video_stream_encoder_->OnBitrateUpdated(
2425 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
sprang4847ae62017-06-27 07:06:52 -07002426
perkj803d97f2016-11-01 11:45:46 -07002427 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002428 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002429 WaitForEncodedFrame(i);
perkj803d97f2016-11-01 11:45:46 -07002430 }
2431
mflodmancc3d4422017-08-03 08:27:51 -07002432 video_stream_encoder_->TriggerCpuOveruse();
perkj803d97f2016-11-01 11:45:46 -07002433 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002434 video_source_.IncomingCapturedFrame(CreateFrame(
2435 SendStatisticsProxy::kMinRequiredMetricsSamples + i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002436 WaitForEncodedFrame(SendStatisticsProxy::kMinRequiredMetricsSamples + i);
perkj803d97f2016-11-01 11:45:46 -07002437 }
2438
mflodmancc3d4422017-08-03 08:27:51 -07002439 video_stream_encoder_->Stop();
2440 video_stream_encoder_.reset();
perkj803d97f2016-11-01 11:45:46 -07002441 stats_proxy_.reset();
sprangf8ee65e2017-02-28 08:49:33 -08002442
perkj803d97f2016-11-01 11:45:46 -07002443 EXPECT_EQ(1,
2444 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2445 EXPECT_EQ(
2446 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
2447}
2448
mflodmancc3d4422017-08-03 08:27:51 -07002449TEST_F(VideoStreamEncoderTest,
2450 CpuLimitedHistogramIsNotReportedForDisabledDegradation) {
Erik Språng4c6ca302019-04-08 15:14:01 +02002451 video_stream_encoder_->OnBitrateUpdated(
2452 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf4e44af2017-04-19 02:01:06 -07002453 const int kWidth = 640;
2454 const int kHeight = 360;
2455
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002456 video_stream_encoder_->SetSource(&video_source_,
2457 webrtc::DegradationPreference::DISABLED);
asaperssonf4e44af2017-04-19 02:01:06 -07002458
2459 for (int i = 1; i <= SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
2460 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002461 WaitForEncodedFrame(i);
asaperssonf4e44af2017-04-19 02:01:06 -07002462 }
2463
mflodmancc3d4422017-08-03 08:27:51 -07002464 video_stream_encoder_->Stop();
2465 video_stream_encoder_.reset();
asaperssonf4e44af2017-04-19 02:01:06 -07002466 stats_proxy_.reset();
2467
2468 EXPECT_EQ(0,
2469 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
2470}
2471
mflodmancc3d4422017-08-03 08:27:51 -07002472TEST_F(VideoStreamEncoderTest, CallsBitrateObserver) {
sprang4847ae62017-06-27 07:06:52 -07002473 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02002474 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
sprang57c2fff2017-01-16 06:24:02 -08002475
2476 const int kDefaultFps = 30;
Erik Språng566124a2018-04-23 12:32:22 +02002477 const VideoBitrateAllocation expected_bitrate =
sprang57c2fff2017-01-16 06:24:02 -08002478 DefaultVideoBitrateAllocator(fake_encoder_.codec_config())
kthelgason2bc68642017-02-07 07:02:22 -08002479 .GetAllocation(kLowTargetBitrateBps, kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002480
sprang57c2fff2017-01-16 06:24:02 -08002481 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
Niels Möller6bb5ab92019-01-11 11:11:10 +01002482 .Times(1);
Erik Språng610c7632019-03-06 15:37:33 +01002483 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kLowTargetBitrateBps),
Erik Språng4c6ca302019-04-08 15:14:01 +02002484 DataRate::bps(kLowTargetBitrateBps),
2485 0, 0);
sprang57c2fff2017-01-16 06:24:02 -08002486
sprang57c2fff2017-01-16 06:24:02 -08002487 video_source_.IncomingCapturedFrame(
Erik Språngd7329ca2019-02-21 21:19:53 +01002488 CreateFrame(rtc::TimeMillis(), codec_width_, codec_height_));
2489 WaitForEncodedFrame(rtc::TimeMillis());
2490 absl::optional<VideoBitrateAllocation> bitrate_allocation =
2491 fake_encoder_.GetAndResetLastBitrateAllocation();
2492 // Check that encoder has been updated too, not just allocation observer.
2493 EXPECT_EQ(bitrate_allocation->get_sum_bps(), kLowTargetBitrateBps);
Sebastian Jansson40889f32019-04-17 12:11:20 +02002494 // TODO(srte): The use of millisecs here looks like an error, but the tests
2495 // fails using seconds, this should be investigated.
2496 fake_clock_.AdvanceTime(TimeDelta::ms(1) / kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002497
2498 // Not called on second frame.
2499 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2500 .Times(0);
2501 video_source_.IncomingCapturedFrame(
Erik Språngd7329ca2019-02-21 21:19:53 +01002502 CreateFrame(rtc::TimeMillis(), codec_width_, codec_height_));
2503 WaitForEncodedFrame(rtc::TimeMillis());
Sebastian Jansson40889f32019-04-17 12:11:20 +02002504 fake_clock_.AdvanceTime(TimeDelta::ms(1) / kDefaultFps);
sprang57c2fff2017-01-16 06:24:02 -08002505
2506 // Called after a process interval.
2507 const int64_t kProcessIntervalMs =
2508 vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
sprang57c2fff2017-01-16 06:24:02 -08002509 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(expected_bitrate))
2510 .Times(1);
Erik Språngd7329ca2019-02-21 21:19:53 +01002511 const int64_t start_time_ms = rtc::TimeMillis();
2512 while (rtc::TimeMillis() - start_time_ms < kProcessIntervalMs) {
2513 video_source_.IncomingCapturedFrame(
2514 CreateFrame(rtc::TimeMillis(), codec_width_, codec_height_));
2515 WaitForEncodedFrame(rtc::TimeMillis());
Sebastian Jansson40889f32019-04-17 12:11:20 +02002516 fake_clock_.AdvanceTime(TimeDelta::ms(1) / kDefaultFps);
Erik Språngd7329ca2019-02-21 21:19:53 +01002517 }
2518
2519 // Since rates are unchanged, encoder should not be reconfigured.
2520 EXPECT_FALSE(fake_encoder_.GetAndResetLastBitrateAllocation().has_value());
sprang57c2fff2017-01-16 06:24:02 -08002521
mflodmancc3d4422017-08-03 08:27:51 -07002522 video_stream_encoder_->Stop();
sprang57c2fff2017-01-16 06:24:02 -08002523}
2524
Åsa Perssonc29cb2c2019-03-25 12:06:59 +01002525TEST_F(VideoStreamEncoderTest, TemporalLayersNotDisabledIfSupported) {
2526 // 2 TLs configured, temporal layers supported by encoder.
2527 const int kNumTemporalLayers = 2;
2528 ResetEncoder("VP8", 1, kNumTemporalLayers, 1, /*screenshare*/ false);
2529 fake_encoder_.SetTemporalLayersSupported(0, true);
2530
2531 // Bitrate allocated across temporal layers.
2532 const int kTl0Bps = kTargetBitrateBps *
2533 webrtc::SimulcastRateAllocator::GetTemporalRateAllocation(
2534 kNumTemporalLayers, /*temporal_id*/ 0);
2535 const int kTl1Bps = kTargetBitrateBps *
2536 webrtc::SimulcastRateAllocator::GetTemporalRateAllocation(
2537 kNumTemporalLayers, /*temporal_id*/ 1);
2538 VideoBitrateAllocation expected_bitrate;
2539 expected_bitrate.SetBitrate(/*si*/ 0, /*ti*/ 0, kTl0Bps);
2540 expected_bitrate.SetBitrate(/*si*/ 0, /*ti*/ 1, kTl1Bps - kTl0Bps);
2541
2542 VerifyAllocatedBitrate(expected_bitrate);
2543 video_stream_encoder_->Stop();
2544}
2545
2546TEST_F(VideoStreamEncoderTest, TemporalLayersDisabledIfNotSupported) {
2547 // 2 TLs configured, temporal layers not supported by encoder.
2548 ResetEncoder("VP8", 1, /*num_temporal_layers*/ 2, 1, /*screenshare*/ false);
2549 fake_encoder_.SetTemporalLayersSupported(0, false);
2550
2551 // Temporal layers not supported by the encoder.
2552 // Total bitrate should be at ti:0.
2553 VideoBitrateAllocation expected_bitrate;
2554 expected_bitrate.SetBitrate(/*si*/ 0, /*ti*/ 0, kTargetBitrateBps);
2555
2556 VerifyAllocatedBitrate(expected_bitrate);
2557 video_stream_encoder_->Stop();
2558}
2559
2560TEST_F(VideoStreamEncoderTest, VerifyBitrateAllocationForTwoStreams) {
2561 // 2 TLs configured, temporal layers only supported for first stream.
2562 ResetEncoder("VP8", 2, /*num_temporal_layers*/ 2, 1, /*screenshare*/ false);
2563 fake_encoder_.SetTemporalLayersSupported(0, true);
2564 fake_encoder_.SetTemporalLayersSupported(1, false);
2565
2566 const int kS0Bps = 150000;
2567 const int kS0Tl0Bps =
2568 kS0Bps * webrtc::SimulcastRateAllocator::GetTemporalRateAllocation(
2569 /*num_layers*/ 2, /*temporal_id*/ 0);
2570 const int kS0Tl1Bps =
2571 kS0Bps * webrtc::SimulcastRateAllocator::GetTemporalRateAllocation(
2572 /*num_layers*/ 2, /*temporal_id*/ 1);
2573 const int kS1Bps = kTargetBitrateBps - kS0Tl1Bps;
2574 // Temporal layers not supported by si:1.
2575 VideoBitrateAllocation expected_bitrate;
2576 expected_bitrate.SetBitrate(/*si*/ 0, /*ti*/ 0, kS0Tl0Bps);
2577 expected_bitrate.SetBitrate(/*si*/ 0, /*ti*/ 1, kS0Tl1Bps - kS0Tl0Bps);
2578 expected_bitrate.SetBitrate(/*si*/ 1, /*ti*/ 0, kS1Bps);
2579
2580 VerifyAllocatedBitrate(expected_bitrate);
2581 video_stream_encoder_->Stop();
2582}
2583
Niels Möller7dc26b72017-12-06 10:27:48 +01002584TEST_F(VideoStreamEncoderTest, OveruseDetectorUpdatedOnReconfigureAndAdaption) {
2585 const int kFrameWidth = 1280;
2586 const int kFrameHeight = 720;
2587 const int kFramerate = 24;
2588
Erik Språng4c6ca302019-04-08 15:14:01 +02002589 video_stream_encoder_->OnBitrateUpdated(
2590 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möller7dc26b72017-12-06 10:27:48 +01002591 test::FrameForwarder source;
2592 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002593 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002594
2595 // Insert a single frame, triggering initial configuration.
2596 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2597 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2598
2599 EXPECT_EQ(
2600 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2601 kDefaultFramerate);
2602
2603 // Trigger reconfigure encoder (without resetting the entire instance).
2604 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002605 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002606 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2607 video_encoder_config.number_of_streams = 1;
2608 video_encoder_config.video_stream_factory =
2609 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2610 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002611 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002612 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2613
2614 // Detector should be updated with fps limit from codec config.
2615 EXPECT_EQ(
2616 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2617 kFramerate);
2618
2619 // Trigger overuse, max framerate should be reduced.
2620 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2621 stats.input_frame_rate = kFramerate;
2622 stats_proxy_->SetMockStats(stats);
2623 video_stream_encoder_->TriggerCpuOveruse();
2624 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2625 int adapted_framerate =
2626 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2627 EXPECT_LT(adapted_framerate, kFramerate);
2628
2629 // Trigger underuse, max framerate should go back to codec configured fps.
2630 // Set extra low fps, to make sure it's actually reset, not just incremented.
2631 stats = stats_proxy_->GetStats();
2632 stats.input_frame_rate = adapted_framerate / 2;
2633 stats_proxy_->SetMockStats(stats);
2634 video_stream_encoder_->TriggerCpuNormalUsage();
2635 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2636 EXPECT_EQ(
2637 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2638 kFramerate);
2639
2640 video_stream_encoder_->Stop();
2641}
2642
2643TEST_F(VideoStreamEncoderTest,
2644 OveruseDetectorUpdatedRespectsFramerateAfterUnderuse) {
2645 const int kFrameWidth = 1280;
2646 const int kFrameHeight = 720;
2647 const int kLowFramerate = 15;
2648 const int kHighFramerate = 25;
2649
Erik Språng4c6ca302019-04-08 15:14:01 +02002650 video_stream_encoder_->OnBitrateUpdated(
2651 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möller7dc26b72017-12-06 10:27:48 +01002652 test::FrameForwarder source;
2653 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002654 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
Niels Möller7dc26b72017-12-06 10:27:48 +01002655
2656 // Trigger initial configuration.
2657 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002658 video_encoder_config.codec_type = kVideoCodecVP8;
Niels Möller7dc26b72017-12-06 10:27:48 +01002659 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2660 video_encoder_config.number_of_streams = 1;
2661 video_encoder_config.video_stream_factory =
2662 new rtc::RefCountedObject<VideoStreamFactory>(1, kLowFramerate);
2663 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2664 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002665 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002666 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2667
2668 EXPECT_EQ(
2669 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2670 kLowFramerate);
2671
2672 // Trigger overuse, max framerate should be reduced.
2673 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2674 stats.input_frame_rate = kLowFramerate;
2675 stats_proxy_->SetMockStats(stats);
2676 video_stream_encoder_->TriggerCpuOveruse();
2677 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2678 int adapted_framerate =
2679 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
2680 EXPECT_LT(adapted_framerate, kLowFramerate);
2681
2682 // Reconfigure the encoder with a new (higher max framerate), max fps should
2683 // still respect the adaptation.
2684 video_encoder_config.video_stream_factory =
2685 new rtc::RefCountedObject<VideoStreamFactory>(1, kHighFramerate);
2686 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
2687 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002688 kMaxPayloadLength);
Niels Möller7dc26b72017-12-06 10:27:48 +01002689 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2690
2691 EXPECT_EQ(
2692 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2693 adapted_framerate);
2694
2695 // Trigger underuse, max framerate should go back to codec configured fps.
2696 stats = stats_proxy_->GetStats();
2697 stats.input_frame_rate = adapted_framerate;
2698 stats_proxy_->SetMockStats(stats);
2699 video_stream_encoder_->TriggerCpuNormalUsage();
2700 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
2701 EXPECT_EQ(
2702 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2703 kHighFramerate);
2704
2705 video_stream_encoder_->Stop();
2706}
2707
mflodmancc3d4422017-08-03 08:27:51 -07002708TEST_F(VideoStreamEncoderTest,
2709 OveruseDetectorUpdatedOnDegradationPreferenceChange) {
sprangfda496a2017-06-15 04:21:07 -07002710 const int kFrameWidth = 1280;
2711 const int kFrameHeight = 720;
2712 const int kFramerate = 24;
2713
Erik Språng4c6ca302019-04-08 15:14:01 +02002714 video_stream_encoder_->OnBitrateUpdated(
2715 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
sprangfda496a2017-06-15 04:21:07 -07002716 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002717 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002718 &source, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangfda496a2017-06-15 04:21:07 -07002719
2720 // Trigger initial configuration.
2721 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02002722 video_encoder_config.codec_type = kVideoCodecVP8;
sprangfda496a2017-06-15 04:21:07 -07002723 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
2724 video_encoder_config.number_of_streams = 1;
2725 video_encoder_config.video_stream_factory =
2726 new rtc::RefCountedObject<VideoStreamFactory>(1, kFramerate);
2727 source.IncomingCapturedFrame(CreateFrame(1, kFrameWidth, kFrameHeight));
mflodmancc3d4422017-08-03 08:27:51 -07002728 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002729 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07002730 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprangfda496a2017-06-15 04:21:07 -07002731
Niels Möller7dc26b72017-12-06 10:27:48 +01002732 EXPECT_EQ(
2733 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2734 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002735
2736 // Trigger overuse, max framerate should be reduced.
2737 VideoSendStream::Stats stats = stats_proxy_->GetStats();
2738 stats.input_frame_rate = kFramerate;
2739 stats_proxy_->SetMockStats(stats);
mflodmancc3d4422017-08-03 08:27:51 -07002740 video_stream_encoder_->TriggerCpuOveruse();
2741 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002742 int adapted_framerate =
2743 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate();
sprangfda496a2017-06-15 04:21:07 -07002744 EXPECT_LT(adapted_framerate, kFramerate);
2745
2746 // Change degradation preference to not enable framerate scaling. Target
2747 // framerate should be changed to codec defined limit.
mflodmancc3d4422017-08-03 08:27:51 -07002748 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002749 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
mflodmancc3d4422017-08-03 08:27:51 -07002750 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
Niels Möller7dc26b72017-12-06 10:27:48 +01002751 EXPECT_EQ(
2752 video_stream_encoder_->overuse_detector_proxy_->GetLastTargetFramerate(),
2753 kFramerate);
sprangfda496a2017-06-15 04:21:07 -07002754
mflodmancc3d4422017-08-03 08:27:51 -07002755 video_stream_encoder_->Stop();
sprangfda496a2017-06-15 04:21:07 -07002756}
2757
mflodmancc3d4422017-08-03 08:27:51 -07002758TEST_F(VideoStreamEncoderTest, DropsFramesAndScalesWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002759 const int kTooLowBitrateForFrameSizeBps = 10000;
Erik Språng610c7632019-03-06 15:37:33 +01002760 video_stream_encoder_->OnBitrateUpdated(
Erik Språng4c6ca302019-04-08 15:14:01 +02002761 DataRate::bps(kTooLowBitrateForFrameSizeBps),
2762 DataRate::bps(kTooLowBitrateForFrameSizeBps), 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002763 const int kWidth = 640;
2764 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002765
asaperssonfab67072017-04-04 05:51:49 -07002766 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002767
2768 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002769 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002770
2771 // Expect the sink_wants to specify a scaled frame.
asapersson0944a802017-04-07 00:57:58 -07002772 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002773
sprangc5d62e22017-04-02 23:53:04 -07002774 int last_pixel_count = video_source_.sink_wants().max_pixel_count;
kthelgason2bc68642017-02-07 07:02:22 -08002775
asaperssonfab67072017-04-04 05:51:49 -07002776 // Next frame is scaled.
kthelgason2bc68642017-02-07 07:02:22 -08002777 video_source_.IncomingCapturedFrame(
asaperssonfab67072017-04-04 05:51:49 -07002778 CreateFrame(2, kWidth * 3 / 4, kHeight * 3 / 4));
kthelgason2bc68642017-02-07 07:02:22 -08002779
2780 // Expect to drop this frame, the wait should time out.
sprang4847ae62017-06-27 07:06:52 -07002781 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002782
sprangc5d62e22017-04-02 23:53:04 -07002783 EXPECT_LT(video_source_.sink_wants().max_pixel_count, last_pixel_count);
kthelgason2bc68642017-02-07 07:02:22 -08002784
mflodmancc3d4422017-08-03 08:27:51 -07002785 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002786}
2787
mflodmancc3d4422017-08-03 08:27:51 -07002788TEST_F(VideoStreamEncoderTest,
2789 NumberOfDroppedFramesLimitedWhenBitrateIsTooLow) {
asaperssonfab67072017-04-04 05:51:49 -07002790 const int kTooLowBitrateForFrameSizeBps = 10000;
Erik Språng610c7632019-03-06 15:37:33 +01002791 video_stream_encoder_->OnBitrateUpdated(
Erik Språng4c6ca302019-04-08 15:14:01 +02002792 DataRate::bps(kTooLowBitrateForFrameSizeBps),
2793 DataRate::bps(kTooLowBitrateForFrameSizeBps), 0, 0);
asaperssonfab67072017-04-04 05:51:49 -07002794 const int kWidth = 640;
2795 const int kHeight = 360;
kthelgason2bc68642017-02-07 07:02:22 -08002796
2797 // We expect the n initial frames to get dropped.
2798 int i;
2799 for (i = 1; i <= kMaxInitialFramedrop; ++i) {
asaperssonfab67072017-04-04 05:51:49 -07002800 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002801 ExpectDroppedFrame();
kthelgason2bc68642017-02-07 07:02:22 -08002802 }
2803 // The n+1th frame should not be dropped, even though it's size is too large.
asaperssonfab67072017-04-04 05:51:49 -07002804 video_source_.IncomingCapturedFrame(CreateFrame(i, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07002805 WaitForEncodedFrame(i);
kthelgason2bc68642017-02-07 07:02:22 -08002806
2807 // Expect the sink_wants to specify a scaled frame.
asaperssonfab67072017-04-04 05:51:49 -07002808 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
kthelgason2bc68642017-02-07 07:02:22 -08002809
mflodmancc3d4422017-08-03 08:27:51 -07002810 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002811}
2812
mflodmancc3d4422017-08-03 08:27:51 -07002813TEST_F(VideoStreamEncoderTest,
2814 InitialFrameDropOffWithMaintainResolutionPreference) {
asaperssonfab67072017-04-04 05:51:49 -07002815 const int kWidth = 640;
2816 const int kHeight = 360;
Erik Språng610c7632019-03-06 15:37:33 +01002817 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kLowTargetBitrateBps),
Erik Språng4c6ca302019-04-08 15:14:01 +02002818 DataRate::bps(kLowTargetBitrateBps),
2819 0, 0);
kthelgason2bc68642017-02-07 07:02:22 -08002820
2821 // Set degradation preference.
mflodmancc3d4422017-08-03 08:27:51 -07002822 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002823 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
kthelgason2bc68642017-02-07 07:02:22 -08002824
asaperssonfab67072017-04-04 05:51:49 -07002825 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgason2bc68642017-02-07 07:02:22 -08002826 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002827 WaitForEncodedFrame(1);
kthelgason2bc68642017-02-07 07:02:22 -08002828
mflodmancc3d4422017-08-03 08:27:51 -07002829 video_stream_encoder_->Stop();
kthelgason2bc68642017-02-07 07:02:22 -08002830}
2831
mflodmancc3d4422017-08-03 08:27:51 -07002832TEST_F(VideoStreamEncoderTest, InitialFrameDropOffWhenEncoderDisabledScaling) {
asaperssonfab67072017-04-04 05:51:49 -07002833 const int kWidth = 640;
2834 const int kHeight = 360;
kthelgasonad9010c2017-02-14 00:46:51 -08002835 fake_encoder_.SetQualityScaling(false);
Niels Möller4db138e2018-04-19 09:04:13 +02002836
2837 VideoEncoderConfig video_encoder_config;
2838 test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config);
2839 // Make format different, to force recreation of encoder.
2840 video_encoder_config.video_format.parameters["foo"] = "foo";
2841 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02002842 kMaxPayloadLength);
Erik Språng610c7632019-03-06 15:37:33 +01002843 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(kLowTargetBitrateBps),
Erik Språng4c6ca302019-04-08 15:14:01 +02002844 DataRate::bps(kLowTargetBitrateBps),
2845 0, 0);
asapersson09f05612017-05-15 23:40:18 -07002846
kthelgasonb83797b2017-02-14 11:57:25 -08002847 // Force quality scaler reconfiguration by resetting the source.
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002848 video_stream_encoder_->SetSource(&video_source_,
2849 webrtc::DegradationPreference::BALANCED);
kthelgasonad9010c2017-02-14 00:46:51 -08002850
asaperssonfab67072017-04-04 05:51:49 -07002851 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
kthelgasonad9010c2017-02-14 00:46:51 -08002852 // Frame should not be dropped, even if it's too large.
sprang4847ae62017-06-27 07:06:52 -07002853 WaitForEncodedFrame(1);
kthelgasonad9010c2017-02-14 00:46:51 -08002854
mflodmancc3d4422017-08-03 08:27:51 -07002855 video_stream_encoder_->Stop();
kthelgasonad9010c2017-02-14 00:46:51 -08002856 fake_encoder_.SetQualityScaling(true);
2857}
2858
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002859TEST_F(VideoStreamEncoderTest, InitialFrameDropActivatesWhenBWEstimateReady) {
2860 webrtc::test::ScopedFieldTrials field_trials(
2861 "WebRTC-InitialFramedrop/Enabled/");
2862 // Reset encoder for field trials to take effect.
2863 ConfigureEncoder(video_encoder_config_.Copy());
2864 const int kTooLowBitrateForFrameSizeBps = 10000;
2865 const int kWidth = 640;
2866 const int kHeight = 360;
2867
Erik Språng4c6ca302019-04-08 15:14:01 +02002868 video_stream_encoder_->OnBitrateUpdated(
2869 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002870 video_source_.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
2871 // Frame should not be dropped.
2872 WaitForEncodedFrame(1);
2873
Erik Språng610c7632019-03-06 15:37:33 +01002874 video_stream_encoder_->OnBitrateUpdated(
Erik Språng4c6ca302019-04-08 15:14:01 +02002875 DataRate::bps(kTooLowBitrateForFrameSizeBps),
2876 DataRate::bps(kTooLowBitrateForFrameSizeBps), 0, 0);
Kári Tristan Helgason639602a2018-08-02 10:51:40 +02002877 video_source_.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
2878 // Expect to drop this frame, the wait should time out.
2879 ExpectDroppedFrame();
2880
2881 // Expect the sink_wants to specify a scaled frame.
2882 EXPECT_LT(video_source_.sink_wants().max_pixel_count, kWidth * kHeight);
2883 video_stream_encoder_->Stop();
2884}
2885
mflodmancc3d4422017-08-03 08:27:51 -07002886TEST_F(VideoStreamEncoderTest,
asaperssond0de2952017-04-21 01:47:31 -07002887 ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
2888 const int kTooSmallWidth = 10;
2889 const int kTooSmallHeight = 10;
Erik Språng4c6ca302019-04-08 15:14:01 +02002890 video_stream_encoder_->OnBitrateUpdated(
2891 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssond0de2952017-04-21 01:47:31 -07002892
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002893 // Enable MAINTAIN_FRAMERATE preference, no initial limitation.
asaperssond0de2952017-04-21 01:47:31 -07002894 test::FrameForwarder source;
mflodmancc3d4422017-08-03 08:27:51 -07002895 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002896 &source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
asaperssond0de2952017-04-21 01:47:31 -07002897 VerifyNoLimitation(source.sink_wants());
2898 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2899
2900 // Trigger adapt down, too small frame, expect no change.
2901 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002902 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002903 video_stream_encoder_->TriggerCpuOveruse();
Åsa Persson8c1bf952018-09-13 10:42:19 +02002904 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssond0de2952017-04-21 01:47:31 -07002905 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
2906 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
2907
mflodmancc3d4422017-08-03 08:27:51 -07002908 video_stream_encoder_->Stop();
asaperssond0de2952017-04-21 01:47:31 -07002909}
2910
mflodmancc3d4422017-08-03 08:27:51 -07002911TEST_F(VideoStreamEncoderTest,
2912 ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07002913 const int kTooSmallWidth = 10;
2914 const int kTooSmallHeight = 10;
2915 const int kFpsLimit = 7;
Erik Språng4c6ca302019-04-08 15:14:01 +02002916 video_stream_encoder_->OnBitrateUpdated(
2917 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07002918
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002919 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07002920 test::FrameForwarder source;
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07002921 video_stream_encoder_->SetSource(&source,
2922 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07002923 VerifyNoLimitation(source.sink_wants());
2924 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2925 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
2926
2927 // Trigger adapt down, expect limited framerate.
2928 source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002929 WaitForEncodedFrame(1);
mflodmancc3d4422017-08-03 08:27:51 -07002930 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002931 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2932 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2933 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2934 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2935
2936 // Trigger adapt down, too small frame, expect no change.
2937 source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
sprang4847ae62017-06-27 07:06:52 -07002938 WaitForEncodedFrame(2);
mflodmancc3d4422017-08-03 08:27:51 -07002939 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07002940 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
2941 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
2942 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
2943 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
2944
mflodmancc3d4422017-08-03 08:27:51 -07002945 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07002946}
2947
mflodmancc3d4422017-08-03 08:27:51 -07002948TEST_F(VideoStreamEncoderTest, FailingInitEncodeDoesntCauseCrash) {
asapersson02465b82017-04-10 01:12:52 -07002949 fake_encoder_.ForceInitEncodeFailure(true);
Erik Språng4c6ca302019-04-08 15:14:01 +02002950 video_stream_encoder_->OnBitrateUpdated(
2951 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möllerf1338562018-04-26 09:51:47 +02002952 ResetEncoder("VP8", 2, 1, 1, false);
asapersson02465b82017-04-10 01:12:52 -07002953 const int kFrameWidth = 1280;
2954 const int kFrameHeight = 720;
2955 video_source_.IncomingCapturedFrame(
2956 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002957 ExpectDroppedFrame();
mflodmancc3d4422017-08-03 08:27:51 -07002958 video_stream_encoder_->Stop();
asapersson02465b82017-04-10 01:12:52 -07002959}
2960
sprangb1ca0732017-02-01 08:38:12 -08002961// TODO(sprang): Extend this with fps throttling and any "balanced" extensions.
mflodmancc3d4422017-08-03 08:27:51 -07002962TEST_F(VideoStreamEncoderTest,
2963 AdaptsResolutionOnOveruse_MaintainFramerateMode) {
Erik Språng4c6ca302019-04-08 15:14:01 +02002964 video_stream_encoder_->OnBitrateUpdated(
2965 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
sprangb1ca0732017-02-01 08:38:12 -08002966
2967 const int kFrameWidth = 1280;
2968 const int kFrameHeight = 720;
2969 // Enabled default VideoAdapter downscaling. First step is 3/4, not 3/5 as
mflodmancc3d4422017-08-03 08:27:51 -07002970 // requested by
2971 // VideoStreamEncoder::VideoSourceProxy::RequestResolutionLowerThan().
sprangb1ca0732017-02-01 08:38:12 -08002972 video_source_.set_adaptation_enabled(true);
2973
2974 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002975 CreateFrame(1 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002976 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002977
2978 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07002979 video_stream_encoder_->TriggerCpuOveruse();
sprangb1ca0732017-02-01 08:38:12 -08002980 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002981 CreateFrame(2 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002982 WaitForEncodedFrame((kFrameWidth * 3) / 4, (kFrameHeight * 3) / 4);
sprangb1ca0732017-02-01 08:38:12 -08002983
asaperssonfab67072017-04-04 05:51:49 -07002984 // Trigger CPU normal use, return to original resolution.
mflodmancc3d4422017-08-03 08:27:51 -07002985 video_stream_encoder_->TriggerCpuNormalUsage();
sprangb1ca0732017-02-01 08:38:12 -08002986 video_source_.IncomingCapturedFrame(
Åsa Persson8c1bf952018-09-13 10:42:19 +02002987 CreateFrame(3 * kFrameIntervalMs, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07002988 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
sprangb1ca0732017-02-01 08:38:12 -08002989
mflodmancc3d4422017-08-03 08:27:51 -07002990 video_stream_encoder_->Stop();
sprangb1ca0732017-02-01 08:38:12 -08002991}
sprangfe627f32017-03-29 08:24:59 -07002992
mflodmancc3d4422017-08-03 08:27:51 -07002993TEST_F(VideoStreamEncoderTest,
2994 AdaptsFramerateOnOveruse_MaintainResolutionMode) {
sprangc5d62e22017-04-02 23:53:04 -07002995 const int kFrameWidth = 1280;
2996 const int kFrameHeight = 720;
sprangc5d62e22017-04-02 23:53:04 -07002997
Erik Språng4c6ca302019-04-08 15:14:01 +02002998 video_stream_encoder_->OnBitrateUpdated(
2999 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -07003000 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003001 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07003002 video_source_.set_adaptation_enabled(true);
3003
sprang4847ae62017-06-27 07:06:52 -07003004 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07003005
3006 video_source_.IncomingCapturedFrame(
3007 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003008 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07003009
3010 // Try to trigger overuse. No fps estimate available => no effect.
mflodmancc3d4422017-08-03 08:27:51 -07003011 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07003012
3013 // Insert frames for one second to get a stable estimate.
sprang4847ae62017-06-27 07:06:52 -07003014 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07003015 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07003016 video_source_.IncomingCapturedFrame(
3017 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003018 WaitForEncodedFrame(timestamp_ms);
sprangc5d62e22017-04-02 23:53:04 -07003019 }
3020
3021 // Trigger CPU overuse, reduce framerate by 2/3.
mflodmancc3d4422017-08-03 08:27:51 -07003022 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07003023 int num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07003024 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07003025 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07003026 video_source_.IncomingCapturedFrame(
3027 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003028 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07003029 ++num_frames_dropped;
3030 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01003031 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07003032 }
3033 }
3034
sprang4847ae62017-06-27 07:06:52 -07003035 // Add some slack to account for frames dropped by the frame dropper.
3036 const int kErrorMargin = 1;
3037 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07003038 kErrorMargin);
3039
3040 // Trigger CPU overuse, reduce framerate by 2/3 again.
mflodmancc3d4422017-08-03 08:27:51 -07003041 video_stream_encoder_->TriggerCpuOveruse();
sprangc5d62e22017-04-02 23:53:04 -07003042 num_frames_dropped = 0;
Åsa Persson8c1bf952018-09-13 10:42:19 +02003043 for (int i = 0; i <= max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07003044 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07003045 video_source_.IncomingCapturedFrame(
3046 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003047 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07003048 ++num_frames_dropped;
3049 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01003050 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07003051 }
3052 }
sprang4847ae62017-06-27 07:06:52 -07003053 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 4 / 9),
sprangc5d62e22017-04-02 23:53:04 -07003054 kErrorMargin);
3055
3056 // Go back up one step.
mflodmancc3d4422017-08-03 08:27:51 -07003057 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07003058 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07003059 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07003060 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07003061 video_source_.IncomingCapturedFrame(
3062 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003063 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07003064 ++num_frames_dropped;
3065 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01003066 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07003067 }
3068 }
sprang4847ae62017-06-27 07:06:52 -07003069 EXPECT_NEAR(num_frames_dropped, max_framerate_ - (max_framerate_ * 2 / 3),
sprangc5d62e22017-04-02 23:53:04 -07003070 kErrorMargin);
3071
3072 // Go back up to original mode.
mflodmancc3d4422017-08-03 08:27:51 -07003073 video_stream_encoder_->TriggerCpuNormalUsage();
sprangc5d62e22017-04-02 23:53:04 -07003074 num_frames_dropped = 0;
sprang4847ae62017-06-27 07:06:52 -07003075 for (int i = 0; i < max_framerate_; ++i) {
sprangc5d62e22017-04-02 23:53:04 -07003076 timestamp_ms += kFrameIntervalMs;
sprangc5d62e22017-04-02 23:53:04 -07003077 video_source_.IncomingCapturedFrame(
3078 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003079 if (!WaitForFrame(kFrameTimeoutMs)) {
sprangc5d62e22017-04-02 23:53:04 -07003080 ++num_frames_dropped;
3081 } else {
Åsa Perssonc74d8da2017-12-04 14:13:56 +01003082 sink_.CheckLastFrameSizeMatches(kFrameWidth, kFrameHeight);
sprangc5d62e22017-04-02 23:53:04 -07003083 }
3084 }
3085 EXPECT_NEAR(num_frames_dropped, 0, kErrorMargin);
3086
mflodmancc3d4422017-08-03 08:27:51 -07003087 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07003088}
3089
mflodmancc3d4422017-08-03 08:27:51 -07003090TEST_F(VideoStreamEncoderTest, DoesntAdaptDownPastMinFramerate) {
sprangc5d62e22017-04-02 23:53:04 -07003091 const int kFramerateFps = 5;
3092 const int kFrameIntervalMs = rtc::kNumMillisecsPerSec / kFramerateFps;
sprangc5d62e22017-04-02 23:53:04 -07003093 const int kFrameWidth = 1280;
3094 const int kFrameHeight = 720;
3095
sprang4847ae62017-06-27 07:06:52 -07003096 // Reconfigure encoder with two temporal layers and screensharing, which will
3097 // disable frame dropping and make testing easier.
Niels Möllerf1338562018-04-26 09:51:47 +02003098 ResetEncoder("VP8", 1, 2, 1, true);
sprang4847ae62017-06-27 07:06:52 -07003099
Erik Språng4c6ca302019-04-08 15:14:01 +02003100 video_stream_encoder_->OnBitrateUpdated(
3101 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -07003102 video_stream_encoder_->SetSource(
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003103 &video_source_, webrtc::DegradationPreference::MAINTAIN_RESOLUTION);
sprangc5d62e22017-04-02 23:53:04 -07003104 video_source_.set_adaptation_enabled(true);
3105
sprang4847ae62017-06-27 07:06:52 -07003106 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
sprangc5d62e22017-04-02 23:53:04 -07003107
3108 // Trigger overuse as much as we can.
Jonathan Yubc771b72017-12-08 17:04:29 -08003109 rtc::VideoSinkWants last_wants;
3110 do {
3111 last_wants = video_source_.sink_wants();
3112
sprangc5d62e22017-04-02 23:53:04 -07003113 // Insert frames to get a new fps estimate...
3114 for (int j = 0; j < kFramerateFps; ++j) {
3115 video_source_.IncomingCapturedFrame(
3116 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
Jonathan Yubc771b72017-12-08 17:04:29 -08003117 if (video_source_.last_sent_width()) {
3118 sink_.WaitForEncodedFrame(timestamp_ms);
3119 }
sprangc5d62e22017-04-02 23:53:04 -07003120 timestamp_ms += kFrameIntervalMs;
Sebastian Jansson40889f32019-04-17 12:11:20 +02003121 fake_clock_.AdvanceTime(TimeDelta::ms(kFrameIntervalMs));
sprangc5d62e22017-04-02 23:53:04 -07003122 }
3123 // ...and then try to adapt again.
mflodmancc3d4422017-08-03 08:27:51 -07003124 video_stream_encoder_->TriggerCpuOveruse();
Jonathan Yubc771b72017-12-08 17:04:29 -08003125 } while (video_source_.sink_wants().max_framerate_fps <
3126 last_wants.max_framerate_fps);
sprangc5d62e22017-04-02 23:53:04 -07003127
Jonathan Yubc771b72017-12-08 17:04:29 -08003128 VerifyFpsEqResolutionMax(video_source_.sink_wants(), kMinFramerateFps);
asaperssonf7e294d2017-06-13 23:25:22 -07003129
mflodmancc3d4422017-08-03 08:27:51 -07003130 video_stream_encoder_->Stop();
sprangc5d62e22017-04-02 23:53:04 -07003131}
asaperssonf7e294d2017-06-13 23:25:22 -07003132
mflodmancc3d4422017-08-03 08:27:51 -07003133TEST_F(VideoStreamEncoderTest,
3134 AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
asaperssonf7e294d2017-06-13 23:25:22 -07003135 const int kWidth = 1280;
3136 const int kHeight = 720;
3137 const int64_t kFrameIntervalMs = 150;
3138 int64_t timestamp_ms = kFrameIntervalMs;
Erik Språng4c6ca302019-04-08 15:14:01 +02003139 video_stream_encoder_->OnBitrateUpdated(
3140 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07003141
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003142 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07003143 AdaptingFrameForwarder source;
3144 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003145 video_stream_encoder_->SetSource(&source,
3146 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07003147 timestamp_ms += kFrameIntervalMs;
3148 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003149 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003150 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003151 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3152 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3153 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3154
3155 // Trigger adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003156 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003157 timestamp_ms += kFrameIntervalMs;
3158 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003159 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003160 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
3161 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3162 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3163 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3164
3165 // Trigger adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003166 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003167 timestamp_ms += kFrameIntervalMs;
3168 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003169 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003170 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
3171 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3172 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3173 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3174
3175 // Trigger adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003176 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003177 timestamp_ms += kFrameIntervalMs;
3178 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003179 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003180 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
3181 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3182 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3183 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3184
3185 // Trigger adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003186 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003187 timestamp_ms += kFrameIntervalMs;
3188 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003189 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003190 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
3191 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3192 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3193 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3194
3195 // Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07003196 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003197 timestamp_ms += kFrameIntervalMs;
3198 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003199 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003200 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
3201 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3202 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3203 EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3204
3205 // Trigger adapt down, expect scaled down resolution (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07003206 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003207 timestamp_ms += kFrameIntervalMs;
3208 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003209 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003210 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
3211 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3212 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3213 EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3214
3215 // Trigger adapt down, expect reduced fps (320x180@7fps).
mflodmancc3d4422017-08-03 08:27:51 -07003216 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003217 timestamp_ms += kFrameIntervalMs;
3218 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003219 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003220 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
3221 rtc::VideoSinkWants last_wants = source.sink_wants();
3222 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3223 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3224 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3225
3226 // Trigger adapt down, min resolution reached, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003227 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003228 timestamp_ms += kFrameIntervalMs;
3229 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003230 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003231 VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
3232 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3233 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3234 EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3235
3236 // Trigger adapt down, expect expect increased fps (320x180@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07003237 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003238 timestamp_ms += kFrameIntervalMs;
3239 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003240 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003241 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
3242 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3243 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3244 EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3245
3246 // Trigger adapt up, expect upscaled resolution (480x270@10fps).
mflodmancc3d4422017-08-03 08:27:51 -07003247 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003248 timestamp_ms += kFrameIntervalMs;
3249 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003250 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003251 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3252 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3253 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3254 EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3255
3256 // Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003257 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003258 timestamp_ms += kFrameIntervalMs;
3259 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003260 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003261 VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
3262 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3263 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3264 EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3265
3266 // Trigger adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003267 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003268 timestamp_ms += kFrameIntervalMs;
3269 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003270 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003271 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3272 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3273 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3274 EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3275
3276 // Trigger adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003277 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003278 timestamp_ms += kFrameIntervalMs;
3279 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003280 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003281 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
3282 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3283 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3284 EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3285
3286 // Trigger adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003287 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003288 timestamp_ms += kFrameIntervalMs;
3289 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003290 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003291 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3292 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3293 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3294 EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3295
3296 // Trigger adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003297 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003298 timestamp_ms += kFrameIntervalMs;
3299 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003300 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003301 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02003302 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003303 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3304 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3305 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3306
3307 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003308 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003309 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003310 EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3311
mflodmancc3d4422017-08-03 08:27:51 -07003312 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003313}
3314
mflodmancc3d4422017-08-03 08:27:51 -07003315TEST_F(VideoStreamEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
asaperssonf7e294d2017-06-13 23:25:22 -07003316 const int kWidth = 1280;
3317 const int kHeight = 720;
3318 const int64_t kFrameIntervalMs = 150;
3319 int64_t timestamp_ms = kFrameIntervalMs;
Erik Språng4c6ca302019-04-08 15:14:01 +02003320 video_stream_encoder_->OnBitrateUpdated(
3321 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07003322
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003323 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07003324 AdaptingFrameForwarder source;
3325 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003326 video_stream_encoder_->SetSource(&source,
3327 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07003328 timestamp_ms += kFrameIntervalMs;
3329 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003330 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003331 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003332 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3333 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3334 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3335 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3336 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3337 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3338
3339 // Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003340 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003341 timestamp_ms += kFrameIntervalMs;
3342 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003343 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003344 VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
3345 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3346 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3347 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3348 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3349 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3350 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3351
3352 // Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003353 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003354 timestamp_ms += kFrameIntervalMs;
3355 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003356 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003357 VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
3358 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3359 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3360 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3361 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3362 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3363 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3364
3365 // Trigger quality adapt down, expect reduced fps (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003366 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003367 timestamp_ms += kFrameIntervalMs;
3368 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003369 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003370 VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
3371 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3372 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3373 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3374 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3375 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3376 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3377
3378 // Trigger cpu adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003379 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003380 timestamp_ms += kFrameIntervalMs;
3381 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003382 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003383 VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
3384 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3385 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3386 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3387 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3388 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3389 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3390
3391 // Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003392 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003393 timestamp_ms += kFrameIntervalMs;
3394 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003395 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003396 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
3397 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3398 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3399 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
3400 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3401 EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3402 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3403
3404 // Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003405 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003406 timestamp_ms += kFrameIntervalMs;
3407 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003408 WaitForEncodedFrame(kWidth, kHeight);
asaperssonf7e294d2017-06-13 23:25:22 -07003409 VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
Åsa Persson8c1bf952018-09-13 10:42:19 +02003410 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003411 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3412 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3413 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3414 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3415 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3416 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3417
3418 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003419 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003420 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003421 EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3422 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3423
mflodmancc3d4422017-08-03 08:27:51 -07003424 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003425}
3426
mflodmancc3d4422017-08-03 08:27:51 -07003427TEST_F(VideoStreamEncoderTest,
3428 AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
asaperssonf7e294d2017-06-13 23:25:22 -07003429 const int kWidth = 640;
3430 const int kHeight = 360;
3431 const int kFpsLimit = 15;
3432 const int64_t kFrameIntervalMs = 150;
3433 int64_t timestamp_ms = kFrameIntervalMs;
Erik Språng4c6ca302019-04-08 15:14:01 +02003434 video_stream_encoder_->OnBitrateUpdated(
3435 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
asaperssonf7e294d2017-06-13 23:25:22 -07003436
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003437 // Enable BALANCED preference, no initial limitation.
asaperssonf7e294d2017-06-13 23:25:22 -07003438 AdaptingFrameForwarder source;
3439 source.set_adaptation_enabled(true);
Taylor Brandstetter49fcc102018-05-16 14:20:41 -07003440 video_stream_encoder_->SetSource(&source,
3441 webrtc::DegradationPreference::BALANCED);
asaperssonf7e294d2017-06-13 23:25:22 -07003442 timestamp_ms += kFrameIntervalMs;
3443 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003444 WaitForEncodedFrame(kWidth, kHeight);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003445 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003446 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3447 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3448 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3449 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3450 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3451 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3452
3453 // Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003454 video_stream_encoder_->TriggerCpuOveruse();
asaperssonf7e294d2017-06-13 23:25:22 -07003455 timestamp_ms += kFrameIntervalMs;
3456 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003457 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003458 VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
3459 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3460 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3461 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3462 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3463 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3464 EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3465
3466 // Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003467 video_stream_encoder_->TriggerQualityLow();
asaperssonf7e294d2017-06-13 23:25:22 -07003468 timestamp_ms += kFrameIntervalMs;
3469 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003470 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003471 VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
3472 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
3473 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3474 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3475 EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
3476 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3477 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3478
3479 // Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
mflodmancc3d4422017-08-03 08:27:51 -07003480 video_stream_encoder_->TriggerCpuNormalUsage();
asaperssonf7e294d2017-06-13 23:25:22 -07003481 timestamp_ms += kFrameIntervalMs;
3482 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003483 WaitForEncodedFrame(timestamp_ms);
asaperssonf7e294d2017-06-13 23:25:22 -07003484 VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
3485 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3486 EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
3487 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3488 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3489 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3490 EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3491
3492 // Trigger quality adapt up, expect increased fps (640x360@30fps).
mflodmancc3d4422017-08-03 08:27:51 -07003493 video_stream_encoder_->TriggerQualityHigh();
asaperssonf7e294d2017-06-13 23:25:22 -07003494 timestamp_ms += kFrameIntervalMs;
3495 source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
sprang4847ae62017-06-27 07:06:52 -07003496 WaitForEncodedFrame(timestamp_ms);
Åsa Persson8c1bf952018-09-13 10:42:19 +02003497 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003498 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
3499 EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
3500 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
3501 EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
3502 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3503 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3504
3505 // Trigger adapt up, expect no change.
mflodmancc3d4422017-08-03 08:27:51 -07003506 video_stream_encoder_->TriggerQualityHigh();
Åsa Persson8c1bf952018-09-13 10:42:19 +02003507 VerifyFpsMaxResolutionMax(source.sink_wants());
asaperssonf7e294d2017-06-13 23:25:22 -07003508 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
3509 EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
3510
mflodmancc3d4422017-08-03 08:27:51 -07003511 video_stream_encoder_->Stop();
asaperssonf7e294d2017-06-13 23:25:22 -07003512}
3513
mflodmancc3d4422017-08-03 08:27:51 -07003514TEST_F(VideoStreamEncoderTest, AcceptsFullHdAdaptedDownSimulcastFrames) {
ilnik6b826ef2017-06-16 06:53:48 -07003515 const int kFrameWidth = 1920;
3516 const int kFrameHeight = 1080;
3517 // 3/4 of 1920.
3518 const int kAdaptedFrameWidth = 1440;
3519 // 3/4 of 1080 rounded down to multiple of 4.
3520 const int kAdaptedFrameHeight = 808;
3521 const int kFramerate = 24;
3522
Erik Språng4c6ca302019-04-08 15:14:01 +02003523 video_stream_encoder_->OnBitrateUpdated(
3524 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
ilnik6b826ef2017-06-16 06:53:48 -07003525 // Trigger reconfigure encoder (without resetting the entire instance).
3526 VideoEncoderConfig video_encoder_config;
Niels Möller259a4972018-04-05 15:36:51 +02003527 video_encoder_config.codec_type = kVideoCodecVP8;
ilnik6b826ef2017-06-16 06:53:48 -07003528 video_encoder_config.max_bitrate_bps = kTargetBitrateBps;
3529 video_encoder_config.number_of_streams = 1;
3530 video_encoder_config.video_stream_factory =
3531 new rtc::RefCountedObject<CroppingVideoStreamFactory>(1, kFramerate);
mflodmancc3d4422017-08-03 08:27:51 -07003532 video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
Niels Möllerf1338562018-04-26 09:51:47 +02003533 kMaxPayloadLength);
mflodmancc3d4422017-08-03 08:27:51 -07003534 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
ilnik6b826ef2017-06-16 06:53:48 -07003535
3536 video_source_.set_adaptation_enabled(true);
3537
3538 video_source_.IncomingCapturedFrame(
3539 CreateFrame(1, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003540 WaitForEncodedFrame(kFrameWidth, kFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003541
3542 // Trigger CPU overuse, downscale by 3/4.
mflodmancc3d4422017-08-03 08:27:51 -07003543 video_stream_encoder_->TriggerCpuOveruse();
ilnik6b826ef2017-06-16 06:53:48 -07003544 video_source_.IncomingCapturedFrame(
3545 CreateFrame(2, kFrameWidth, kFrameHeight));
sprang4847ae62017-06-27 07:06:52 -07003546 WaitForEncodedFrame(kAdaptedFrameWidth, kAdaptedFrameHeight);
ilnik6b826ef2017-06-16 06:53:48 -07003547
mflodmancc3d4422017-08-03 08:27:51 -07003548 video_stream_encoder_->Stop();
ilnik6b826ef2017-06-16 06:53:48 -07003549}
3550
mflodmancc3d4422017-08-03 08:27:51 -07003551TEST_F(VideoStreamEncoderTest, PeriodicallyUpdatesChannelParameters) {
sprang4847ae62017-06-27 07:06:52 -07003552 const int kFrameWidth = 1280;
3553 const int kFrameHeight = 720;
3554 const int kLowFps = 2;
3555 const int kHighFps = 30;
3556
Erik Språng4c6ca302019-04-08 15:14:01 +02003557 video_stream_encoder_->OnBitrateUpdated(
3558 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003559
3560 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3561 max_framerate_ = kLowFps;
3562
3563 // Insert 2 seconds of 2fps video.
3564 for (int i = 0; i < kLowFps * 2; ++i) {
3565 video_source_.IncomingCapturedFrame(
3566 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3567 WaitForEncodedFrame(timestamp_ms);
3568 timestamp_ms += 1000 / kLowFps;
3569 }
3570
3571 // Make sure encoder is updated with new target.
Erik Språng4c6ca302019-04-08 15:14:01 +02003572 video_stream_encoder_->OnBitrateUpdated(
3573 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
sprang4847ae62017-06-27 07:06:52 -07003574 video_source_.IncomingCapturedFrame(
3575 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3576 WaitForEncodedFrame(timestamp_ms);
3577 timestamp_ms += 1000 / kLowFps;
3578
3579 EXPECT_EQ(kLowFps, fake_encoder_.GetConfiguredInputFramerate());
3580
3581 // Insert 30fps frames for just a little more than the forced update period.
3582 const int kVcmTimerIntervalFrames =
3583 (vcm::VCMProcessTimer::kDefaultProcessIntervalMs * kHighFps) / 1000;
3584 const int kFrameIntervalMs = 1000 / kHighFps;
3585 max_framerate_ = kHighFps;
3586 for (int i = 0; i < kVcmTimerIntervalFrames + 2; ++i) {
3587 video_source_.IncomingCapturedFrame(
3588 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3589 // Wait for encoded frame, but skip ahead if it doesn't arrive as it might
3590 // be dropped if the encoder hans't been updated with the new higher target
3591 // framerate yet, causing it to overshoot the target bitrate and then
3592 // suffering the wrath of the media optimizer.
3593 TimedWaitForEncodedFrame(timestamp_ms, 2 * kFrameIntervalMs);
3594 timestamp_ms += kFrameIntervalMs;
3595 }
3596
3597 // Don expect correct measurement just yet, but it should be higher than
3598 // before.
3599 EXPECT_GT(fake_encoder_.GetConfiguredInputFramerate(), kLowFps);
3600
mflodmancc3d4422017-08-03 08:27:51 -07003601 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003602}
3603
mflodmancc3d4422017-08-03 08:27:51 -07003604TEST_F(VideoStreamEncoderTest, DoesNotUpdateBitrateAllocationWhenSuspended) {
sprang4847ae62017-06-27 07:06:52 -07003605 const int kFrameWidth = 1280;
3606 const int kFrameHeight = 720;
3607 const int kTargetBitrateBps = 1000000;
3608
3609 MockBitrateObserver bitrate_observer;
Niels Möller0327c2d2018-05-21 14:09:31 +02003610 video_stream_encoder_->SetBitrateAllocationObserver(&bitrate_observer);
Erik Språng4c6ca302019-04-08 15:14:01 +02003611 video_stream_encoder_->OnBitrateUpdated(
3612 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
mflodmancc3d4422017-08-03 08:27:51 -07003613 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
sprang4847ae62017-06-27 07:06:52 -07003614
3615 // Insert a first video frame, causes another bitrate update.
3616 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3617 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(1);
3618 video_source_.IncomingCapturedFrame(
3619 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3620 WaitForEncodedFrame(timestamp_ms);
3621
3622 // Next, simulate video suspension due to pacer queue overrun.
Erik Språng4c6ca302019-04-08 15:14:01 +02003623 video_stream_encoder_->OnBitrateUpdated(DataRate::bps(0), DataRate::bps(0), 0,
Erik Språng610c7632019-03-06 15:37:33 +01003624 1);
sprang4847ae62017-06-27 07:06:52 -07003625
3626 // Skip ahead until a new periodic parameter update should have occured.
3627 timestamp_ms += vcm::VCMProcessTimer::kDefaultProcessIntervalMs;
Sebastian Jansson40889f32019-04-17 12:11:20 +02003628 fake_clock_.AdvanceTime(
3629 TimeDelta::ms(vcm::VCMProcessTimer::kDefaultProcessIntervalMs));
sprang4847ae62017-06-27 07:06:52 -07003630
3631 // Bitrate observer should not be called.
3632 EXPECT_CALL(bitrate_observer, OnBitrateAllocationUpdated(_)).Times(0);
3633 video_source_.IncomingCapturedFrame(
3634 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3635 ExpectDroppedFrame();
3636
mflodmancc3d4422017-08-03 08:27:51 -07003637 video_stream_encoder_->Stop();
sprang4847ae62017-06-27 07:06:52 -07003638}
ilnik6b826ef2017-06-16 06:53:48 -07003639
Niels Möller4db138e2018-04-19 09:04:13 +02003640TEST_F(VideoStreamEncoderTest,
3641 DefaultCpuAdaptationThresholdsForSoftwareEncoder) {
3642 const int kFrameWidth = 1280;
3643 const int kFrameHeight = 720;
3644 const CpuOveruseOptions default_options;
Erik Språng4c6ca302019-04-08 15:14:01 +02003645 video_stream_encoder_->OnBitrateUpdated(
3646 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möller4db138e2018-04-19 09:04:13 +02003647 video_source_.IncomingCapturedFrame(
3648 CreateFrame(1, kFrameWidth, kFrameHeight));
3649 WaitForEncodedFrame(1);
3650 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3651 .low_encode_usage_threshold_percent,
3652 default_options.low_encode_usage_threshold_percent);
3653 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3654 .high_encode_usage_threshold_percent,
3655 default_options.high_encode_usage_threshold_percent);
3656 video_stream_encoder_->Stop();
3657}
3658
3659TEST_F(VideoStreamEncoderTest,
3660 HigherCpuAdaptationThresholdsForHardwareEncoder) {
3661 const int kFrameWidth = 1280;
3662 const int kFrameHeight = 720;
3663 CpuOveruseOptions hardware_options;
3664 hardware_options.low_encode_usage_threshold_percent = 150;
3665 hardware_options.high_encode_usage_threshold_percent = 200;
Mirta Dvornicicccc1b572019-01-15 12:42:18 +01003666 fake_encoder_.SetIsHardwareAccelerated(true);
Niels Möller4db138e2018-04-19 09:04:13 +02003667
Erik Språng4c6ca302019-04-08 15:14:01 +02003668 video_stream_encoder_->OnBitrateUpdated(
3669 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möller4db138e2018-04-19 09:04:13 +02003670 video_source_.IncomingCapturedFrame(
3671 CreateFrame(1, kFrameWidth, kFrameHeight));
3672 WaitForEncodedFrame(1);
3673 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3674 .low_encode_usage_threshold_percent,
3675 hardware_options.low_encode_usage_threshold_percent);
3676 EXPECT_EQ(video_stream_encoder_->overuse_detector_proxy_->GetOptions()
3677 .high_encode_usage_threshold_percent,
3678 hardware_options.high_encode_usage_threshold_percent);
3679 video_stream_encoder_->Stop();
3680}
3681
Niels Möller6bb5ab92019-01-11 11:11:10 +01003682TEST_F(VideoStreamEncoderTest, DropsFramesWhenEncoderOvershoots) {
3683 const int kFrameWidth = 320;
3684 const int kFrameHeight = 240;
3685 const int kFps = 30;
3686 const int kTargetBitrateBps = 120000;
3687 const int kNumFramesInRun = kFps * 5; // Runs of five seconds.
3688
Erik Språng4c6ca302019-04-08 15:14:01 +02003689 video_stream_encoder_->OnBitrateUpdated(
3690 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003691
3692 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3693 max_framerate_ = kFps;
3694
3695 // Insert 3 seconds of video, verify number of drops with normal bitrate.
3696 fake_encoder_.SimulateOvershoot(1.0);
3697 int num_dropped = 0;
3698 for (int i = 0; i < kNumFramesInRun; ++i) {
3699 video_source_.IncomingCapturedFrame(
3700 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3701 // Wait up to two frame durations for a frame to arrive.
3702 if (!TimedWaitForEncodedFrame(timestamp_ms, 2 * 1000 / kFps)) {
3703 ++num_dropped;
3704 }
3705 timestamp_ms += 1000 / kFps;
3706 }
3707
Erik Språnga8d48ab2019-02-08 14:17:40 +01003708 // Framerate should be measured to be near the expected target rate.
3709 EXPECT_NEAR(fake_encoder_.GetLastFramerate(), kFps, 1);
3710
3711 // Frame drops should be within 5% of expected 0%.
3712 EXPECT_NEAR(num_dropped, 0, 5 * kNumFramesInRun / 100);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003713
3714 // Make encoder produce frames at double the expected bitrate during 3 seconds
3715 // of video, verify number of drops. Rate needs to be slightly changed in
3716 // order to force the rate to be reconfigured.
Erik Språng7ca375c2019-02-06 16:20:17 +01003717 double overshoot_factor = 2.0;
3718 if (RateControlSettings::ParseFromFieldTrials().UseEncoderBitrateAdjuster()) {
3719 // With bitrate adjuster, when need to overshoot even more to trigger
3720 // frame dropping.
3721 overshoot_factor *= 2;
3722 }
3723 fake_encoder_.SimulateOvershoot(overshoot_factor);
Erik Språng610c7632019-03-06 15:37:33 +01003724 video_stream_encoder_->OnBitrateUpdated(
Erik Språng4c6ca302019-04-08 15:14:01 +02003725 DataRate::bps(kTargetBitrateBps + 1000),
3726 DataRate::bps(kTargetBitrateBps + 1000), 0, 0);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003727 num_dropped = 0;
3728 for (int i = 0; i < kNumFramesInRun; ++i) {
3729 video_source_.IncomingCapturedFrame(
3730 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3731 // Wait up to two frame durations for a frame to arrive.
3732 if (!TimedWaitForEncodedFrame(timestamp_ms, 2 * 1000 / kFps)) {
3733 ++num_dropped;
3734 }
3735 timestamp_ms += 1000 / kFps;
3736 }
3737
Erik Språng4c6ca302019-04-08 15:14:01 +02003738 video_stream_encoder_->OnBitrateUpdated(
3739 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Erik Språnga8d48ab2019-02-08 14:17:40 +01003740
3741 // Target framerate should be still be near the expected target, despite
3742 // the frame drops.
3743 EXPECT_NEAR(fake_encoder_.GetLastFramerate(), kFps, 1);
3744
3745 // Frame drops should be within 5% of expected 50%.
3746 EXPECT_NEAR(num_dropped, kNumFramesInRun / 2, 5 * kNumFramesInRun / 100);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003747
3748 video_stream_encoder_->Stop();
3749}
3750
3751TEST_F(VideoStreamEncoderTest, ConfiguresCorrectFrameRate) {
3752 const int kFrameWidth = 320;
3753 const int kFrameHeight = 240;
3754 const int kActualInputFps = 24;
3755 const int kTargetBitrateBps = 120000;
3756
3757 ASSERT_GT(max_framerate_, kActualInputFps);
3758
3759 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
3760 max_framerate_ = kActualInputFps;
Erik Språng4c6ca302019-04-08 15:14:01 +02003761 video_stream_encoder_->OnBitrateUpdated(
3762 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Niels Möller6bb5ab92019-01-11 11:11:10 +01003763
3764 // Insert 3 seconds of video, with an input fps lower than configured max.
3765 for (int i = 0; i < kActualInputFps * 3; ++i) {
3766 video_source_.IncomingCapturedFrame(
3767 CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
3768 // Wait up to two frame durations for a frame to arrive.
3769 WaitForEncodedFrame(timestamp_ms);
3770 timestamp_ms += 1000 / kActualInputFps;
3771 }
3772
3773 EXPECT_NEAR(kActualInputFps, fake_encoder_.GetLastFramerate(), 1);
3774
3775 video_stream_encoder_->Stop();
3776}
3777
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01003778TEST_F(VideoStreamEncoderTest, AccumulatesUpdateRectOnDroppedFrames) {
3779 VideoFrame::UpdateRect rect;
Erik Språng4c6ca302019-04-08 15:14:01 +02003780 video_stream_encoder_->OnBitrateUpdated(
3781 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Ilya Nikolaevskiy71aee3a2019-02-18 13:01:26 +01003782
3783 fake_encoder_.BlockNextEncode();
3784 video_source_.IncomingCapturedFrame(
3785 CreateFrameWithUpdatedPixel(1, nullptr, 0));
3786 WaitForEncodedFrame(1);
3787 // On the very first frame full update should be forced.
3788 rect = fake_encoder_.GetLastUpdateRect();
3789 EXPECT_EQ(rect.offset_x, 0);
3790 EXPECT_EQ(rect.offset_y, 0);
3791 EXPECT_EQ(rect.height, codec_height_);
3792 EXPECT_EQ(rect.width, codec_width_);
3793 // Here, the encoder thread will be blocked in the TestEncoder waiting for a
3794 // call to ContinueEncode.
3795 video_source_.IncomingCapturedFrame(
3796 CreateFrameWithUpdatedPixel(2, nullptr, 1));
3797 ExpectDroppedFrame();
3798 video_source_.IncomingCapturedFrame(
3799 CreateFrameWithUpdatedPixel(3, nullptr, 10));
3800 ExpectDroppedFrame();
3801 fake_encoder_.ContinueEncode();
3802 WaitForEncodedFrame(3);
3803 // Updates to pixels 1 and 10 should be accumulated to one 10x1 rect.
3804 rect = fake_encoder_.GetLastUpdateRect();
3805 EXPECT_EQ(rect.offset_x, 1);
3806 EXPECT_EQ(rect.offset_y, 0);
3807 EXPECT_EQ(rect.width, 10);
3808 EXPECT_EQ(rect.height, 1);
3809
3810 video_source_.IncomingCapturedFrame(
3811 CreateFrameWithUpdatedPixel(4, nullptr, 0));
3812 WaitForEncodedFrame(4);
3813 // Previous frame was encoded, so no accumulation should happen.
3814 rect = fake_encoder_.GetLastUpdateRect();
3815 EXPECT_EQ(rect.offset_x, 0);
3816 EXPECT_EQ(rect.offset_y, 0);
3817 EXPECT_EQ(rect.width, 1);
3818 EXPECT_EQ(rect.height, 1);
3819
3820 video_stream_encoder_->Stop();
3821}
3822
Erik Språngd7329ca2019-02-21 21:19:53 +01003823TEST_F(VideoStreamEncoderTest, SetsFrameTypes) {
Erik Språng4c6ca302019-04-08 15:14:01 +02003824 video_stream_encoder_->OnBitrateUpdated(
3825 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Erik Språngd7329ca2019-02-21 21:19:53 +01003826
3827 // First frame is always keyframe.
3828 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
3829 WaitForEncodedFrame(1);
Niels Möller8f7ce222019-03-21 15:43:58 +01003830 EXPECT_THAT(
3831 fake_encoder_.LastFrameTypes(),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02003832 ::testing::ElementsAre(VideoFrameType{VideoFrameType::kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003833
3834 // Insert delta frame.
3835 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
3836 WaitForEncodedFrame(2);
Niels Möller8f7ce222019-03-21 15:43:58 +01003837 EXPECT_THAT(
3838 fake_encoder_.LastFrameTypes(),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02003839 ::testing::ElementsAre(VideoFrameType{VideoFrameType::kVideoFrameDelta}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003840
3841 // Request next frame be a key-frame.
3842 video_stream_encoder_->SendKeyFrame();
3843 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
3844 WaitForEncodedFrame(3);
Niels Möller8f7ce222019-03-21 15:43:58 +01003845 EXPECT_THAT(
3846 fake_encoder_.LastFrameTypes(),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02003847 ::testing::ElementsAre(VideoFrameType{VideoFrameType::kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003848
3849 video_stream_encoder_->Stop();
3850}
3851
3852TEST_F(VideoStreamEncoderTest, SetsFrameTypesSimulcast) {
3853 // Setup simulcast with three streams.
3854 ResetEncoder("VP8", 3, 1, 1, false);
Erik Språng610c7632019-03-06 15:37:33 +01003855 video_stream_encoder_->OnBitrateUpdated(
Erik Språng4c6ca302019-04-08 15:14:01 +02003856 DataRate::bps(kSimulcastTargetBitrateBps),
3857 DataRate::bps(kSimulcastTargetBitrateBps), 0, 0);
Erik Språngd7329ca2019-02-21 21:19:53 +01003858 // Wait for all three layers before triggering event.
3859 sink_.SetNumExpectedLayers(3);
3860
3861 // First frame is always keyframe.
3862 video_source_.IncomingCapturedFrame(CreateFrame(1, nullptr));
3863 WaitForEncodedFrame(1);
3864 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02003865 ::testing::ElementsAreArray({VideoFrameType::kVideoFrameKey,
3866 VideoFrameType::kVideoFrameKey,
3867 VideoFrameType::kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003868
3869 // Insert delta frame.
3870 video_source_.IncomingCapturedFrame(CreateFrame(2, nullptr));
3871 WaitForEncodedFrame(2);
3872 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02003873 ::testing::ElementsAreArray({VideoFrameType::kVideoFrameDelta,
3874 VideoFrameType::kVideoFrameDelta,
3875 VideoFrameType::kVideoFrameDelta}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003876
3877 // Request next frame be a key-frame.
3878 // Only first stream is configured to produce key-frame.
3879 video_stream_encoder_->SendKeyFrame();
3880 video_source_.IncomingCapturedFrame(CreateFrame(3, nullptr));
3881 WaitForEncodedFrame(3);
Sergey Silkine62a08a2019-05-13 13:45:39 +02003882
3883 // TODO(webrtc:10615): Map keyframe request to spatial layer. Currently
3884 // keyframe request on any layer triggers keyframe on all layers.
Erik Språngd7329ca2019-02-21 21:19:53 +01003885 EXPECT_THAT(fake_encoder_.LastFrameTypes(),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02003886 ::testing::ElementsAreArray({VideoFrameType::kVideoFrameKey,
Sergey Silkine62a08a2019-05-13 13:45:39 +02003887 VideoFrameType::kVideoFrameKey,
3888 VideoFrameType::kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003889
3890 video_stream_encoder_->Stop();
3891}
3892
3893TEST_F(VideoStreamEncoderTest, RequestKeyframeInternalSource) {
3894 // Configure internal source factory and setup test again.
3895 encoder_factory_.SetHasInternalSource(true);
3896 ResetEncoder("VP8", 1, 1, 1, false);
Erik Språng4c6ca302019-04-08 15:14:01 +02003897 video_stream_encoder_->OnBitrateUpdated(
3898 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Erik Språngd7329ca2019-02-21 21:19:53 +01003899
3900 // Call encoder directly, simulating internal source where encoded frame
3901 // callback in VideoStreamEncoder is called despite no OnFrame().
3902 fake_encoder_.InjectFrame(CreateFrame(1, nullptr), true);
3903 EXPECT_TRUE(WaitForFrame(kDefaultTimeoutMs));
Niels Möller8f7ce222019-03-21 15:43:58 +01003904 EXPECT_THAT(
3905 fake_encoder_.LastFrameTypes(),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02003906 ::testing::ElementsAre(VideoFrameType{VideoFrameType::kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003907
Niels Möller8f7ce222019-03-21 15:43:58 +01003908 const std::vector<VideoFrameType> kDeltaFrame = {
3909 VideoFrameType::kVideoFrameDelta};
Erik Språngd7329ca2019-02-21 21:19:53 +01003910 // Need to set timestamp manually since manually for injected frame.
3911 VideoFrame frame = CreateFrame(101, nullptr);
3912 frame.set_timestamp(101);
3913 fake_encoder_.InjectFrame(frame, false);
3914 EXPECT_TRUE(WaitForFrame(kDefaultTimeoutMs));
Niels Möller8f7ce222019-03-21 15:43:58 +01003915 EXPECT_THAT(
3916 fake_encoder_.LastFrameTypes(),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02003917 ::testing::ElementsAre(VideoFrameType{VideoFrameType::kVideoFrameDelta}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003918
3919 // Request key-frame. The forces a dummy frame down into the encoder.
3920 fake_encoder_.ExpectNullFrame();
3921 video_stream_encoder_->SendKeyFrame();
3922 EXPECT_TRUE(WaitForFrame(kDefaultTimeoutMs));
Niels Möller8f7ce222019-03-21 15:43:58 +01003923 EXPECT_THAT(
3924 fake_encoder_.LastFrameTypes(),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02003925 ::testing::ElementsAre(VideoFrameType{VideoFrameType::kVideoFrameKey}));
Erik Språngd7329ca2019-02-21 21:19:53 +01003926
3927 video_stream_encoder_->Stop();
3928}
Erik Språngb7cb7b52019-02-26 15:52:33 +01003929
3930TEST_F(VideoStreamEncoderTest, AdjustsTimestampInternalSource) {
3931 // Configure internal source factory and setup test again.
3932 encoder_factory_.SetHasInternalSource(true);
3933 ResetEncoder("VP8", 1, 1, 1, false);
Erik Språng4c6ca302019-04-08 15:14:01 +02003934 video_stream_encoder_->OnBitrateUpdated(
3935 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
Erik Språngb7cb7b52019-02-26 15:52:33 +01003936
3937 int64_t timestamp = 1;
3938 EncodedImage image;
3939 image.Allocate(kTargetBitrateBps / kDefaultFramerate / 8);
3940 image.capture_time_ms_ = ++timestamp;
3941 image.SetTimestamp(static_cast<uint32_t>(timestamp * 90));
3942 const int64_t kEncodeFinishDelayMs = 10;
3943 image.timing_.encode_start_ms = timestamp;
3944 image.timing_.encode_finish_ms = timestamp + kEncodeFinishDelayMs;
3945 fake_encoder_.InjectEncodedImage(image);
3946 // Wait for frame without incrementing clock.
3947 EXPECT_TRUE(sink_.WaitForFrame(kDefaultTimeoutMs));
3948 // Frame is captured kEncodeFinishDelayMs before it's encoded, so restored
3949 // capture timestamp should be kEncodeFinishDelayMs in the past.
3950 EXPECT_EQ(sink_.GetLastCaptureTimeMs(),
3951 fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec -
3952 kEncodeFinishDelayMs);
3953
3954 video_stream_encoder_->Stop();
3955}
Mirta Dvornicic28f0eb22019-05-28 16:30:16 +02003956
3957TEST_F(VideoStreamEncoderTest, DoesNotRewriteH264BitstreamWithOptimalSps) {
3958 // Configure internal source factory and setup test again.
3959 encoder_factory_.SetHasInternalSource(true);
3960 ResetEncoder("H264", 1, 1, 1, false);
3961
3962 EncodedImage image(optimal_sps, sizeof(optimal_sps), sizeof(optimal_sps));
3963 image._frameType = VideoFrameType::kVideoFrameKey;
3964
3965 CodecSpecificInfo codec_specific_info;
3966 codec_specific_info.codecType = kVideoCodecH264;
3967
3968 RTPFragmentationHeader fragmentation;
3969 fragmentation.VerifyAndAllocateFragmentationHeader(1);
3970 fragmentation.fragmentationOffset[0] = 4;
3971 fragmentation.fragmentationLength[0] = sizeof(optimal_sps) - 4;
3972
3973 fake_encoder_.InjectEncodedImage(image, &codec_specific_info, &fragmentation);
3974 EXPECT_TRUE(sink_.WaitForFrame(kDefaultTimeoutMs));
3975
3976 EXPECT_THAT(sink_.GetLastEncodedImageData(),
3977 testing::ElementsAreArray(optimal_sps));
3978 RTPFragmentationHeader last_fragmentation = sink_.GetLastFragmentation();
3979 ASSERT_THAT(last_fragmentation.fragmentationVectorSize, 1U);
3980 EXPECT_EQ(last_fragmentation.fragmentationOffset[0], 4U);
3981 EXPECT_EQ(last_fragmentation.fragmentationLength[0], sizeof(optimal_sps) - 4);
3982
3983 video_stream_encoder_->Stop();
3984}
3985
3986TEST_F(VideoStreamEncoderTest, RewritesH264BitstreamWithNonOptimalSps) {
3987 uint8_t original_sps[] = {0, 0, 0, 1, H264::NaluType::kSps,
3988 0x00, 0x00, 0x03, 0x03, 0xF4,
3989 0x05, 0x03, 0xC7, 0xC0};
3990
3991 // Configure internal source factory and setup test again.
3992 encoder_factory_.SetHasInternalSource(true);
3993 ResetEncoder("H264", 1, 1, 1, false);
3994
3995 EncodedImage image(original_sps, sizeof(original_sps), sizeof(original_sps));
3996 image._frameType = VideoFrameType::kVideoFrameKey;
3997
3998 CodecSpecificInfo codec_specific_info;
3999 codec_specific_info.codecType = kVideoCodecH264;
4000
4001 RTPFragmentationHeader fragmentation;
4002 fragmentation.VerifyAndAllocateFragmentationHeader(1);
4003 fragmentation.fragmentationOffset[0] = 4;
4004 fragmentation.fragmentationLength[0] = sizeof(original_sps) - 4;
4005
4006 fake_encoder_.InjectEncodedImage(image, &codec_specific_info, &fragmentation);
4007 EXPECT_TRUE(sink_.WaitForFrame(kDefaultTimeoutMs));
4008
4009 EXPECT_THAT(sink_.GetLastEncodedImageData(),
4010 testing::ElementsAreArray(optimal_sps));
4011 RTPFragmentationHeader last_fragmentation = sink_.GetLastFragmentation();
4012 ASSERT_THAT(last_fragmentation.fragmentationVectorSize, 1U);
4013 EXPECT_EQ(last_fragmentation.fragmentationOffset[0], 4U);
4014 EXPECT_EQ(last_fragmentation.fragmentationLength[0], sizeof(optimal_sps) - 4);
4015
4016 video_stream_encoder_->Stop();
4017}
4018
Ilya Nikolaevskiyba96e2f2019-06-04 15:15:14 +02004019TEST_F(VideoStreamEncoderTest, CopiesVideoFrameMetadataAfterDownscale) {
4020 const int kFrameWidth = 1280;
4021 const int kFrameHeight = 720;
4022 const int kTargetBitrateBps = 300000; // To low for HD resolution.
4023
4024 video_stream_encoder_->OnBitrateUpdated(
4025 DataRate::bps(kTargetBitrateBps), DataRate::bps(kTargetBitrateBps), 0, 0);
4026 video_stream_encoder_->WaitUntilTaskQueueIsIdle();
4027
4028 // Insert a first video frame. It should be dropped because of downscale in
4029 // resolution.
4030 int64_t timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
4031 VideoFrame frame = CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight);
4032 frame.set_rotation(kVideoRotation_270);
4033 video_source_.IncomingCapturedFrame(frame);
4034
4035 ExpectDroppedFrame();
4036
4037 // Second frame is downscaled.
4038 timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
4039 frame = CreateFrame(timestamp_ms, kFrameWidth / 2, kFrameHeight / 2);
4040 frame.set_rotation(kVideoRotation_90);
4041 video_source_.IncomingCapturedFrame(frame);
4042
4043 WaitForEncodedFrame(timestamp_ms);
4044 sink_.CheckLastFrameRotationMatches(kVideoRotation_90);
4045
4046 // Insert another frame, also downscaled.
4047 timestamp_ms = fake_clock_.TimeNanos() / rtc::kNumNanosecsPerMillisec;
4048 frame = CreateFrame(timestamp_ms, kFrameWidth / 2, kFrameHeight / 2);
4049 frame.set_rotation(kVideoRotation_180);
4050 video_source_.IncomingCapturedFrame(frame);
4051
4052 WaitForEncodedFrame(timestamp_ms);
4053 sink_.CheckLastFrameRotationMatches(kVideoRotation_180);
4054
4055 video_stream_encoder_->Stop();
4056}
4057
perkj26091b12016-09-01 01:17:40 -07004058} // namespace webrtc