blob: 04bf3d1d5c49cb2fababa0642eb17e376a1691d8 [file] [log] [blame]
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +00001/*
2 * libjingle
3 * Copyright 2010 Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28// If we don't have a WebRtcVideoFrame, just skip all of these tests.
29#if defined(HAVE_WEBRTC_VIDEO)
30#include <limits.h> // For INT_MAX
31#include <string>
32#include <vector>
33
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +000034#include "talk/media/base/mediachannel.h"
35#include "talk/media/base/testutils.h"
36#include "talk/media/base/videoadapter.h"
37#include "talk/media/devices/filevideocapturer.h"
38#include "talk/media/webrtc/webrtcvideoframe.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000039#include "webrtc/base/gunit.h"
40#include "webrtc/base/logging.h"
41#include "webrtc/base/sigslot.h"
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +000042
43namespace cricket {
44
45namespace {
46 static const uint32 kWaitTimeout = 3000U; // 3 seconds.
47 static const uint32 kShortWaitTimeout = 1000U; // 1 second.
48 void UpdateCpuLoad(CoordinatedVideoAdapter* adapter,
49 int current_cpus, int max_cpus, float process_load, float system_load) {
50 adapter->set_cpu_load_min_samples(1);
51 adapter->OnCpuLoadUpdated(current_cpus, max_cpus,
52 process_load, system_load);
53 }
54}
55
56class VideoAdapterTest : public testing::Test {
57 public:
58 virtual void SetUp() {
59 capturer_.reset(new FileVideoCapturer);
60 EXPECT_TRUE(capturer_->Init(GetTestFilePath(
61 "captured-320x240-2s-48.frames")));
62 capture_format_ = capturer_->GetSupportedFormats()->at(0);
63 capture_format_.interval = VideoFormat::FpsToInterval(50);
64 adapter_.reset(new VideoAdapter());
65 adapter_->SetInputFormat(capture_format_);
66
67 listener_.reset(new VideoCapturerListener(adapter_.get()));
68 capturer_->SignalFrameCaptured.connect(
69 listener_.get(), &VideoCapturerListener::OnFrameCaptured);
70 }
71
pbos@webrtc.org75c3ec12014-08-27 18:16:13 +000072 virtual void TearDown() {
73 // Explicitly disconnect the VideoCapturer before to avoid data races
74 // (frames delivered to VideoCapturerListener while it's being destructed).
75 capturer_->SignalFrameCaptured.disconnect_all();
76 }
77
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +000078 protected:
79 class VideoCapturerListener: public sigslot::has_slots<> {
80 public:
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +000081 struct Stats {
82 int captured_frames;
83 int dropped_frames;
84 bool last_adapt_was_no_op;
85
86 int adapted_width;
87 int adapted_height;
88 };
89
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +000090 explicit VideoCapturerListener(VideoAdapter* adapter)
91 : video_adapter_(adapter),
92 adapted_frame_(NULL),
93 copied_output_frame_(),
94 captured_frames_(0),
95 dropped_frames_(0),
96 last_adapt_was_no_op_(false) {
97 }
98
99 void OnFrameCaptured(VideoCapturer* capturer,
100 const CapturedFrame* captured_frame) {
101 WebRtcVideoFrame temp_i420;
102 EXPECT_TRUE(temp_i420.Init(captured_frame,
103 captured_frame->width, abs(captured_frame->height)));
104 VideoFrame* out_frame = NULL;
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000105 rtc::CritScope lock(&crit_);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000106 EXPECT_TRUE(video_adapter_->AdaptFrame(&temp_i420, &out_frame));
107 if (out_frame) {
108 if (out_frame == &temp_i420) {
109 last_adapt_was_no_op_ = true;
110 copied_output_frame_.reset(temp_i420.Copy());
111 adapted_frame_ = copied_output_frame_.get();
112 } else {
113 last_adapt_was_no_op_ = false;
114 adapted_frame_ = out_frame;
115 copied_output_frame_.reset();
116 }
117 } else {
118 ++dropped_frames_;
119 }
120 ++captured_frames_;
121 }
122
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000123 Stats GetStats() {
124 rtc::CritScope lock(&crit_);
125 Stats stats;
126 stats.captured_frames = captured_frames_;
127 stats.dropped_frames = dropped_frames_;
128 stats.last_adapt_was_no_op = last_adapt_was_no_op_;
129 if (adapted_frame_ != NULL) {
pbos@webrtc.orgf21ac1f2014-08-26 12:46:57 +0000130 stats.adapted_width = static_cast<int>(adapted_frame_->GetWidth());
131 stats.adapted_height = static_cast<int>(adapted_frame_->GetHeight());
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000132 } else {
133 stats.adapted_width = stats.adapted_height = -1;
134 }
135
136 return stats;
137 }
138
139 VideoFrame* CopyAdaptedFrame() {
140 rtc::CritScope lock(&crit_);
141 if (adapted_frame_ == NULL) {
142 return NULL;
143 }
144 return adapted_frame_->Copy();
145 }
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000146
147 private:
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000148 rtc::CriticalSection crit_;
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000149 VideoAdapter* video_adapter_;
150 const VideoFrame* adapted_frame_;
151 rtc::scoped_ptr<VideoFrame> copied_output_frame_;
152 int captured_frames_;
153 int dropped_frames_;
154 bool last_adapt_was_no_op_;
155 };
156
157 class CpuAdapterListener: public sigslot::has_slots<> {
158 public:
159 CpuAdapterListener() : received_cpu_signal_(false) {}
160 void OnCpuAdaptationSignalled() { received_cpu_signal_ = true; }
161 bool received_cpu_signal() { return received_cpu_signal_; }
162 private:
163 bool received_cpu_signal_;
164 };
165
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000166 void VerifyAdaptedResolution(const VideoCapturerListener::Stats& stats,
167 int width,
168 int height) {
169 EXPECT_EQ(width, stats.adapted_width);
170 EXPECT_EQ(height, stats.adapted_height);
171 }
172
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000173 rtc::scoped_ptr<FileVideoCapturer> capturer_;
174 rtc::scoped_ptr<VideoAdapter> adapter_;
175 rtc::scoped_ptr<VideoCapturerListener> listener_;
176 VideoFormat capture_format_;
177};
178
179
180// Test adapter remembers exact pixel count
181TEST_F(VideoAdapterTest, AdaptNumPixels) {
182 adapter_->SetOutputNumPixels(123456);
183 EXPECT_EQ(123456, adapter_->GetOutputNumPixels());
184}
185
186// Test adapter is constructed but not activated. Expect no frame drop and no
187// resolution change.
188TEST_F(VideoAdapterTest, AdaptInactive) {
189 // Output resolution is not set.
190 EXPECT_EQ(INT_MAX, adapter_->GetOutputNumPixels());
191
192 // Call Adapter with some frames.
193 EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
194 EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000195 listener_->GetStats().captured_frames >= 10, kWaitTimeout);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000196
197 // Verify no frame drop and no resolution change.
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000198 VideoCapturerListener::Stats stats = listener_->GetStats();
199 EXPECT_GE(stats.captured_frames, 10);
200 EXPECT_EQ(0, stats.dropped_frames);
201 VerifyAdaptedResolution(stats, capture_format_.width, capture_format_.height);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000202}
203
204// Do not adapt the frame rate or the resolution. Expect no frame drop and no
205// resolution change.
206TEST_F(VideoAdapterTest, AdaptNothing) {
207 adapter_->SetOutputFormat(capture_format_);
208 EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
209 EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000210 listener_->GetStats().captured_frames >= 10, kWaitTimeout);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000211
212 // Verify no frame drop and no resolution change.
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000213 VideoCapturerListener::Stats stats = listener_->GetStats();
214 EXPECT_GE(stats.captured_frames, 10);
215 EXPECT_EQ(0, stats.dropped_frames);
216 VerifyAdaptedResolution(stats, capture_format_.width, capture_format_.height);
217 EXPECT_TRUE(stats.last_adapt_was_no_op);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000218}
219
220TEST_F(VideoAdapterTest, AdaptZeroInterval) {
221 VideoFormat format = capturer_->GetSupportedFormats()->at(0);
222 format.interval = 0;
223 adapter_->SetInputFormat(format);
224 adapter_->SetOutputFormat(format);
225 EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
226 EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000227 listener_->GetStats().captured_frames >= 10, kWaitTimeout);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000228
229 // Verify no crash and that frames aren't dropped.
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000230 VideoCapturerListener::Stats stats = listener_->GetStats();
231 EXPECT_GE(stats.captured_frames, 10);
232 EXPECT_EQ(0, stats.dropped_frames);
233 VerifyAdaptedResolution(stats, capture_format_.width, capture_format_.height);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000234}
235
236// Adapt the frame rate to be half of the capture rate at the beginning. Expect
237// the number of dropped frames to be half of the number the captured frames.
238TEST_F(VideoAdapterTest, AdaptFramerate) {
239 VideoFormat request_format = capture_format_;
240 request_format.interval *= 2;
241 adapter_->SetOutputFormat(request_format);
242 EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
243 EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000244 listener_->GetStats().captured_frames >= 10, kWaitTimeout);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000245
246 // Verify frame drop and no resolution change.
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000247 VideoCapturerListener::Stats stats = listener_->GetStats();
248 EXPECT_GE(stats.captured_frames, 10);
249 EXPECT_EQ(stats.captured_frames / 2, stats.dropped_frames);
250 VerifyAdaptedResolution(stats, capture_format_.width, capture_format_.height);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000251}
252
253// Adapt the frame rate to be half of the capture rate at the beginning. Expect
254// the number of dropped frames to be half of the number the captured frames.
255TEST_F(VideoAdapterTest, AdaptFramerateVariable) {
256 VideoFormat request_format = capture_format_;
257 request_format.interval = request_format.interval * 3 / 2;
258 adapter_->SetOutputFormat(request_format);
259 EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
260 EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000261 listener_->GetStats().captured_frames >= 30, kWaitTimeout);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000262
263 // Verify frame drop and no resolution change.
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000264 VideoCapturerListener::Stats stats = listener_->GetStats();
265 EXPECT_GE(stats.captured_frames, 30);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000266 // Verify 2 / 3 kept (20) and 1 / 3 dropped (10).
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000267 EXPECT_EQ(stats.captured_frames * 1 / 3, stats.dropped_frames);
268 VerifyAdaptedResolution(stats, capture_format_.width, capture_format_.height);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000269}
270
271// Adapt the frame rate to be half of the capture rate after capturing no less
272// than 10 frames. Expect no frame dropped before adaptation and frame dropped
273// after adaptation.
274TEST_F(VideoAdapterTest, AdaptFramerateOntheFly) {
275 VideoFormat request_format = capture_format_;
276 adapter_->SetOutputFormat(request_format);
277 EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
278 EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000279 listener_->GetStats().captured_frames >= 10, kWaitTimeout);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000280
281 // Verify no frame drop before adaptation.
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000282 EXPECT_EQ(0, listener_->GetStats().dropped_frames);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000283
284 // Adapat the frame rate.
285 request_format.interval *= 2;
286 adapter_->SetOutputFormat(request_format);
287
288 EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000289 listener_->GetStats().captured_frames >= 20, kWaitTimeout);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000290
291 // Verify frame drop after adaptation.
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000292 EXPECT_GT(listener_->GetStats().dropped_frames, 0);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000293}
294
295// Adapt the frame resolution to be a quarter of the capture resolution at the
296// beginning. Expect resolution change.
297TEST_F(VideoAdapterTest, AdaptResolution) {
298 VideoFormat request_format = capture_format_;
299 request_format.width /= 2;
300 request_format.height /= 2;
301 adapter_->SetOutputFormat(request_format);
302 EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
303 EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000304 listener_->GetStats().captured_frames >= 10, kWaitTimeout);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000305
306 // Verify no frame drop and resolution change.
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000307 VideoCapturerListener::Stats stats = listener_->GetStats();
308 EXPECT_EQ(0, stats.dropped_frames);
309 VerifyAdaptedResolution(stats, request_format.width, request_format.height);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000310}
311
312// Adapt the frame resolution to half width. Expect resolution change.
313TEST_F(VideoAdapterTest, AdaptResolutionNarrow) {
314 VideoFormat request_format = capture_format_;
315 request_format.width /= 2;
316 adapter_->set_scale_third(true);
317 adapter_->SetOutputFormat(request_format);
318 EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
319 EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000320 listener_->GetStats().captured_frames >= 10, kWaitTimeout);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000321
322 // Verify resolution change.
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000323 VerifyAdaptedResolution(listener_->GetStats(), 213, 160);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000324}
325
326// Adapt the frame resolution to half height. Expect resolution change.
327TEST_F(VideoAdapterTest, AdaptResolutionWide) {
328 VideoFormat request_format = capture_format_;
329 request_format.height /= 2;
330 adapter_->set_scale_third(true);
331 adapter_->SetOutputFormat(request_format);
332 EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
333 EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000334 listener_->GetStats().captured_frames >= 10, kWaitTimeout);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000335
336 // Verify resolution change.
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000337 VerifyAdaptedResolution(listener_->GetStats(), 213, 160);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000338}
339
340// Adapt the frame resolution to be a quarter of the capture resolution after
341// capturing no less than 10 frames. Expect no resolution change before
342// adaptation and resolution change after adaptation.
343TEST_F(VideoAdapterTest, AdaptResolutionOnTheFly) {
344 VideoFormat request_format = capture_format_;
345 adapter_->SetOutputFormat(request_format);
346 EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
347 EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000348 listener_->GetStats().captured_frames >= 10, kWaitTimeout);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000349
350 // Verify no resolution change before adaptation.
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000351 VerifyAdaptedResolution(
352 listener_->GetStats(), request_format.width, request_format.height);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000353
354 // Adapt the frame resolution.
355 request_format.width /= 2;
356 request_format.height /= 2;
357 adapter_->SetOutputFormat(request_format);
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000358 int captured_frames = listener_->GetStats().captured_frames;
359 EXPECT_TRUE_WAIT(
360 !capturer_->IsRunning() ||
361 listener_->GetStats().captured_frames >= captured_frames + 10,
362 kWaitTimeout);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000363
364 // Verify resolution change after adaptation.
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000365 VerifyAdaptedResolution(
366 listener_->GetStats(), request_format.width, request_format.height);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000367}
368
369// Black the output frame.
370TEST_F(VideoAdapterTest, BlackOutput) {
371 adapter_->SetOutputFormat(capture_format_);
372 EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
373 EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000374 listener_->GetStats().captured_frames >= 10, kWaitTimeout);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000375 // Verify that the output frame is not black.
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000376 rtc::scoped_ptr<VideoFrame> adapted_frame(listener_->CopyAdaptedFrame());
377 EXPECT_NE(16, *adapted_frame->GetYPlane());
378 EXPECT_NE(128, *adapted_frame->GetUPlane());
379 EXPECT_NE(128, *adapted_frame->GetVPlane());
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000380
381 adapter_->SetBlackOutput(true);
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000382 int captured_frames = listener_->GetStats().captured_frames;
383 EXPECT_TRUE_WAIT(
384 !capturer_->IsRunning() ||
385 listener_->GetStats().captured_frames >= captured_frames + 10,
386 kWaitTimeout);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000387 // Verify that the output frame is black.
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000388 adapted_frame.reset(listener_->CopyAdaptedFrame());
389 EXPECT_EQ(16, *adapted_frame->GetYPlane());
390 EXPECT_EQ(128, *adapted_frame->GetUPlane());
391 EXPECT_EQ(128, *adapted_frame->GetVPlane());
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000392
393 // Verify that the elapsed time and timestamp of the black frame increase.
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000394 int64 elapsed_time = adapted_frame->GetElapsedTime();
395 int64 timestamp = adapted_frame->GetTimeStamp();
396 captured_frames = listener_->GetStats().captured_frames;
397 EXPECT_TRUE_WAIT(
398 !capturer_->IsRunning() ||
399 listener_->GetStats().captured_frames >= captured_frames + 10,
400 kWaitTimeout);
401
402 adapted_frame.reset(listener_->CopyAdaptedFrame());
403 EXPECT_GT(adapted_frame->GetElapsedTime(), elapsed_time);
404 EXPECT_GT(adapted_frame->GetTimeStamp(), timestamp);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000405
406 // Change the output size
407 VideoFormat request_format = capture_format_;
408 request_format.width /= 2;
409 request_format.height /= 2;
410 adapter_->SetOutputFormat(request_format);
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000411 captured_frames = listener_->GetStats().captured_frames;
412 EXPECT_TRUE_WAIT(
413 !capturer_->IsRunning() ||
414 listener_->GetStats().captured_frames >= captured_frames + 10,
415 kWaitTimeout);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000416
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000417 // Verify resolution change after adaptation.
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000418 VerifyAdaptedResolution(
419 listener_->GetStats(), request_format.width, request_format.height);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000420 // Verify that the output frame is black.
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000421 adapted_frame.reset(listener_->CopyAdaptedFrame());
422 EXPECT_EQ(16, *adapted_frame->GetYPlane());
423 EXPECT_EQ(128, *adapted_frame->GetUPlane());
424 EXPECT_EQ(128, *adapted_frame->GetVPlane());
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000425}
426
427// Drop all frames.
428TEST_F(VideoAdapterTest, DropAllFrames) {
429 VideoFormat format; // with resolution 0x0.
430 adapter_->SetOutputFormat(format);
431 EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
432 EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000433 listener_->GetStats().captured_frames >= 10, kWaitTimeout);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000434
435 // Verify all frames are dropped.
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000436 VideoCapturerListener::Stats stats = listener_->GetStats();
437 EXPECT_GE(stats.captured_frames, 10);
438 EXPECT_EQ(stats.captured_frames, stats.dropped_frames);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000439}
440
441TEST(CoordinatedVideoAdapterTest, TestCoordinatedWithoutCpuAdaptation) {
442 CoordinatedVideoAdapter adapter;
443 adapter.set_cpu_adaptation(false);
444
445 VideoFormat format(640, 400, VideoFormat::FpsToInterval(30), FOURCC_I420);
446 adapter.SetInputFormat(format);
447 adapter.set_scale_third(true);
448 EXPECT_EQ(format, adapter.input_format());
449 EXPECT_TRUE(adapter.output_format().IsSize0x0());
450
451 // Server format request 640x400.
452 format.height = 400;
453 adapter.OnOutputFormatRequest(format);
454 EXPECT_EQ(640, adapter.output_format().width);
455 EXPECT_EQ(400, adapter.output_format().height);
456
457 // Server format request 1280x720, higher than input. Adapt nothing.
458 format.width = 1280;
459 format.height = 720;
460 adapter.OnOutputFormatRequest(format);
461 EXPECT_EQ(640, adapter.output_format().width);
462 EXPECT_EQ(400, adapter.output_format().height);
463
464 // Cpu load is high, but cpu adaptation is disabled. Adapt nothing.
465 adapter.OnCpuLoadUpdated(1, 1, 0.99f, 0.99f);
466 EXPECT_EQ(640, adapter.output_format().width);
467 EXPECT_EQ(400, adapter.output_format().height);
468
469 // Encoder resolution request: downgrade with different size. Adapt nothing.
470 adapter.OnEncoderResolutionRequest(320, 200,
471 CoordinatedVideoAdapter::DOWNGRADE);
472 EXPECT_EQ(640, adapter.output_format().width);
473 EXPECT_EQ(400, adapter.output_format().height);
474
475 // Encoder resolution request: downgrade.
476 adapter.OnEncoderResolutionRequest(640, 400,
477 CoordinatedVideoAdapter::DOWNGRADE);
478 EXPECT_EQ(480, adapter.output_format().width);
479 EXPECT_EQ(300, adapter.output_format().height);
480
481 // Encoder resolution request: downgrade. But GD off. Adapt nothing.
482 adapter.set_gd_adaptation(false);
483 adapter.OnEncoderResolutionRequest(480, 300,
484 CoordinatedVideoAdapter::DOWNGRADE);
485 EXPECT_EQ(480, adapter.output_format().width);
486 EXPECT_EQ(300, adapter.output_format().height);
487 adapter.set_gd_adaptation(true);
488
489 // Encoder resolution request: downgrade.
490 adapter.OnEncoderResolutionRequest(480, 300,
491 CoordinatedVideoAdapter::DOWNGRADE);
492 EXPECT_EQ(320, adapter.output_format().width);
493 EXPECT_EQ(200, adapter.output_format().height);
494
495 // Encoder resolution request: keep. Adapt nothing.
496 adapter.OnEncoderResolutionRequest(320, 200,
497 CoordinatedVideoAdapter::KEEP);
498 EXPECT_EQ(320, adapter.output_format().width);
499 EXPECT_EQ(200, adapter.output_format().height);
500
501 // Encoder resolution request: upgrade.
502 adapter.OnEncoderResolutionRequest(320, 200,
503 CoordinatedVideoAdapter::UPGRADE);
504 EXPECT_EQ(480, adapter.output_format().width);
505 EXPECT_EQ(300, adapter.output_format().height);
506
507 // Server format request 0x0.
508 format.width = 0;
509 format.height = 0;
510 adapter.OnOutputFormatRequest(format);
511 EXPECT_TRUE(adapter.output_format().IsSize0x0());
512
513 // Server format request 320x200.
514 format.width = 320;
515 format.height = 200;
516 adapter.OnOutputFormatRequest(format);
517 EXPECT_EQ(320, adapter.output_format().width);
518 EXPECT_EQ(200, adapter.output_format().height);
519
520 // Server format request 160x100. But view disabled. Adapt nothing.
521 adapter.set_view_adaptation(false);
522 format.width = 160;
523 format.height = 100;
524 adapter.OnOutputFormatRequest(format);
525 EXPECT_EQ(320, adapter.output_format().width);
526 EXPECT_EQ(200, adapter.output_format().height);
527 adapter.set_view_adaptation(true);
528
529 // Enable View Switch. Expect adapt down.
530 adapter.set_view_switch(true);
531 format.width = 160;
532 format.height = 100;
533 adapter.OnOutputFormatRequest(format);
534 EXPECT_EQ(160, adapter.output_format().width);
535 EXPECT_EQ(100, adapter.output_format().height);
536
537 // Encoder resolution request: upgrade. Adapt nothing.
538 adapter.OnEncoderResolutionRequest(160, 100,
539 CoordinatedVideoAdapter::UPGRADE);
540 EXPECT_EQ(160, adapter.output_format().width);
541 EXPECT_EQ(100, adapter.output_format().height);
542
543 // Request View of 2 / 3. Expect adapt down.
544 adapter.set_view_switch(true);
545 format.width = (640 * 2 + 1) / 3;
546 format.height = (400 * 2 + 1) / 3;
547 adapter.OnOutputFormatRequest(format);
548 EXPECT_EQ((640 * 2 + 1) / 3, adapter.output_format().width);
549 EXPECT_EQ((400 * 2 + 1) / 3, adapter.output_format().height);
550
551
552 // Request View of 3 / 8. Expect adapt down.
553 adapter.set_view_switch(true);
554 format.width = 640 * 3 / 8;
555 format.height = 400 * 3 / 8;
556 adapter.OnOutputFormatRequest(format);
557 EXPECT_EQ(640 * 3 / 8, adapter.output_format().width);
558 EXPECT_EQ(400 * 3 / 8, adapter.output_format().height);
559
560 // View Switch back up. Expect adapt.
561 format.width = 320;
562 format.height = 200;
563 adapter.OnOutputFormatRequest(format);
564 EXPECT_EQ(320, adapter.output_format().width);
565 EXPECT_EQ(200, adapter.output_format().height);
566
567 adapter.set_view_switch(false);
568
569 // Encoder resolution request: upgrade. Constrained by server request.
570 adapter.OnEncoderResolutionRequest(320, 200,
571 CoordinatedVideoAdapter::UPGRADE);
572 EXPECT_EQ(320, adapter.output_format().width);
573 EXPECT_EQ(200, adapter.output_format().height);
574
575 // Server format request 480x300.
576 format.width = 480;
577 format.height = 300;
578 adapter.OnOutputFormatRequest(format);
579 EXPECT_EQ(480, adapter.output_format().width);
580 EXPECT_EQ(300, adapter.output_format().height);
581}
582
583TEST(CoordinatedVideoAdapterTest, TestCoordinatedWithCpuAdaptation) {
584 CoordinatedVideoAdapter adapter;
585 adapter.set_cpu_adaptation(true);
586 EXPECT_FALSE(adapter.cpu_smoothing());
587 VideoFormat format(640, 400, VideoFormat::FpsToInterval(30), FOURCC_I420);
588 adapter.SetInputFormat(format);
589
590 // Server format request 640x400.
591 format.height = 400;
592 adapter.OnOutputFormatRequest(format);
593 EXPECT_EQ(640, adapter.output_format().width);
594 EXPECT_EQ(400, adapter.output_format().height);
595
596 // Process load is medium, but system load is high. Downgrade.
597 UpdateCpuLoad(&adapter, 1, 1, 0.55f, 0.98f);
598 EXPECT_EQ(480, adapter.output_format().width);
599 EXPECT_EQ(300, adapter.output_format().height);
600
601 // CPU high, but cpu adaptation disabled. Adapt nothing.
602 adapter.set_cpu_adaptation(false);
603 adapter.OnCpuLoadUpdated(1, 1, 0.55f, 0.98f);
604 EXPECT_EQ(480, adapter.output_format().width);
605 EXPECT_EQ(300, adapter.output_format().height);
606 adapter.set_cpu_adaptation(true);
607
608 // System load is high, but time has not elaspsed. Adapt nothing.
609 adapter.set_cpu_load_min_samples(2);
610 adapter.OnCpuLoadUpdated(1, 1, 0.55f, 0.98f);
611 EXPECT_EQ(480, adapter.output_format().width);
612 EXPECT_EQ(300, adapter.output_format().height);
613
614 // Process load is medium, but system load is high. Downgrade.
615 UpdateCpuLoad(&adapter, 1, 1, 0.55f, 0.98f);
616 EXPECT_EQ(320, adapter.output_format().width);
617 EXPECT_EQ(200, adapter.output_format().height);
618
619 // Test reason for adapting is CPU.
620 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_CPU,
621 adapter.adapt_reason());
622
623 // Server format request 320x200. Same as CPU. Do nothing.
624 format.width = 320;
625 format.height = 200;
626 adapter.OnOutputFormatRequest(format);
627 EXPECT_EQ(320, adapter.output_format().width);
628 EXPECT_EQ(200, adapter.output_format().height);
629
630 // Test reason for adapting is CPU and VIEW.
631 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_CPU +
632 CoordinatedVideoAdapter::ADAPTREASON_VIEW,
633 adapter.adapt_reason());
634
635 // Process load and system load are normal. Adapt nothing.
636 UpdateCpuLoad(&adapter, 1, 1, 0.5f, 0.8f);
637 EXPECT_EQ(320, adapter.output_format().width);
638 EXPECT_EQ(200, adapter.output_format().height);
639
640 // Process load and system load are low, but view is still low. Adapt nothing.
641 UpdateCpuLoad(&adapter, 1, 1, 0.2f, 0.3f);
642 EXPECT_EQ(320, adapter.output_format().width);
643 EXPECT_EQ(200, adapter.output_format().height);
644
645 // Test reason for adapting is VIEW.
646 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_VIEW,
647 adapter.adapt_reason());
648
649 // Server format request 640x400. Cpu is still low. Upgrade.
650 format.width = 640;
651 format.height = 400;
652 adapter.OnOutputFormatRequest(format);
653 EXPECT_EQ(480, adapter.output_format().width);
654 EXPECT_EQ(300, adapter.output_format().height);
655
656 // Test reason for adapting is CPU.
657 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_CPU,
658 adapter.adapt_reason());
659
660 // Encoder resolution request: downgrade.
661 adapter.OnEncoderResolutionRequest(480, 300,
662 CoordinatedVideoAdapter::DOWNGRADE);
663 EXPECT_EQ(320, adapter.output_format().width);
664 EXPECT_EQ(200, adapter.output_format().height);
665
666 // Test reason for adapting is BANDWIDTH.
667 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_BANDWIDTH,
668 adapter.adapt_reason());
669
670 // Process load and system load are low. Constrained by GD. Adapt nothing
671 adapter.OnCpuLoadUpdated(1, 1, 0.2f, 0.3f);
672 EXPECT_EQ(320, adapter.output_format().width);
673 EXPECT_EQ(200, adapter.output_format().height);
674
675 // Encoder resolution request: upgrade.
676 adapter.OnEncoderResolutionRequest(320, 200,
677 CoordinatedVideoAdapter::UPGRADE);
678 EXPECT_EQ(480, adapter.output_format().width);
679 EXPECT_EQ(300, adapter.output_format().height);
680
681 // Encoder resolution request: upgrade. Constrained by CPU.
682 adapter.OnEncoderResolutionRequest(480, 300,
683 CoordinatedVideoAdapter::UPGRADE);
684 EXPECT_EQ(480, adapter.output_format().width);
685 EXPECT_EQ(300, adapter.output_format().height);
686
687 // Server format request 640x400. Constrained by CPU.
688 format.width = 640;
689 format.height = 400;
690 adapter.OnOutputFormatRequest(format);
691 EXPECT_EQ(480, adapter.output_format().width);
692 EXPECT_EQ(300, adapter.output_format().height);
693}
694
695TEST(CoordinatedVideoAdapterTest, TestCoordinatedWithCpuRequest) {
696 CoordinatedVideoAdapter adapter;
697 adapter.set_cpu_adaptation(true);
698 EXPECT_FALSE(adapter.cpu_smoothing());
699 VideoFormat format(640, 400, VideoFormat::FpsToInterval(30), FOURCC_I420);
700 adapter.SetInputFormat(format);
701
702 // Server format request 640x400.
703 format.height = 400;
704 adapter.OnOutputFormatRequest(format);
705 EXPECT_EQ(640, adapter.output_format().width);
706 EXPECT_EQ(400, adapter.output_format().height);
707
708 // CPU resolution request: downgrade. Adapt down.
709 adapter.OnCpuResolutionRequest(CoordinatedVideoAdapter::DOWNGRADE);
710 EXPECT_EQ(480, adapter.output_format().width);
711 EXPECT_EQ(300, adapter.output_format().height);
712
713 // CPU resolution request: keep. Do nothing.
714 adapter.OnCpuResolutionRequest(CoordinatedVideoAdapter::KEEP);
715 EXPECT_EQ(480, adapter.output_format().width);
716 EXPECT_EQ(300, adapter.output_format().height);
717
718 // CPU resolution request: downgrade, but cpu adaptation disabled.
719 // Adapt nothing.
720 adapter.set_cpu_adaptation(false);
721 adapter.OnCpuResolutionRequest(CoordinatedVideoAdapter::DOWNGRADE);
722 EXPECT_EQ(480, adapter.output_format().width);
723 EXPECT_EQ(300, adapter.output_format().height);
724
725 // CPU resolution request: downgrade. Adapt down.
726 adapter.set_cpu_adaptation(true);
727 adapter.OnCpuResolutionRequest(CoordinatedVideoAdapter::DOWNGRADE);
728 EXPECT_EQ(320, adapter.output_format().width);
729 EXPECT_EQ(200, adapter.output_format().height);
730
731 // Test reason for adapting is CPU.
732 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_CPU,
733 adapter.adapt_reason());
734
735 // CPU resolution request: downgrade, but already at minimum. Do nothing.
736 adapter.OnCpuResolutionRequest(CoordinatedVideoAdapter::DOWNGRADE);
737 EXPECT_EQ(320, adapter.output_format().width);
738 EXPECT_EQ(200, adapter.output_format().height);
739
740 // Server format request 320x200. Same as CPU. Do nothing.
741 format.width = 320;
742 format.height = 200;
743 adapter.OnOutputFormatRequest(format);
744 EXPECT_EQ(320, adapter.output_format().width);
745 EXPECT_EQ(200, adapter.output_format().height);
746
747 // Test reason for adapting is CPU and VIEW.
748 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_CPU +
749 CoordinatedVideoAdapter::ADAPTREASON_VIEW,
750 adapter.adapt_reason());
751
752 // CPU resolution request: upgrade, but view request still low. Do nothing.
753 adapter.OnCpuResolutionRequest(CoordinatedVideoAdapter::UPGRADE);
754 EXPECT_EQ(320, adapter.output_format().width);
755 EXPECT_EQ(200, adapter.output_format().height);
756
757 // Test reason for adapting is VIEW.
758 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_VIEW,
759 adapter.adapt_reason());
760
761 // Server format request 640x400. Cpu is still low. Upgrade.
762 format.width = 640;
763 format.height = 400;
764 adapter.OnOutputFormatRequest(format);
765 EXPECT_EQ(480, adapter.output_format().width);
766 EXPECT_EQ(300, adapter.output_format().height);
767
768 // Test reason for adapting is CPU.
769 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_CPU,
770 adapter.adapt_reason());
771
772 // Encoder resolution request: downgrade.
773 adapter.OnEncoderResolutionRequest(480, 300,
774 CoordinatedVideoAdapter::DOWNGRADE);
775 EXPECT_EQ(320, adapter.output_format().width);
776 EXPECT_EQ(200, adapter.output_format().height);
777
778 // Test reason for adapting is BANDWIDTH.
779 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_BANDWIDTH,
780 adapter.adapt_reason());
781
782 // Process load and system load are low. Constrained by GD. Adapt nothing
783 adapter.OnCpuLoadUpdated(1, 1, 0.2f, 0.3f);
784 EXPECT_EQ(320, adapter.output_format().width);
785 EXPECT_EQ(200, adapter.output_format().height);
786
787 // Encoder resolution request: upgrade.
788 adapter.OnEncoderResolutionRequest(320, 200,
789 CoordinatedVideoAdapter::UPGRADE);
790 EXPECT_EQ(480, adapter.output_format().width);
791 EXPECT_EQ(300, adapter.output_format().height);
792
793 // Encoder resolution request: upgrade. Constrained by CPU.
794 adapter.OnEncoderResolutionRequest(480, 300,
795 CoordinatedVideoAdapter::UPGRADE);
796 EXPECT_EQ(480, adapter.output_format().width);
797 EXPECT_EQ(300, adapter.output_format().height);
798
799 // Server format request 640x400. Constrained by CPU.
800 format.width = 640;
801 format.height = 400;
802 adapter.OnOutputFormatRequest(format);
803 EXPECT_EQ(480, adapter.output_format().width);
804 EXPECT_EQ(300, adapter.output_format().height);
805}
806
807TEST(CoordinatedVideoAdapterTest, TestViewRequestPlusCameraSwitch) {
808 CoordinatedVideoAdapter adapter;
809 adapter.set_view_switch(true);
810
811 // Start at HD.
812 VideoFormat format(1280, 720, VideoFormat::FpsToInterval(30), FOURCC_I420);
813 adapter.SetInputFormat(format);
814 EXPECT_EQ(format, adapter.input_format());
815 EXPECT_TRUE(adapter.output_format().IsSize0x0());
816
817 // View request for VGA.
818 format.width = 640;
819 format.height = 360;
820 adapter.OnOutputFormatRequest(format);
821 EXPECT_EQ(640, adapter.output_format().width);
822 EXPECT_EQ(360, adapter.output_format().height);
823 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_VIEW, adapter.adapt_reason());
824
825 // Now, the camera reopens at VGA.
826 // Both the frame and the output format should be 640x360.
827 WebRtcVideoFrame in_frame;
828 in_frame.InitToBlack(640, 360, 1, 1, 33, 33);
829 VideoFrame* out_frame;
830 adapter.AdaptFrame(&in_frame, &out_frame);
831 EXPECT_EQ(640u, out_frame->GetWidth());
832 EXPECT_EQ(360u, out_frame->GetHeight());
833 // At this point, the view is no longer adapted, since the input has resized
834 // small enough to fit the last view request.
835 EXPECT_EQ(0, adapter.adapt_reason());
836
837 // And another view request comes in for 640x360, which should have no
838 // real impact.
839 adapter.OnOutputFormatRequest(format);
840 EXPECT_EQ(640, adapter.output_format().width);
841 EXPECT_EQ(360, adapter.output_format().height);
842 EXPECT_EQ(0, adapter.adapt_reason());
843}
844
845TEST(CoordinatedVideoAdapterTest, TestVGAWidth) {
846 CoordinatedVideoAdapter adapter;
847 adapter.set_view_switch(true);
848
849 // Start at 640x480, for cameras that don't support 640x360.
850 VideoFormat format(640, 480, VideoFormat::FpsToInterval(30), FOURCC_I420);
851 adapter.SetInputFormat(format);
852 EXPECT_EQ(format, adapter.input_format());
853 EXPECT_TRUE(adapter.output_format().IsSize0x0());
854
855 // Output format is 640x360, though.
856 format.width = 640;
857 format.height = 360;
858 adapter.SetOutputFormat(format);
859
860 // And also a view request comes for 640x360.
861 adapter.OnOutputFormatRequest(format);
862 // At this point, we have to adapt down to something lower.
863 EXPECT_EQ(480, adapter.output_format().width);
864 EXPECT_EQ(360, adapter.output_format().height);
865
866 // But if frames come in at 640x360, we shouldn't adapt them down.
867 // Fake a 640x360 frame.
868 WebRtcVideoFrame in_frame;
869 in_frame.InitToBlack(640, 360, 1, 1, 33, 33);
870 VideoFrame* out_frame;
871 adapter.AdaptFrame(&in_frame, &out_frame);
872
873 EXPECT_EQ(640u, out_frame->GetWidth());
874 EXPECT_EQ(360u, out_frame->GetHeight());
875
876 // Similarly, no-op adapt requests for other reasons shouldn't change
877 // adaptation state (before a previous bug, the previous EXPECTs would
878 // fail and the following would succeed, as the no-op CPU request would
879 // fix the adaptation state).
880 adapter.set_cpu_adaptation(true);
881 UpdateCpuLoad(&adapter, 1, 1, 0.7f, 0.7f);
882 adapter.AdaptFrame(&in_frame, &out_frame);
883
884 EXPECT_EQ(640u, out_frame->GetWidth());
885 EXPECT_EQ(360u, out_frame->GetHeight());
886}
887
888// When adapting resolution for CPU or GD, the quantity of pixels that the
889// request is based on is reduced to half or double, and then an actual
890// resolution is snapped to, rounding to the closest actual resolution.
891// This works well for some tolerance to 3/4, odd widths and aspect ratios
892// that dont exactly match, but is not best behavior for ViewRequests which
893// need to be be strictly respected to avoid going over the resolution budget
894// given to the codec - 854x480 total pixels.
895// ViewRequest must find a lower resolution.
896TEST(CoordinatedVideoAdapterTest, TestCoordinatedViewRequestDown) {
897 CoordinatedVideoAdapter adapter;
898 adapter.set_cpu_adaptation(false);
899
900 VideoFormat format(960, 540, VideoFormat::FpsToInterval(30), FOURCC_I420);
901 adapter.SetInputFormat(format);
902 adapter.set_scale_third(true);
903 EXPECT_EQ(format, adapter.input_format());
904 EXPECT_TRUE(adapter.output_format().IsSize0x0());
905
906 // Server format request 640x400. Expect HVGA.
907 format.width = 640;
908 format.height = 400;
909 adapter.OnOutputFormatRequest(format);
910 EXPECT_EQ(640, adapter.output_format().width);
911 EXPECT_EQ(360, adapter.output_format().height);
912
913 // Test reason for adapting is VIEW.
914 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_VIEW, adapter.adapt_reason());
915}
916
917// Test that we downgrade video for cpu up to two times.
918TEST(CoordinatedVideoAdapterTest, TestCpuDowngradeTimes) {
919 CoordinatedVideoAdapter adapter;
920 adapter.set_cpu_adaptation(true);
921 EXPECT_FALSE(adapter.cpu_smoothing());
922 VideoFormat format(640, 400, VideoFormat::FpsToInterval(30), FOURCC_I420);
923 adapter.SetInputFormat(format);
924
925 // Server format request 640x400.
926 format.height = 400;
927 adapter.OnOutputFormatRequest(format);
928 EXPECT_EQ(640, adapter.output_format().width);
929 EXPECT_EQ(400, adapter.output_format().height);
930
931 // Process load and system load are low. Do not change the cpu desired format
932 // and do not adapt.
933 adapter.OnCpuLoadUpdated(1, 1, 0.2f, 0.3f);
934 EXPECT_EQ(640, adapter.output_format().width);
935 EXPECT_EQ(400, adapter.output_format().height);
936
937 // System load is high. Downgrade.
938 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
939 EXPECT_EQ(480, adapter.output_format().width);
940 EXPECT_EQ(300, adapter.output_format().height);
941
942 // System load is high. Downgrade again.
943 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
944 EXPECT_EQ(320, adapter.output_format().width);
945 EXPECT_EQ(200, adapter.output_format().height);
946
947 // System load is still high. Do not downgrade any more.
948 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
949 EXPECT_EQ(320, adapter.output_format().width);
950 EXPECT_EQ(200, adapter.output_format().height);
951
952 // Process load and system load are low. Upgrade.
953 UpdateCpuLoad(&adapter, 1, 1, 0.2f, 0.3f);
954 EXPECT_EQ(480, adapter.output_format().width);
955 EXPECT_EQ(300, adapter.output_format().height);
956
957 // System load is high. Downgrade.
958 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
959 EXPECT_EQ(320, adapter.output_format().width);
960 EXPECT_EQ(200, adapter.output_format().height);
961
962 // System load is still high. Do not downgrade any more.
963 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
964 EXPECT_EQ(320, adapter.output_format().width);
965 EXPECT_EQ(200, adapter.output_format().height);
966}
967
968// Test that we respect CPU adapter threshold values.
969TEST(CoordinatedVideoAdapterTest, TestAdapterCpuThreshold) {
970 CoordinatedVideoAdapter adapter;
971 adapter.set_cpu_adaptation(true);
972 EXPECT_FALSE(adapter.cpu_smoothing());
973 VideoFormat format(640, 400, VideoFormat::FpsToInterval(30), FOURCC_I420);
974 adapter.SetInputFormat(format);
975
976 // Server format request 640x400.
977 format.height = 400;
978 adapter.OnOutputFormatRequest(format);
979 EXPECT_EQ(640, adapter.output_format().width);
980 EXPECT_EQ(400, adapter.output_format().height);
981
982 // Process load and system load are low. Do not change the cpu desired format
983 // and do not adapt.
984 adapter.OnCpuLoadUpdated(1, 1, 0.2f, 0.3f);
985 EXPECT_EQ(640, adapter.output_format().width);
986 EXPECT_EQ(400, adapter.output_format().height);
987
988 // System load is high. Downgrade.
989 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
990 EXPECT_EQ(480, adapter.output_format().width);
991 EXPECT_EQ(300, adapter.output_format().height);
992
993 // Test reason for adapting is CPU.
994 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_CPU, adapter.adapt_reason());
995
996 // System load is high. Normally downgrade but threshold is high. Do nothing.
997 adapter.set_high_system_threshold(0.98f); // Set threshold high.
998 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
999 EXPECT_EQ(480, adapter.output_format().width);
1000 EXPECT_EQ(300, adapter.output_format().height);
1001
1002 // System load is medium. Normally do nothing, threshold is low. Adapt down.
1003 adapter.set_high_system_threshold(0.75f); // Set threshold low.
1004 UpdateCpuLoad(&adapter, 1, 1, 0.8f, 0.8f);
1005 EXPECT_EQ(320, adapter.output_format().width);
1006 EXPECT_EQ(200, adapter.output_format().height);
1007}
1008
1009
1010// Test that for an upgrade cpu request, we actually upgrade the desired format;
1011// for a downgrade request, we downgrade from the output format.
1012TEST(CoordinatedVideoAdapterTest, TestRealCpuUpgrade) {
1013 CoordinatedVideoAdapter adapter;
1014 adapter.set_cpu_adaptation(true);
1015 adapter.set_cpu_smoothing(true);
1016 VideoFormat format(640, 400, VideoFormat::FpsToInterval(30), FOURCC_I420);
1017 adapter.SetInputFormat(format);
1018
1019 // Server format request 640x400.
1020 format.width = 640;
1021 format.height = 400;
1022 adapter.OnOutputFormatRequest(format);
1023 EXPECT_EQ(640, adapter.output_format().width);
1024 EXPECT_EQ(400, adapter.output_format().height);
1025
1026 // Process load and system load are low. Do not change the cpu desired format
1027 // and do not adapt.
1028 UpdateCpuLoad(&adapter, 1, 1, 0.2f, 0.3f);
1029 EXPECT_EQ(640, adapter.output_format().width);
1030 EXPECT_EQ(400, adapter.output_format().height);
1031
1032 // Server format request 320x200.
1033 format.width = 320;
1034 format.height = 200;
1035 adapter.OnOutputFormatRequest(format);
1036 EXPECT_EQ(320, adapter.output_format().width);
1037 EXPECT_EQ(200, adapter.output_format().height);
1038
1039 // Process load and system load are low. Do not change the cpu desired format
1040 // and do not adapt.
1041 UpdateCpuLoad(&adapter, 1, 1, 0.2f, 0.3f);
1042 EXPECT_EQ(320, adapter.output_format().width);
1043 EXPECT_EQ(200, adapter.output_format().height);
1044
1045 // Server format request 640x400. Set to 640x400 immediately.
1046 format.width = 640;
1047 format.height = 400;
1048 adapter.OnOutputFormatRequest(format);
1049 EXPECT_EQ(640, adapter.output_format().width);
1050 EXPECT_EQ(400, adapter.output_format().height);
1051
1052 // Server format request 320x200.
1053 format.width = 320;
1054 format.height = 200;
1055 adapter.OnOutputFormatRequest(format);
1056 EXPECT_EQ(320, adapter.output_format().width);
1057 EXPECT_EQ(200, adapter.output_format().height);
1058
1059 // Process load is high, but system is not. Do not change the cpu desired
1060 // format and do not adapt.
1061 for (size_t i = 0; i < 10; ++i) {
1062 UpdateCpuLoad(&adapter, 1, 1, 0.75f, 0.8f);
1063 }
1064 EXPECT_EQ(320, adapter.output_format().width);
1065 EXPECT_EQ(200, adapter.output_format().height);
1066}
1067
1068// Test that for an upgrade encoder request, we actually upgrade the desired
1069// format; for a downgrade request, we downgrade from the output format.
1070TEST(CoordinatedVideoAdapterTest, TestRealEncoderUpgrade) {
1071 CoordinatedVideoAdapter adapter;
1072 adapter.set_cpu_adaptation(true);
1073 adapter.set_cpu_smoothing(true);
1074 VideoFormat format(640, 400, VideoFormat::FpsToInterval(30), FOURCC_I420);
1075 adapter.SetInputFormat(format);
1076
1077 // Server format request 640x400.
1078 format.width = 640;
1079 format.height = 400;
1080 adapter.OnOutputFormatRequest(format);
1081 EXPECT_EQ(640, adapter.output_format().width);
1082 EXPECT_EQ(400, adapter.output_format().height);
1083
1084 // Encoder resolution request. Do not change the encoder desired format and
1085 // do not adapt.
1086 adapter.OnEncoderResolutionRequest(640, 400,
1087 CoordinatedVideoAdapter::UPGRADE);
1088 EXPECT_EQ(640, adapter.output_format().width);
1089 EXPECT_EQ(400, adapter.output_format().height);
1090
1091 // Server format request 320x200.
1092 format.width = 320;
1093 format.height = 200;
1094 adapter.OnOutputFormatRequest(format);
1095 EXPECT_EQ(320, adapter.output_format().width);
1096 EXPECT_EQ(200, adapter.output_format().height);
1097
1098 // Encoder resolution request. Do not change the encoder desired format and
1099 // do not adapt.
1100 adapter.OnEncoderResolutionRequest(320, 200,
1101 CoordinatedVideoAdapter::UPGRADE);
1102 EXPECT_EQ(320, adapter.output_format().width);
1103 EXPECT_EQ(200, adapter.output_format().height);
1104
1105 // Server format request 640x400. Set to 640x400 immediately.
1106 format.width = 640;
1107 format.height = 400;
1108 adapter.OnOutputFormatRequest(format);
1109 EXPECT_EQ(480, adapter.output_format().width);
1110 EXPECT_EQ(300, adapter.output_format().height);
1111
1112 // Test reason for adapting is BANDWIDTH.
1113 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_BANDWIDTH,
1114 adapter.adapt_reason());
1115
1116 // Server format request 320x200.
1117 format.width = 320;
1118 format.height = 200;
1119 adapter.OnOutputFormatRequest(format);
1120 EXPECT_EQ(320, adapter.output_format().width);
1121 EXPECT_EQ(200, adapter.output_format().height);
1122
1123 // Encoder resolution request. Downgrade from 320x200.
1124 adapter.OnEncoderResolutionRequest(320, 200,
1125 CoordinatedVideoAdapter::DOWNGRADE);
1126 EXPECT_EQ(240, adapter.output_format().width);
1127 EXPECT_EQ(150, adapter.output_format().height);
1128}
1129
1130TEST(CoordinatedVideoAdapterTest, TestNormalizeOutputFormat) {
1131 CoordinatedVideoAdapter adapter;
1132 // The input format is 640x360 and the output is limited to 16:9.
1133 VideoFormat format(640, 360, VideoFormat::FpsToInterval(30), FOURCC_I420);
1134 adapter.SetInputFormat(format);
1135
1136 format.width = 320;
1137 format.height = 180;
1138 format.interval = VideoFormat::FpsToInterval(15);
1139 adapter.OnOutputFormatRequest(format);
1140 EXPECT_EQ(320, adapter.output_format().width);
1141 EXPECT_EQ(180, adapter.output_format().height);
1142 EXPECT_EQ(VideoFormat::FpsToInterval(15), adapter.output_format().interval);
1143
1144 format.width = 320;
1145 format.height = 200;
1146 format.interval = VideoFormat::FpsToInterval(40);
1147 adapter.OnOutputFormatRequest(format);
1148 EXPECT_EQ(320, adapter.output_format().width);
1149 EXPECT_EQ(180, adapter.output_format().height);
1150 EXPECT_EQ(VideoFormat::FpsToInterval(30), adapter.output_format().interval);
1151
1152 // Test reason for adapting is VIEW. Should work even with normalization.
1153 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_VIEW,
1154 adapter.adapt_reason());
1155
1156 format.width = 320;
1157 format.height = 240;
1158 adapter.OnOutputFormatRequest(format);
1159 EXPECT_EQ(320, adapter.output_format().width);
1160 EXPECT_EQ(180, adapter.output_format().height);
1161
1162 // The input format is 640x480 and the output will be 4:3.
1163 format.width = 640;
1164 format.height = 480;
1165 adapter.SetInputFormat(format);
1166 EXPECT_EQ(320, adapter.output_format().width);
1167 EXPECT_EQ(240, adapter.output_format().height);
1168
1169 format.width = 320;
1170 format.height = 240;
1171 adapter.OnOutputFormatRequest(format);
1172 EXPECT_EQ(320, adapter.output_format().width);
1173 EXPECT_EQ(240, adapter.output_format().height);
1174
1175 // The input format is initialized after the output. At that time, the output
1176 // height is adjusted.
1177 format.width = 0;
1178 format.height = 0;
1179 adapter.SetInputFormat(format);
1180
1181 format.width = 320;
1182 format.height = 240;
1183 format.interval = VideoFormat::FpsToInterval(30);
1184 adapter.OnOutputFormatRequest(format);
1185 EXPECT_EQ(320, adapter.output_format().width);
1186 EXPECT_EQ(240, adapter.output_format().height);
1187 EXPECT_EQ(VideoFormat::FpsToInterval(30), adapter.output_format().interval);
1188
1189 format.width = 640;
1190 format.height = 480;
1191 format.interval = VideoFormat::FpsToInterval(15);
1192 adapter.SetInputFormat(format);
1193 EXPECT_EQ(320, adapter.output_format().width);
1194 EXPECT_EQ(240, adapter.output_format().height);
1195 EXPECT_EQ(VideoFormat::FpsToInterval(15), adapter.output_format().interval);
1196}
1197
1198// Test that we downgrade video for cpu up to two times.
1199TEST_F(VideoAdapterTest, CpuDowngradeAndSignal) {
1200 CoordinatedVideoAdapter adapter;
1201 CpuAdapterListener cpu_listener;
1202 adapter.SignalCpuAdaptationUnable.connect(
1203 &cpu_listener, &CpuAdapterListener::OnCpuAdaptationSignalled);
1204
1205 adapter.set_cpu_adaptation(true);
1206 EXPECT_FALSE(adapter.cpu_smoothing());
1207 VideoFormat format(640, 360, VideoFormat::FpsToInterval(30), FOURCC_I420);
1208 adapter.SetInputFormat(format);
1209 adapter.OnOutputFormatRequest(format);
1210
1211 // System load is high. Downgrade.
1212 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
1213
1214 // System load is high. Downgrade again.
1215 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
1216
1217 // System load is still high. Do not downgrade any more. Ensure we have not
1218 // signalled until after the cpu warning though.
1219 EXPECT_TRUE(!cpu_listener.received_cpu_signal());
1220 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
1221 EXPECT_TRUE_WAIT(cpu_listener.received_cpu_signal(), kWaitTimeout);
1222}
1223
1224// Test that we downgrade video for cpu up to two times.
1225TEST_F(VideoAdapterTest, CpuDowngradeAndDontSignal) {
1226 CoordinatedVideoAdapter adapter;
1227 CpuAdapterListener cpu_listener;
1228 adapter.SignalCpuAdaptationUnable.connect(
1229 &cpu_listener, &CpuAdapterListener::OnCpuAdaptationSignalled);
1230
1231 adapter.set_cpu_adaptation(true);
1232 adapter.set_cpu_smoothing(true);
1233 VideoFormat format(640, 360, VideoFormat::FpsToInterval(30), FOURCC_I420);
1234 adapter.SetInputFormat(format);
1235 adapter.OnOutputFormatRequest(format);
1236
1237 // System load is high. Downgrade.
1238 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
1239
1240 // System load is high, process is not, Do not downgrade again.
1241 UpdateCpuLoad(&adapter, 1, 1, 0.25f, 0.95f);
1242
1243 // System load is high, process is not, Do not downgrade again and do not
1244 // signal.
1245 adapter.set_cpu_adaptation(false);
1246 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
1247 rtc::Thread::Current()->ProcessMessages(kShortWaitTimeout);
1248 EXPECT_TRUE(!cpu_listener.received_cpu_signal());
1249 adapter.set_cpu_adaptation(true);
1250}
1251
1252// Test that we require enough time before we downgrade.
1253TEST_F(VideoAdapterTest, CpuMinTimeRequirement) {
1254 CoordinatedVideoAdapter adapter;
1255 CpuAdapterListener cpu_listener;
1256 adapter.SignalCpuAdaptationUnable.connect(
1257 &cpu_listener, &CpuAdapterListener::OnCpuAdaptationSignalled);
1258
1259 adapter.set_cpu_adaptation(true);
1260 adapter.set_cpu_smoothing(true);
1261 VideoFormat format(640, 360, VideoFormat::FpsToInterval(30), FOURCC_I420);
1262 adapter.SetInputFormat(format);
1263 adapter.OnOutputFormatRequest(format);
1264
1265 EXPECT_EQ(3, adapter.cpu_load_min_samples());
1266 adapter.set_cpu_load_min_samples(5);
1267
1268 for (size_t i = 0; i < 4; ++i) {
1269 adapter.OnCpuLoadUpdated(1, 1, 1.0f, 1.0f);
1270 EXPECT_EQ(640, adapter.output_format().width);
1271 EXPECT_EQ(360, adapter.output_format().height);
1272 }
1273 // The computed cpu load should now be around 93.5%, with the coefficient of
1274 // 0.4 and a seed value of 0.5. That should be high enough to adapt, but it
1275 // isn't enough samples, so we shouldn't have adapted on any of the previous
1276 // samples.
1277
1278 // One more sample is enough, though, once enough time has passed.
1279 adapter.OnCpuLoadUpdated(1, 1, 1.0f, 1.0f);
1280 EXPECT_EQ(480, adapter.output_format().width);
1281 EXPECT_EQ(270, adapter.output_format().height);
1282
1283 // Now the cpu is lower, but we still need enough samples to upgrade.
1284 for (size_t i = 0; i < 4; ++i) {
1285 adapter.OnCpuLoadUpdated(1, 1, 0.1f, 0.1f);
1286 EXPECT_EQ(480, adapter.output_format().width);
1287 EXPECT_EQ(270, adapter.output_format().height);
1288 }
1289
1290 // One more sample is enough, once time has elapsed.
1291 adapter.OnCpuLoadUpdated(1, 1, 1.0f, 1.0f);
1292 EXPECT_EQ(640, adapter.output_format().width);
1293 EXPECT_EQ(360, adapter.output_format().height);
1294}
1295
1296TEST_F(VideoAdapterTest, CpuIgnoresSpikes) {
1297 CoordinatedVideoAdapter adapter;
1298 CpuAdapterListener cpu_listener;
1299 adapter.SignalCpuAdaptationUnable.connect(
1300 &cpu_listener, &CpuAdapterListener::OnCpuAdaptationSignalled);
1301
1302 adapter.set_cpu_adaptation(true);
1303 adapter.set_cpu_smoothing(true);
1304 VideoFormat format(640, 360, VideoFormat::FpsToInterval(30), FOURCC_I420);
1305 adapter.SetInputFormat(format);
1306 adapter.OnOutputFormatRequest(format);
1307
1308 // System load is high. Downgrade.
1309 for (size_t i = 0; i < 5; ++i) {
1310 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
1311 }
1312 EXPECT_EQ(480, adapter.output_format().width);
1313 EXPECT_EQ(270, adapter.output_format().height);
1314
1315 // Now we're in a state where we could upgrade or downgrade, so get to a
1316 // steady state of about 75% cpu usage.
1317 for (size_t i = 0; i < 5; ++i) {
1318 UpdateCpuLoad(&adapter, 1, 1, 0.75f, 0.75f);
1319 EXPECT_EQ(480, adapter.output_format().width);
1320 EXPECT_EQ(270, adapter.output_format().height);
1321 }
1322
1323 // Now, the cpu spikes for two samples, but then goes back to
1324 // normal. This shouldn't cause adaptation.
1325 UpdateCpuLoad(&adapter, 1, 1, 0.90f, 0.90f);
1326 UpdateCpuLoad(&adapter, 1, 1, 0.90f, 0.90f);
1327 EXPECT_EQ(480, adapter.output_format().width);
1328 EXPECT_EQ(270, adapter.output_format().height);
1329 // Back to the steady state for awhile.
1330 for (size_t i = 0; i < 5; ++i) {
1331 UpdateCpuLoad(&adapter, 1, 1, 0.75, 0.75);
1332 EXPECT_EQ(480, adapter.output_format().width);
1333 EXPECT_EQ(270, adapter.output_format().height);
1334 }
1335
1336 // Now, system cpu usage is starting to drop down. But it takes a bit before
1337 // it gets all the way there.
1338 for (size_t i = 0; i < 10; ++i) {
1339 UpdateCpuLoad(&adapter, 1, 1, 0.5f, 0.5f);
1340 }
1341 EXPECT_EQ(640, adapter.output_format().width);
1342 EXPECT_EQ(360, adapter.output_format().height);
1343}
1344
1345} // namespace cricket
1346#endif // HAVE_WEBRTC_VIDEO