1 /*
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
34 #include "talk/media/base/fakevideocapturer.h"
35 #include "talk/media/base/mediachannel.h"
36 #include "talk/media/base/testutils.h"
37 #include "talk/media/base/videoadapter.h"
38 #include "webrtc/base/gunit.h"
39 #include "webrtc/base/logging.h"
40 #include "webrtc/base/sigslot.h"
41
42 namespace cricket {
43
44 namespace {
45 static const uint32_t kWaitTimeout = 3000U; // 3 seconds.
46 static const uint32_t kShortWaitTimeout = 1000U; // 1 second.
UpdateCpuLoad(CoordinatedVideoAdapter * adapter,int current_cpus,int max_cpus,float process_load,float system_load)47 void UpdateCpuLoad(CoordinatedVideoAdapter* adapter,
48 int current_cpus, int max_cpus, float process_load, float system_load) {
49 adapter->set_cpu_load_min_samples(1);
50 adapter->OnCpuLoadUpdated(current_cpus, max_cpus,
51 process_load, system_load);
52 }
53 }
54
55 class VideoAdapterTest : public testing::Test {
56 public:
SetUp()57 virtual void SetUp() {
58 capturer_.reset(new FakeVideoCapturer);
59 capture_format_ = capturer_->GetSupportedFormats()->at(0);
60 capture_format_.interval = VideoFormat::FpsToInterval(50);
61 adapter_.reset(new VideoAdapter());
62 adapter_->SetInputFormat(capture_format_);
63
64 listener_.reset(new VideoCapturerListener(adapter_.get()));
65 capturer_->SignalFrameCaptured.connect(
66 listener_.get(), &VideoCapturerListener::OnFrameCaptured);
67 }
68
TearDown()69 virtual void TearDown() {
70 // Explicitly disconnect the VideoCapturer before to avoid data races
71 // (frames delivered to VideoCapturerListener while it's being destructed).
72 capturer_->SignalFrameCaptured.disconnect_all();
73 }
74
75 protected:
76 class VideoCapturerListener: public sigslot::has_slots<> {
77 public:
78 struct Stats {
79 int captured_frames;
80 int dropped_frames;
81 bool last_adapt_was_no_op;
82
83 int adapted_width;
84 int adapted_height;
85 };
86
VideoCapturerListener(VideoAdapter * adapter)87 explicit VideoCapturerListener(VideoAdapter* adapter)
88 : video_adapter_(adapter),
89 captured_frames_(0),
90 dropped_frames_(0),
91 last_adapt_was_no_op_(false) {
92 }
93
OnFrameCaptured(VideoCapturer * capturer,const CapturedFrame * captured_frame)94 void OnFrameCaptured(VideoCapturer* capturer,
95 const CapturedFrame* captured_frame) {
96 rtc::CritScope lock(&crit_);
97 const int in_width = captured_frame->width;
98 const int in_height = abs(captured_frame->height);
99 const VideoFormat adapted_format =
100 video_adapter_->AdaptFrameResolution(in_width, in_height);
101 if (!adapted_format.IsSize0x0()) {
102 adapted_format_ = adapted_format;
103 last_adapt_was_no_op_ = (in_width == adapted_format.width &&
104 in_height == adapted_format.height);
105 } else {
106 ++dropped_frames_;
107 }
108 ++captured_frames_;
109 }
110
GetStats()111 Stats GetStats() {
112 rtc::CritScope lock(&crit_);
113 Stats stats;
114 stats.captured_frames = captured_frames_;
115 stats.dropped_frames = dropped_frames_;
116 stats.last_adapt_was_no_op = last_adapt_was_no_op_;
117 if (!adapted_format_.IsSize0x0()) {
118 stats.adapted_width = adapted_format_.width;
119 stats.adapted_height = adapted_format_.height;
120 } else {
121 stats.adapted_width = stats.adapted_height = -1;
122 }
123
124 return stats;
125 }
126
127 private:
128 rtc::CriticalSection crit_;
129 VideoAdapter* video_adapter_;
130 VideoFormat adapted_format_;
131 int captured_frames_;
132 int dropped_frames_;
133 bool last_adapt_was_no_op_;
134 };
135
136 class CpuAdapterListener: public sigslot::has_slots<> {
137 public:
CpuAdapterListener()138 CpuAdapterListener() : received_cpu_signal_(false) {}
OnCpuAdaptationSignalled()139 void OnCpuAdaptationSignalled() { received_cpu_signal_ = true; }
received_cpu_signal()140 bool received_cpu_signal() { return received_cpu_signal_; }
141 private:
142 bool received_cpu_signal_;
143 };
144
VerifyAdaptedResolution(const VideoCapturerListener::Stats & stats,int width,int height)145 void VerifyAdaptedResolution(const VideoCapturerListener::Stats& stats,
146 int width,
147 int height) {
148 EXPECT_EQ(width, stats.adapted_width);
149 EXPECT_EQ(height, stats.adapted_height);
150 }
151
152 rtc::scoped_ptr<FakeVideoCapturer> capturer_;
153 rtc::scoped_ptr<VideoAdapter> adapter_;
154 rtc::scoped_ptr<VideoCapturerListener> listener_;
155 VideoFormat capture_format_;
156 };
157
158
159 // Test adapter remembers exact pixel count
TEST_F(VideoAdapterTest,AdaptNumPixels)160 TEST_F(VideoAdapterTest, AdaptNumPixels) {
161 adapter_->SetOutputNumPixels(123456);
162 EXPECT_EQ(123456, adapter_->GetOutputNumPixels());
163 }
164
165 // Test adapter is constructed but not activated. Expect no frame drop and no
166 // resolution change.
TEST_F(VideoAdapterTest,AdaptInactive)167 TEST_F(VideoAdapterTest, AdaptInactive) {
168 // Output resolution is not set.
169 EXPECT_EQ(INT_MAX, adapter_->GetOutputNumPixels());
170
171 // Call Adapter with some frames.
172 EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
173 for (int i = 0; i < 10; ++i)
174 capturer_->CaptureFrame();
175
176 // Verify no frame drop and no resolution change.
177 VideoCapturerListener::Stats stats = listener_->GetStats();
178 EXPECT_GE(stats.captured_frames, 10);
179 EXPECT_EQ(0, stats.dropped_frames);
180 VerifyAdaptedResolution(stats, capture_format_.width, capture_format_.height);
181 }
182
183 // Do not adapt the frame rate or the resolution. Expect no frame drop and no
184 // resolution change.
TEST_F(VideoAdapterTest,AdaptNothing)185 TEST_F(VideoAdapterTest, AdaptNothing) {
186 adapter_->SetOutputFormat(capture_format_);
187 EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
188 for (int i = 0; i < 10; ++i)
189 capturer_->CaptureFrame();
190
191 // Verify no frame drop and no resolution change.
192 VideoCapturerListener::Stats stats = listener_->GetStats();
193 EXPECT_GE(stats.captured_frames, 10);
194 EXPECT_EQ(0, stats.dropped_frames);
195 VerifyAdaptedResolution(stats, capture_format_.width, capture_format_.height);
196 EXPECT_TRUE(stats.last_adapt_was_no_op);
197 }
198
TEST_F(VideoAdapterTest,AdaptZeroInterval)199 TEST_F(VideoAdapterTest, AdaptZeroInterval) {
200 VideoFormat format = capturer_->GetSupportedFormats()->at(0);
201 format.interval = 0;
202 adapter_->SetInputFormat(format);
203 adapter_->SetOutputFormat(format);
204 EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
205 for (int i = 0; i < 10; ++i)
206 capturer_->CaptureFrame();
207
208 // Verify no crash and that frames aren't dropped.
209 VideoCapturerListener::Stats stats = listener_->GetStats();
210 EXPECT_GE(stats.captured_frames, 10);
211 EXPECT_EQ(0, stats.dropped_frames);
212 VerifyAdaptedResolution(stats, capture_format_.width, capture_format_.height);
213 }
214
215 // Adapt the frame rate to be half of the capture rate at the beginning. Expect
216 // the number of dropped frames to be half of the number the captured frames.
TEST_F(VideoAdapterTest,AdaptFramerate)217 TEST_F(VideoAdapterTest, AdaptFramerate) {
218 VideoFormat request_format = capture_format_;
219 request_format.interval *= 2;
220 adapter_->SetOutputFormat(request_format);
221 EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
222 for (int i = 0; i < 10; ++i)
223 capturer_->CaptureFrame();
224
225 // Verify frame drop and no resolution change.
226 VideoCapturerListener::Stats stats = listener_->GetStats();
227 EXPECT_GE(stats.captured_frames, 10);
228 EXPECT_EQ(stats.captured_frames / 2, stats.dropped_frames);
229 VerifyAdaptedResolution(stats, capture_format_.width, capture_format_.height);
230 }
231
232 // Adapt the frame rate to be half of the capture rate at the beginning. Expect
233 // the number of dropped frames to be half of the number the captured frames.
TEST_F(VideoAdapterTest,AdaptFramerateVariable)234 TEST_F(VideoAdapterTest, AdaptFramerateVariable) {
235 VideoFormat request_format = capture_format_;
236 request_format.interval = request_format.interval * 3 / 2;
237 adapter_->SetOutputFormat(request_format);
238 EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
239 for (int i = 0; i < 30; ++i)
240 capturer_->CaptureFrame();
241
242 // Verify frame drop and no resolution change.
243 VideoCapturerListener::Stats stats = listener_->GetStats();
244 EXPECT_GE(stats.captured_frames, 30);
245 // Verify 2 / 3 kept (20) and 1 / 3 dropped (10).
246 EXPECT_EQ(stats.captured_frames * 1 / 3, stats.dropped_frames);
247 VerifyAdaptedResolution(stats, capture_format_.width, capture_format_.height);
248 }
249
250 // Adapt the frame rate to be half of the capture rate after capturing no less
251 // than 10 frames. Expect no frame dropped before adaptation and frame dropped
252 // after adaptation.
TEST_F(VideoAdapterTest,AdaptFramerateOntheFly)253 TEST_F(VideoAdapterTest, AdaptFramerateOntheFly) {
254 VideoFormat request_format = capture_format_;
255 adapter_->SetOutputFormat(request_format);
256 EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
257 for (int i = 0; i < 10; ++i)
258 capturer_->CaptureFrame();
259
260 // Verify no frame drop before adaptation.
261 EXPECT_EQ(0, listener_->GetStats().dropped_frames);
262
263 // Adapat the frame rate.
264 request_format.interval *= 2;
265 adapter_->SetOutputFormat(request_format);
266
267 for (int i = 0; i < 20; ++i)
268 capturer_->CaptureFrame();
269
270 // Verify frame drop after adaptation.
271 EXPECT_GT(listener_->GetStats().dropped_frames, 0);
272 }
273
274 // Set a very high output pixel resolution. Expect no resolution change.
TEST_F(VideoAdapterTest,AdaptFrameResolutionHighLimit)275 TEST_F(VideoAdapterTest, AdaptFrameResolutionHighLimit) {
276 adapter_->SetOutputNumPixels(INT_MAX);
277 VideoFormat adapted_format = adapter_->AdaptFrameResolution(
278 capture_format_.width, capture_format_.height);
279 EXPECT_EQ(capture_format_.width, adapted_format.width);
280 EXPECT_EQ(capture_format_.height, adapted_format.height);
281
282 adapter_->SetOutputNumPixels(987654321);
283 adapted_format = capture_format_,
284 adapter_->AdaptFrameResolution(capture_format_.width, capture_format_.height);
285 EXPECT_EQ(capture_format_.width, adapted_format.width);
286 EXPECT_EQ(capture_format_.height, adapted_format.height);
287 }
288
289 // Adapt the frame resolution to be the same as capture resolution. Expect no
290 // resolution change.
TEST_F(VideoAdapterTest,AdaptFrameResolutionIdentical)291 TEST_F(VideoAdapterTest, AdaptFrameResolutionIdentical) {
292 adapter_->SetOutputFormat(capture_format_);
293 const VideoFormat adapted_format = adapter_->AdaptFrameResolution(
294 capture_format_.width, capture_format_.height);
295 EXPECT_EQ(capture_format_.width, adapted_format.width);
296 EXPECT_EQ(capture_format_.height, adapted_format.height);
297 }
298
299 // Adapt the frame resolution to be a quarter of the capture resolution. Expect
300 // resolution change.
TEST_F(VideoAdapterTest,AdaptFrameResolutionQuarter)301 TEST_F(VideoAdapterTest, AdaptFrameResolutionQuarter) {
302 VideoFormat request_format = capture_format_;
303 request_format.width /= 2;
304 request_format.height /= 2;
305 adapter_->SetOutputFormat(request_format);
306 const VideoFormat adapted_format = adapter_->AdaptFrameResolution(
307 request_format.width, request_format.height);
308 EXPECT_EQ(request_format.width, adapted_format.width);
309 EXPECT_EQ(request_format.height, adapted_format.height);
310 }
311
312 // Adapt the pixel resolution to 0. Expect frame drop.
TEST_F(VideoAdapterTest,AdaptFrameResolutionDrop)313 TEST_F(VideoAdapterTest, AdaptFrameResolutionDrop) {
314 adapter_->SetOutputNumPixels(0);
315 EXPECT_TRUE(
316 adapter_->AdaptFrameResolution(capture_format_.width,
317 capture_format_.height).IsSize0x0());
318 }
319
320 // Adapt the frame resolution to be a quarter of the capture resolution at the
321 // beginning. Expect resolution change.
TEST_F(VideoAdapterTest,AdaptResolution)322 TEST_F(VideoAdapterTest, AdaptResolution) {
323 VideoFormat request_format = capture_format_;
324 request_format.width /= 2;
325 request_format.height /= 2;
326 adapter_->SetOutputFormat(request_format);
327 EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
328 for (int i = 0; i < 10; ++i)
329 capturer_->CaptureFrame();
330
331 // Verify no frame drop and resolution change.
332 VideoCapturerListener::Stats stats = listener_->GetStats();
333 EXPECT_EQ(0, stats.dropped_frames);
334 VerifyAdaptedResolution(stats, request_format.width, request_format.height);
335 }
336
337 // Adapt the frame resolution to half width. Expect resolution change.
TEST_F(VideoAdapterTest,AdaptResolutionNarrow)338 TEST_F(VideoAdapterTest, AdaptResolutionNarrow) {
339 VideoFormat request_format = capture_format_;
340 request_format.width /= 2;
341 adapter_->set_scale_third(true);
342 adapter_->SetOutputFormat(request_format);
343 EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
344 for (int i = 0; i < 10; ++i)
345 capturer_->CaptureFrame();
346
347 // Verify resolution change.
348 VerifyAdaptedResolution(listener_->GetStats(),
349 capture_format_.width * 2 / 3,
350 capture_format_.height * 2 / 3);
351 }
352
353 // Adapt the frame resolution to half height. Expect resolution change.
TEST_F(VideoAdapterTest,AdaptResolutionWide)354 TEST_F(VideoAdapterTest, AdaptResolutionWide) {
355 VideoFormat request_format = capture_format_;
356 request_format.height /= 2;
357 adapter_->set_scale_third(true);
358 adapter_->SetOutputFormat(request_format);
359 EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
360 for (int i = 0; i < 10; ++i)
361 capturer_->CaptureFrame();
362
363 // Verify resolution change.
364 VerifyAdaptedResolution(listener_->GetStats(),
365 capture_format_.width * 2 / 3,
366 capture_format_.height * 2 / 3);
367 }
368
369 // Adapt the frame resolution to be a quarter of the capture resolution after
370 // capturing no less than 10 frames. Expect no resolution change before
371 // adaptation and resolution change after adaptation.
TEST_F(VideoAdapterTest,AdaptResolutionOnTheFly)372 TEST_F(VideoAdapterTest, AdaptResolutionOnTheFly) {
373 VideoFormat request_format = capture_format_;
374 adapter_->SetOutputFormat(request_format);
375 EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
376 for (int i = 0; i < 10; ++i)
377 capturer_->CaptureFrame();
378
379 // Verify no resolution change before adaptation.
380 VerifyAdaptedResolution(
381 listener_->GetStats(), request_format.width, request_format.height);
382
383 // Adapt the frame resolution.
384 request_format.width /= 2;
385 request_format.height /= 2;
386 adapter_->SetOutputFormat(request_format);
387 for (int i = 0; i < 10; ++i)
388 capturer_->CaptureFrame();
389
390 // Verify resolution change after adaptation.
391 VerifyAdaptedResolution(
392 listener_->GetStats(), request_format.width, request_format.height);
393 }
394
395 // Drop all frames.
TEST_F(VideoAdapterTest,DropAllFrames)396 TEST_F(VideoAdapterTest, DropAllFrames) {
397 VideoFormat format; // with resolution 0x0.
398 adapter_->SetOutputFormat(format);
399 EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
400 for (int i = 0; i < 10; ++i)
401 capturer_->CaptureFrame();
402
403 // Verify all frames are dropped.
404 VideoCapturerListener::Stats stats = listener_->GetStats();
405 EXPECT_GE(stats.captured_frames, 10);
406 EXPECT_EQ(stats.captured_frames, stats.dropped_frames);
407 }
408
TEST(CoordinatedVideoAdapterTest,TestCoordinatedWithoutCpuAdaptation)409 TEST(CoordinatedVideoAdapterTest, TestCoordinatedWithoutCpuAdaptation) {
410 CoordinatedVideoAdapter adapter;
411 adapter.set_cpu_adaptation(false);
412
413 VideoFormat format(640, 400, VideoFormat::FpsToInterval(30), FOURCC_I420);
414 adapter.SetInputFormat(format);
415 adapter.set_scale_third(true);
416 EXPECT_EQ(format, adapter.input_format());
417 EXPECT_TRUE(adapter.output_format().IsSize0x0());
418
419 // Server format request 640x400.
420 format.height = 400;
421 adapter.OnOutputFormatRequest(format);
422 EXPECT_EQ(640, adapter.output_format().width);
423 EXPECT_EQ(400, adapter.output_format().height);
424
425 // Server format request 1280x720, higher than input. Adapt nothing.
426 format.width = 1280;
427 format.height = 720;
428 adapter.OnOutputFormatRequest(format);
429 EXPECT_EQ(640, adapter.output_format().width);
430 EXPECT_EQ(400, adapter.output_format().height);
431
432 // Cpu load is high, but cpu adaptation is disabled. Adapt nothing.
433 adapter.OnCpuLoadUpdated(1, 1, 0.99f, 0.99f);
434 EXPECT_EQ(640, adapter.output_format().width);
435 EXPECT_EQ(400, adapter.output_format().height);
436
437 // Encoder resolution request: downgrade with different size. Adapt nothing.
438 adapter.OnEncoderResolutionRequest(320, 200,
439 CoordinatedVideoAdapter::DOWNGRADE);
440 EXPECT_EQ(640, adapter.output_format().width);
441 EXPECT_EQ(400, adapter.output_format().height);
442
443 // Encoder resolution request: downgrade.
444 adapter.OnEncoderResolutionRequest(640, 400,
445 CoordinatedVideoAdapter::DOWNGRADE);
446 EXPECT_EQ(480, adapter.output_format().width);
447 EXPECT_EQ(300, adapter.output_format().height);
448
449 // Encoder resolution request: downgrade. But GD off. Adapt nothing.
450 adapter.set_gd_adaptation(false);
451 adapter.OnEncoderResolutionRequest(480, 300,
452 CoordinatedVideoAdapter::DOWNGRADE);
453 EXPECT_EQ(480, adapter.output_format().width);
454 EXPECT_EQ(300, adapter.output_format().height);
455 adapter.set_gd_adaptation(true);
456
457 // Encoder resolution request: downgrade.
458 adapter.OnEncoderResolutionRequest(480, 300,
459 CoordinatedVideoAdapter::DOWNGRADE);
460 EXPECT_EQ(320, adapter.output_format().width);
461 EXPECT_EQ(200, adapter.output_format().height);
462
463 // Encoder resolution request: keep. Adapt nothing.
464 adapter.OnEncoderResolutionRequest(320, 200,
465 CoordinatedVideoAdapter::KEEP);
466 EXPECT_EQ(320, adapter.output_format().width);
467 EXPECT_EQ(200, adapter.output_format().height);
468
469 // Encoder resolution request: upgrade.
470 adapter.OnEncoderResolutionRequest(320, 200,
471 CoordinatedVideoAdapter::UPGRADE);
472 EXPECT_EQ(480, adapter.output_format().width);
473 EXPECT_EQ(300, adapter.output_format().height);
474
475 // Server format request 0x0.
476 format.width = 0;
477 format.height = 0;
478 adapter.OnOutputFormatRequest(format);
479 EXPECT_TRUE(adapter.output_format().IsSize0x0());
480
481 // Server format request 320x200.
482 format.width = 320;
483 format.height = 200;
484 adapter.OnOutputFormatRequest(format);
485 EXPECT_EQ(320, adapter.output_format().width);
486 EXPECT_EQ(200, adapter.output_format().height);
487
488 // Server format request 160x100. But view disabled. Adapt nothing.
489 adapter.set_view_adaptation(false);
490 format.width = 160;
491 format.height = 100;
492 adapter.OnOutputFormatRequest(format);
493 EXPECT_EQ(320, adapter.output_format().width);
494 EXPECT_EQ(200, adapter.output_format().height);
495 adapter.set_view_adaptation(true);
496
497 // Enable View Switch. Expect adapt down.
498 adapter.set_view_switch(true);
499 format.width = 160;
500 format.height = 100;
501 adapter.OnOutputFormatRequest(format);
502 EXPECT_EQ(160, adapter.output_format().width);
503 EXPECT_EQ(100, adapter.output_format().height);
504
505 // Encoder resolution request: upgrade. Adapt nothing.
506 adapter.OnEncoderResolutionRequest(160, 100,
507 CoordinatedVideoAdapter::UPGRADE);
508 EXPECT_EQ(160, adapter.output_format().width);
509 EXPECT_EQ(100, adapter.output_format().height);
510
511 // Request View of 2 / 3. Expect adapt down.
512 adapter.set_view_switch(true);
513 format.width = (640 * 2 + 1) / 3;
514 format.height = (400 * 2 + 1) / 3;
515 adapter.OnOutputFormatRequest(format);
516 EXPECT_EQ((640 * 2 + 1) / 3, adapter.output_format().width);
517 EXPECT_EQ((400 * 2 + 1) / 3, adapter.output_format().height);
518
519
520 // Request View of 3 / 8. Expect adapt down.
521 adapter.set_view_switch(true);
522 format.width = 640 * 3 / 8;
523 format.height = 400 * 3 / 8;
524 adapter.OnOutputFormatRequest(format);
525 EXPECT_EQ(640 * 3 / 8, adapter.output_format().width);
526 EXPECT_EQ(400 * 3 / 8, adapter.output_format().height);
527
528 // View Switch back up. Expect adapt.
529 format.width = 320;
530 format.height = 200;
531 adapter.OnOutputFormatRequest(format);
532 EXPECT_EQ(320, adapter.output_format().width);
533 EXPECT_EQ(200, adapter.output_format().height);
534
535 adapter.set_view_switch(false);
536
537 // Encoder resolution request: upgrade. Constrained by server request.
538 adapter.OnEncoderResolutionRequest(320, 200,
539 CoordinatedVideoAdapter::UPGRADE);
540 EXPECT_EQ(320, adapter.output_format().width);
541 EXPECT_EQ(200, adapter.output_format().height);
542
543 // Server format request 480x300.
544 format.width = 480;
545 format.height = 300;
546 adapter.OnOutputFormatRequest(format);
547 EXPECT_EQ(480, adapter.output_format().width);
548 EXPECT_EQ(300, adapter.output_format().height);
549 }
550
TEST(CoordinatedVideoAdapterTest,TestCoordinatedWithCpuAdaptation)551 TEST(CoordinatedVideoAdapterTest, TestCoordinatedWithCpuAdaptation) {
552 CoordinatedVideoAdapter adapter;
553 adapter.set_cpu_adaptation(true);
554 EXPECT_FALSE(adapter.cpu_smoothing());
555 VideoFormat format(640, 400, VideoFormat::FpsToInterval(30), FOURCC_I420);
556 adapter.SetInputFormat(format);
557
558 // Server format request 640x400.
559 format.height = 400;
560 adapter.OnOutputFormatRequest(format);
561 EXPECT_EQ(640, adapter.output_format().width);
562 EXPECT_EQ(400, adapter.output_format().height);
563
564 // Process load is medium, but system load is high. Downgrade.
565 UpdateCpuLoad(&adapter, 1, 1, 0.55f, 0.98f);
566 EXPECT_EQ(480, adapter.output_format().width);
567 EXPECT_EQ(300, adapter.output_format().height);
568
569 // CPU high, but cpu adaptation disabled. Adapt nothing.
570 adapter.set_cpu_adaptation(false);
571 adapter.OnCpuLoadUpdated(1, 1, 0.55f, 0.98f);
572 EXPECT_EQ(480, adapter.output_format().width);
573 EXPECT_EQ(300, adapter.output_format().height);
574 adapter.set_cpu_adaptation(true);
575
576 // System load is high, but time has not elaspsed. Adapt nothing.
577 adapter.set_cpu_load_min_samples(2);
578 adapter.OnCpuLoadUpdated(1, 1, 0.55f, 0.98f);
579 EXPECT_EQ(480, adapter.output_format().width);
580 EXPECT_EQ(300, adapter.output_format().height);
581
582 // Process load is medium, but system load is high. Downgrade.
583 UpdateCpuLoad(&adapter, 1, 1, 0.55f, 0.98f);
584 EXPECT_EQ(320, adapter.output_format().width);
585 EXPECT_EQ(200, adapter.output_format().height);
586
587 // Test reason for adapting is CPU.
588 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_CPU,
589 adapter.adapt_reason());
590
591 // Server format request 320x200. Same as CPU. Do nothing.
592 format.width = 320;
593 format.height = 200;
594 adapter.OnOutputFormatRequest(format);
595 EXPECT_EQ(320, adapter.output_format().width);
596 EXPECT_EQ(200, adapter.output_format().height);
597
598 // Test reason for adapting is CPU and VIEW.
599 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_CPU +
600 CoordinatedVideoAdapter::ADAPTREASON_VIEW,
601 adapter.adapt_reason());
602
603 // Process load and system load are normal. Adapt nothing.
604 UpdateCpuLoad(&adapter, 1, 1, 0.5f, 0.8f);
605 EXPECT_EQ(320, adapter.output_format().width);
606 EXPECT_EQ(200, adapter.output_format().height);
607
608 // Process load and system load are low, but view is still low. Adapt nothing.
609 UpdateCpuLoad(&adapter, 1, 1, 0.2f, 0.3f);
610 EXPECT_EQ(320, adapter.output_format().width);
611 EXPECT_EQ(200, adapter.output_format().height);
612
613 // Test reason for adapting is VIEW.
614 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_VIEW,
615 adapter.adapt_reason());
616
617 // Server format request 640x400. Cpu is still low. Upgrade.
618 format.width = 640;
619 format.height = 400;
620 adapter.OnOutputFormatRequest(format);
621 EXPECT_EQ(480, adapter.output_format().width);
622 EXPECT_EQ(300, adapter.output_format().height);
623
624 // Test reason for adapting is CPU.
625 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_CPU,
626 adapter.adapt_reason());
627
628 // Encoder resolution request: downgrade.
629 adapter.OnEncoderResolutionRequest(480, 300,
630 CoordinatedVideoAdapter::DOWNGRADE);
631 EXPECT_EQ(320, adapter.output_format().width);
632 EXPECT_EQ(200, adapter.output_format().height);
633
634 // Test reason for adapting is BANDWIDTH.
635 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_BANDWIDTH,
636 adapter.adapt_reason());
637
638 // Process load and system load are low. Constrained by GD. Adapt nothing
639 adapter.OnCpuLoadUpdated(1, 1, 0.2f, 0.3f);
640 EXPECT_EQ(320, adapter.output_format().width);
641 EXPECT_EQ(200, adapter.output_format().height);
642
643 // Encoder resolution request: upgrade.
644 adapter.OnEncoderResolutionRequest(320, 200,
645 CoordinatedVideoAdapter::UPGRADE);
646 EXPECT_EQ(480, adapter.output_format().width);
647 EXPECT_EQ(300, adapter.output_format().height);
648
649 // Encoder resolution request: upgrade. Constrained by CPU.
650 adapter.OnEncoderResolutionRequest(480, 300,
651 CoordinatedVideoAdapter::UPGRADE);
652 EXPECT_EQ(480, adapter.output_format().width);
653 EXPECT_EQ(300, adapter.output_format().height);
654
655 // Server format request 640x400. Constrained by CPU.
656 format.width = 640;
657 format.height = 400;
658 adapter.OnOutputFormatRequest(format);
659 EXPECT_EQ(480, adapter.output_format().width);
660 EXPECT_EQ(300, adapter.output_format().height);
661 }
662
TEST(CoordinatedVideoAdapterTest,TestCoordinatedWithCpuRequest)663 TEST(CoordinatedVideoAdapterTest, TestCoordinatedWithCpuRequest) {
664 CoordinatedVideoAdapter adapter;
665 adapter.set_cpu_adaptation(true);
666 EXPECT_FALSE(adapter.cpu_smoothing());
667 VideoFormat format(640, 400, VideoFormat::FpsToInterval(30), FOURCC_I420);
668 adapter.SetInputFormat(format);
669
670 // Server format request 640x400.
671 format.height = 400;
672 adapter.OnOutputFormatRequest(format);
673 EXPECT_EQ(640, adapter.output_format().width);
674 EXPECT_EQ(400, adapter.output_format().height);
675
676 // CPU resolution request: downgrade. Adapt down.
677 adapter.OnCpuResolutionRequest(CoordinatedVideoAdapter::DOWNGRADE);
678 EXPECT_EQ(480, adapter.output_format().width);
679 EXPECT_EQ(300, adapter.output_format().height);
680
681 // CPU resolution request: keep. Do nothing.
682 adapter.OnCpuResolutionRequest(CoordinatedVideoAdapter::KEEP);
683 EXPECT_EQ(480, adapter.output_format().width);
684 EXPECT_EQ(300, adapter.output_format().height);
685
686 // CPU resolution request: downgrade, but cpu adaptation disabled.
687 // Adapt nothing.
688 adapter.set_cpu_adaptation(false);
689 adapter.OnCpuResolutionRequest(CoordinatedVideoAdapter::DOWNGRADE);
690 EXPECT_EQ(480, adapter.output_format().width);
691 EXPECT_EQ(300, adapter.output_format().height);
692
693 // CPU resolution request: downgrade. Adapt down.
694 adapter.set_cpu_adaptation(true);
695 adapter.OnCpuResolutionRequest(CoordinatedVideoAdapter::DOWNGRADE);
696 EXPECT_EQ(320, adapter.output_format().width);
697 EXPECT_EQ(200, adapter.output_format().height);
698
699 // Test reason for adapting is CPU.
700 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_CPU,
701 adapter.adapt_reason());
702
703 // CPU resolution request: downgrade, but already at minimum. Do nothing.
704 adapter.OnCpuResolutionRequest(CoordinatedVideoAdapter::DOWNGRADE);
705 EXPECT_EQ(320, adapter.output_format().width);
706 EXPECT_EQ(200, adapter.output_format().height);
707
708 // Server format request 320x200. Same as CPU. Do nothing.
709 format.width = 320;
710 format.height = 200;
711 adapter.OnOutputFormatRequest(format);
712 EXPECT_EQ(320, adapter.output_format().width);
713 EXPECT_EQ(200, adapter.output_format().height);
714
715 // Test reason for adapting is CPU and VIEW.
716 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_CPU +
717 CoordinatedVideoAdapter::ADAPTREASON_VIEW,
718 adapter.adapt_reason());
719
720 // CPU resolution request: upgrade, but view request still low. Do nothing.
721 adapter.OnCpuResolutionRequest(CoordinatedVideoAdapter::UPGRADE);
722 EXPECT_EQ(320, adapter.output_format().width);
723 EXPECT_EQ(200, adapter.output_format().height);
724
725 // Test reason for adapting is VIEW.
726 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_VIEW,
727 adapter.adapt_reason());
728
729 // Server format request 640x400. Cpu is still low. Upgrade.
730 format.width = 640;
731 format.height = 400;
732 adapter.OnOutputFormatRequest(format);
733 EXPECT_EQ(480, adapter.output_format().width);
734 EXPECT_EQ(300, adapter.output_format().height);
735
736 // Test reason for adapting is CPU.
737 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_CPU,
738 adapter.adapt_reason());
739
740 // Encoder resolution request: downgrade.
741 adapter.OnEncoderResolutionRequest(480, 300,
742 CoordinatedVideoAdapter::DOWNGRADE);
743 EXPECT_EQ(320, adapter.output_format().width);
744 EXPECT_EQ(200, adapter.output_format().height);
745
746 // Test reason for adapting is BANDWIDTH.
747 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_BANDWIDTH,
748 adapter.adapt_reason());
749
750 // Process load and system load are low. Constrained by GD. Adapt nothing
751 adapter.OnCpuLoadUpdated(1, 1, 0.2f, 0.3f);
752 EXPECT_EQ(320, adapter.output_format().width);
753 EXPECT_EQ(200, adapter.output_format().height);
754
755 // Encoder resolution request: upgrade.
756 adapter.OnEncoderResolutionRequest(320, 200,
757 CoordinatedVideoAdapter::UPGRADE);
758 EXPECT_EQ(480, adapter.output_format().width);
759 EXPECT_EQ(300, adapter.output_format().height);
760
761 // Encoder resolution request: upgrade. Constrained by CPU.
762 adapter.OnEncoderResolutionRequest(480, 300,
763 CoordinatedVideoAdapter::UPGRADE);
764 EXPECT_EQ(480, adapter.output_format().width);
765 EXPECT_EQ(300, adapter.output_format().height);
766
767 // Server format request 640x400. Constrained by CPU.
768 format.width = 640;
769 format.height = 400;
770 adapter.OnOutputFormatRequest(format);
771 EXPECT_EQ(480, adapter.output_format().width);
772 EXPECT_EQ(300, adapter.output_format().height);
773 }
774
TEST(CoordinatedVideoAdapterTest,TestViewRequestPlusCameraSwitch)775 TEST(CoordinatedVideoAdapterTest, TestViewRequestPlusCameraSwitch) {
776 CoordinatedVideoAdapter adapter;
777 adapter.set_view_switch(true);
778
779 // Start at HD.
780 VideoFormat format(1280, 720, VideoFormat::FpsToInterval(30), FOURCC_I420);
781 adapter.SetInputFormat(format);
782 EXPECT_EQ(format, adapter.input_format());
783 EXPECT_TRUE(adapter.output_format().IsSize0x0());
784
785 // View request for VGA.
786 format.width = 640;
787 format.height = 360;
788 adapter.OnOutputFormatRequest(format);
789 EXPECT_EQ(640, adapter.output_format().width);
790 EXPECT_EQ(360, adapter.output_format().height);
791 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_VIEW, adapter.adapt_reason());
792
793 // Now, the camera reopens at VGA.
794 // Both the frame and the output format should be 640x360.
795 const VideoFormat out_format = adapter.AdaptFrameResolution(640, 360);
796 EXPECT_EQ(640, out_format.width);
797 EXPECT_EQ(360, out_format.height);
798 // At this point, the view is no longer adapted, since the input has resized
799 // small enough to fit the last view request.
800 EXPECT_EQ(0, adapter.adapt_reason());
801
802 // And another view request comes in for 640x360, which should have no
803 // real impact.
804 adapter.OnOutputFormatRequest(format);
805 EXPECT_EQ(640, adapter.output_format().width);
806 EXPECT_EQ(360, adapter.output_format().height);
807 EXPECT_EQ(0, adapter.adapt_reason());
808 }
809
TEST(CoordinatedVideoAdapterTest,TestVGAWidth)810 TEST(CoordinatedVideoAdapterTest, TestVGAWidth) {
811 CoordinatedVideoAdapter adapter;
812 adapter.set_view_switch(true);
813
814 // Start at 640x480, for cameras that don't support 640x360.
815 VideoFormat format(640, 480, VideoFormat::FpsToInterval(30), FOURCC_I420);
816 adapter.SetInputFormat(format);
817 EXPECT_EQ(format, adapter.input_format());
818 EXPECT_TRUE(adapter.output_format().IsSize0x0());
819
820 // Output format is 640x360, though.
821 format.width = 640;
822 format.height = 360;
823 adapter.SetOutputFormat(format);
824
825 // And also a view request comes for 640x360.
826 adapter.OnOutputFormatRequest(format);
827 // At this point, we have to adapt down to something lower.
828 EXPECT_EQ(480, adapter.output_format().width);
829 EXPECT_EQ(360, adapter.output_format().height);
830
831 // But if frames come in at 640x360, we shouldn't adapt them down.
832 // Fake a 640x360 frame.
833 VideoFormat out_format = adapter.AdaptFrameResolution(640, 360);
834 EXPECT_EQ(640, out_format.width);
835 EXPECT_EQ(360, out_format.height);
836
837 // Similarly, no-op adapt requests for other reasons shouldn't change
838 // adaptation state (before a previous bug, the previous EXPECTs would
839 // fail and the following would succeed, as the no-op CPU request would
840 // fix the adaptation state).
841 adapter.set_cpu_adaptation(true);
842 UpdateCpuLoad(&adapter, 1, 1, 0.7f, 0.7f);
843 out_format = adapter.AdaptFrameResolution(640, 360);
844
845 EXPECT_EQ(640, out_format.width);
846 EXPECT_EQ(360, out_format.height);
847 }
848
849 // When adapting resolution for CPU or GD, the quantity of pixels that the
850 // request is based on is reduced to half or double, and then an actual
851 // resolution is snapped to, rounding to the closest actual resolution.
852 // This works well for some tolerance to 3/4, odd widths and aspect ratios
853 // that dont exactly match, but is not best behavior for ViewRequests which
854 // need to be be strictly respected to avoid going over the resolution budget
855 // given to the codec - 854x480 total pixels.
856 // ViewRequest must find a lower resolution.
TEST(CoordinatedVideoAdapterTest,TestCoordinatedViewRequestDown)857 TEST(CoordinatedVideoAdapterTest, TestCoordinatedViewRequestDown) {
858 CoordinatedVideoAdapter adapter;
859 adapter.set_cpu_adaptation(false);
860
861 VideoFormat format(960, 540, VideoFormat::FpsToInterval(30), FOURCC_I420);
862 adapter.SetInputFormat(format);
863 adapter.set_scale_third(true);
864 EXPECT_EQ(format, adapter.input_format());
865 EXPECT_TRUE(adapter.output_format().IsSize0x0());
866
867 // Server format request 640x400. Expect HVGA.
868 format.width = 640;
869 format.height = 400;
870 adapter.OnOutputFormatRequest(format);
871 EXPECT_EQ(640, adapter.output_format().width);
872 EXPECT_EQ(360, adapter.output_format().height);
873
874 // Test reason for adapting is VIEW.
875 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_VIEW, adapter.adapt_reason());
876 }
877
878 // Test that we downgrade video for cpu up to two times.
TEST(CoordinatedVideoAdapterTest,TestCpuDowngradeTimes)879 TEST(CoordinatedVideoAdapterTest, TestCpuDowngradeTimes) {
880 CoordinatedVideoAdapter adapter;
881 adapter.set_cpu_adaptation(true);
882 EXPECT_FALSE(adapter.cpu_smoothing());
883 VideoFormat format(640, 400, VideoFormat::FpsToInterval(30), FOURCC_I420);
884 adapter.SetInputFormat(format);
885
886 // Server format request 640x400.
887 format.height = 400;
888 adapter.OnOutputFormatRequest(format);
889 EXPECT_EQ(640, adapter.output_format().width);
890 EXPECT_EQ(400, adapter.output_format().height);
891
892 // Process load and system load are low. Do not change the cpu desired format
893 // and do not adapt.
894 adapter.OnCpuLoadUpdated(1, 1, 0.2f, 0.3f);
895 EXPECT_EQ(640, adapter.output_format().width);
896 EXPECT_EQ(400, adapter.output_format().height);
897
898 // System load is high. Downgrade.
899 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
900 EXPECT_EQ(480, adapter.output_format().width);
901 EXPECT_EQ(300, adapter.output_format().height);
902
903 // System load is high. Downgrade again.
904 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
905 EXPECT_EQ(320, adapter.output_format().width);
906 EXPECT_EQ(200, adapter.output_format().height);
907
908 // System load is still high. Do not downgrade any more.
909 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
910 EXPECT_EQ(320, adapter.output_format().width);
911 EXPECT_EQ(200, adapter.output_format().height);
912
913 // Process load and system load are low. Upgrade.
914 UpdateCpuLoad(&adapter, 1, 1, 0.2f, 0.3f);
915 EXPECT_EQ(480, adapter.output_format().width);
916 EXPECT_EQ(300, adapter.output_format().height);
917
918 // System load is high. Downgrade.
919 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
920 EXPECT_EQ(320, adapter.output_format().width);
921 EXPECT_EQ(200, adapter.output_format().height);
922
923 // System load is still high. Do not downgrade any more.
924 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
925 EXPECT_EQ(320, adapter.output_format().width);
926 EXPECT_EQ(200, adapter.output_format().height);
927 }
928
929 // Test that we respect CPU adapter threshold values.
TEST(CoordinatedVideoAdapterTest,TestAdapterCpuThreshold)930 TEST(CoordinatedVideoAdapterTest, TestAdapterCpuThreshold) {
931 CoordinatedVideoAdapter adapter;
932 adapter.set_cpu_adaptation(true);
933 EXPECT_FALSE(adapter.cpu_smoothing());
934 VideoFormat format(640, 400, VideoFormat::FpsToInterval(30), FOURCC_I420);
935 adapter.SetInputFormat(format);
936
937 // Server format request 640x400.
938 format.height = 400;
939 adapter.OnOutputFormatRequest(format);
940 EXPECT_EQ(640, adapter.output_format().width);
941 EXPECT_EQ(400, adapter.output_format().height);
942
943 // Process load and system load are low. Do not change the cpu desired format
944 // and do not adapt.
945 adapter.OnCpuLoadUpdated(1, 1, 0.2f, 0.3f);
946 EXPECT_EQ(640, adapter.output_format().width);
947 EXPECT_EQ(400, adapter.output_format().height);
948
949 // System load is high. Downgrade.
950 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
951 EXPECT_EQ(480, adapter.output_format().width);
952 EXPECT_EQ(300, adapter.output_format().height);
953
954 // Test reason for adapting is CPU.
955 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_CPU, adapter.adapt_reason());
956
957 // System load is high. Normally downgrade but threshold is high. Do nothing.
958 adapter.set_high_system_threshold(0.98f); // Set threshold high.
959 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
960 EXPECT_EQ(480, adapter.output_format().width);
961 EXPECT_EQ(300, adapter.output_format().height);
962
963 // System load is medium. Normally do nothing, threshold is low. Adapt down.
964 adapter.set_high_system_threshold(0.75f); // Set threshold low.
965 UpdateCpuLoad(&adapter, 1, 1, 0.8f, 0.8f);
966 EXPECT_EQ(320, adapter.output_format().width);
967 EXPECT_EQ(200, adapter.output_format().height);
968 }
969
970
971 // Test that for an upgrade cpu request, we actually upgrade the desired format;
972 // for a downgrade request, we downgrade from the output format.
TEST(CoordinatedVideoAdapterTest,TestRealCpuUpgrade)973 TEST(CoordinatedVideoAdapterTest, TestRealCpuUpgrade) {
974 CoordinatedVideoAdapter adapter;
975 adapter.set_cpu_adaptation(true);
976 adapter.set_cpu_smoothing(true);
977 VideoFormat format(640, 400, VideoFormat::FpsToInterval(30), FOURCC_I420);
978 adapter.SetInputFormat(format);
979
980 // Server format request 640x400.
981 format.width = 640;
982 format.height = 400;
983 adapter.OnOutputFormatRequest(format);
984 EXPECT_EQ(640, adapter.output_format().width);
985 EXPECT_EQ(400, adapter.output_format().height);
986
987 // Process load and system load are low. Do not change the cpu desired format
988 // and do not adapt.
989 UpdateCpuLoad(&adapter, 1, 1, 0.2f, 0.3f);
990 EXPECT_EQ(640, adapter.output_format().width);
991 EXPECT_EQ(400, adapter.output_format().height);
992
993 // Server format request 320x200.
994 format.width = 320;
995 format.height = 200;
996 adapter.OnOutputFormatRequest(format);
997 EXPECT_EQ(320, adapter.output_format().width);
998 EXPECT_EQ(200, adapter.output_format().height);
999
1000 // Process load and system load are low. Do not change the cpu desired format
1001 // and do not adapt.
1002 UpdateCpuLoad(&adapter, 1, 1, 0.2f, 0.3f);
1003 EXPECT_EQ(320, adapter.output_format().width);
1004 EXPECT_EQ(200, adapter.output_format().height);
1005
1006 // Server format request 640x400. Set to 640x400 immediately.
1007 format.width = 640;
1008 format.height = 400;
1009 adapter.OnOutputFormatRequest(format);
1010 EXPECT_EQ(640, adapter.output_format().width);
1011 EXPECT_EQ(400, adapter.output_format().height);
1012
1013 // Server format request 320x200.
1014 format.width = 320;
1015 format.height = 200;
1016 adapter.OnOutputFormatRequest(format);
1017 EXPECT_EQ(320, adapter.output_format().width);
1018 EXPECT_EQ(200, adapter.output_format().height);
1019
1020 // Process load is high, but system is not. Do not change the cpu desired
1021 // format and do not adapt.
1022 for (size_t i = 0; i < 10; ++i) {
1023 UpdateCpuLoad(&adapter, 1, 1, 0.75f, 0.8f);
1024 }
1025 EXPECT_EQ(320, adapter.output_format().width);
1026 EXPECT_EQ(200, adapter.output_format().height);
1027 }
1028
1029 // Test that for an upgrade encoder request, we actually upgrade the desired
1030 // format; for a downgrade request, we downgrade from the output format.
TEST(CoordinatedVideoAdapterTest,TestRealEncoderUpgrade)1031 TEST(CoordinatedVideoAdapterTest, TestRealEncoderUpgrade) {
1032 CoordinatedVideoAdapter adapter;
1033 adapter.set_cpu_adaptation(true);
1034 adapter.set_cpu_smoothing(true);
1035 VideoFormat format(640, 400, VideoFormat::FpsToInterval(30), FOURCC_I420);
1036 adapter.SetInputFormat(format);
1037
1038 // Server format request 640x400.
1039 format.width = 640;
1040 format.height = 400;
1041 adapter.OnOutputFormatRequest(format);
1042 EXPECT_EQ(640, adapter.output_format().width);
1043 EXPECT_EQ(400, adapter.output_format().height);
1044
1045 // Encoder resolution request. Do not change the encoder desired format and
1046 // do not adapt.
1047 adapter.OnEncoderResolutionRequest(640, 400,
1048 CoordinatedVideoAdapter::UPGRADE);
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 // Encoder resolution request. Do not change the encoder desired format and
1060 // do not adapt.
1061 adapter.OnEncoderResolutionRequest(320, 200,
1062 CoordinatedVideoAdapter::UPGRADE);
1063 EXPECT_EQ(320, adapter.output_format().width);
1064 EXPECT_EQ(200, adapter.output_format().height);
1065
1066 // Server format request 640x400. Set to 640x400 immediately.
1067 format.width = 640;
1068 format.height = 400;
1069 adapter.OnOutputFormatRequest(format);
1070 EXPECT_EQ(480, adapter.output_format().width);
1071 EXPECT_EQ(300, adapter.output_format().height);
1072
1073 // Test reason for adapting is BANDWIDTH.
1074 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_BANDWIDTH,
1075 adapter.adapt_reason());
1076
1077 // Server format request 320x200.
1078 format.width = 320;
1079 format.height = 200;
1080 adapter.OnOutputFormatRequest(format);
1081 EXPECT_EQ(320, adapter.output_format().width);
1082 EXPECT_EQ(200, adapter.output_format().height);
1083
1084 // Encoder resolution request. Downgrade from 320x200.
1085 adapter.OnEncoderResolutionRequest(320, 200,
1086 CoordinatedVideoAdapter::DOWNGRADE);
1087 EXPECT_EQ(240, adapter.output_format().width);
1088 EXPECT_EQ(150, adapter.output_format().height);
1089 }
1090
TEST(CoordinatedVideoAdapterTest,TestNormalizeOutputFormat)1091 TEST(CoordinatedVideoAdapterTest, TestNormalizeOutputFormat) {
1092 CoordinatedVideoAdapter adapter;
1093 // The input format is 640x360 and the output is limited to 16:9.
1094 VideoFormat format(640, 360, VideoFormat::FpsToInterval(30), FOURCC_I420);
1095 adapter.SetInputFormat(format);
1096
1097 format.width = 320;
1098 format.height = 180;
1099 format.interval = VideoFormat::FpsToInterval(15);
1100 adapter.OnOutputFormatRequest(format);
1101 EXPECT_EQ(320, adapter.output_format().width);
1102 EXPECT_EQ(180, adapter.output_format().height);
1103 EXPECT_EQ(VideoFormat::FpsToInterval(15), adapter.output_format().interval);
1104
1105 format.width = 320;
1106 format.height = 200;
1107 format.interval = VideoFormat::FpsToInterval(40);
1108 adapter.OnOutputFormatRequest(format);
1109 EXPECT_EQ(320, adapter.output_format().width);
1110 EXPECT_EQ(180, adapter.output_format().height);
1111 EXPECT_EQ(VideoFormat::FpsToInterval(30), adapter.output_format().interval);
1112
1113 // Test reason for adapting is VIEW. Should work even with normalization.
1114 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_VIEW,
1115 adapter.adapt_reason());
1116
1117 format.width = 320;
1118 format.height = 240;
1119 adapter.OnOutputFormatRequest(format);
1120 EXPECT_EQ(320, adapter.output_format().width);
1121 EXPECT_EQ(180, adapter.output_format().height);
1122
1123 // The input format is 640x480 and the output will be 4:3.
1124 format.width = 640;
1125 format.height = 480;
1126 adapter.SetInputFormat(format);
1127 EXPECT_EQ(320, adapter.output_format().width);
1128 EXPECT_EQ(240, adapter.output_format().height);
1129
1130 format.width = 320;
1131 format.height = 240;
1132 adapter.OnOutputFormatRequest(format);
1133 EXPECT_EQ(320, adapter.output_format().width);
1134 EXPECT_EQ(240, adapter.output_format().height);
1135
1136 // The input format is initialized after the output. At that time, the output
1137 // height is adjusted.
1138 format.width = 0;
1139 format.height = 0;
1140 adapter.SetInputFormat(format);
1141
1142 format.width = 320;
1143 format.height = 240;
1144 format.interval = VideoFormat::FpsToInterval(30);
1145 adapter.OnOutputFormatRequest(format);
1146 EXPECT_EQ(320, adapter.output_format().width);
1147 EXPECT_EQ(240, adapter.output_format().height);
1148 EXPECT_EQ(VideoFormat::FpsToInterval(30), adapter.output_format().interval);
1149
1150 format.width = 640;
1151 format.height = 480;
1152 format.interval = VideoFormat::FpsToInterval(15);
1153 adapter.SetInputFormat(format);
1154 EXPECT_EQ(320, adapter.output_format().width);
1155 EXPECT_EQ(240, adapter.output_format().height);
1156 EXPECT_EQ(VideoFormat::FpsToInterval(15), adapter.output_format().interval);
1157 }
1158
1159 // Test that we downgrade video for cpu up to two times.
TEST_F(VideoAdapterTest,CpuDowngradeAndSignal)1160 TEST_F(VideoAdapterTest, CpuDowngradeAndSignal) {
1161 CoordinatedVideoAdapter adapter;
1162 CpuAdapterListener cpu_listener;
1163 adapter.SignalCpuAdaptationUnable.connect(
1164 &cpu_listener, &CpuAdapterListener::OnCpuAdaptationSignalled);
1165
1166 adapter.set_cpu_adaptation(true);
1167 EXPECT_FALSE(adapter.cpu_smoothing());
1168 VideoFormat format(640, 360, VideoFormat::FpsToInterval(30), FOURCC_I420);
1169 adapter.SetInputFormat(format);
1170 adapter.OnOutputFormatRequest(format);
1171
1172 // System load is high. Downgrade.
1173 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
1174
1175 // System load is high. Downgrade again.
1176 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
1177
1178 // System load is still high. Do not downgrade any more. Ensure we have not
1179 // signalled until after the cpu warning though.
1180 EXPECT_TRUE(!cpu_listener.received_cpu_signal());
1181 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
1182 EXPECT_TRUE_WAIT(cpu_listener.received_cpu_signal(), kWaitTimeout);
1183 }
1184
1185 // Test that we downgrade video for cpu up to two times.
TEST_F(VideoAdapterTest,CpuDowngradeAndDontSignal)1186 TEST_F(VideoAdapterTest, CpuDowngradeAndDontSignal) {
1187 CoordinatedVideoAdapter adapter;
1188 CpuAdapterListener cpu_listener;
1189 adapter.SignalCpuAdaptationUnable.connect(
1190 &cpu_listener, &CpuAdapterListener::OnCpuAdaptationSignalled);
1191
1192 adapter.set_cpu_adaptation(true);
1193 adapter.set_cpu_smoothing(true);
1194 VideoFormat format(640, 360, VideoFormat::FpsToInterval(30), FOURCC_I420);
1195 adapter.SetInputFormat(format);
1196 adapter.OnOutputFormatRequest(format);
1197
1198 // System load is high. Downgrade.
1199 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
1200
1201 // System load is high, process is not, Do not downgrade again.
1202 UpdateCpuLoad(&adapter, 1, 1, 0.25f, 0.95f);
1203
1204 // System load is high, process is not, Do not downgrade again and do not
1205 // signal.
1206 adapter.set_cpu_adaptation(false);
1207 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
1208 rtc::Thread::Current()->ProcessMessages(kShortWaitTimeout);
1209 EXPECT_TRUE(!cpu_listener.received_cpu_signal());
1210 adapter.set_cpu_adaptation(true);
1211 }
1212
1213 // Test that we require enough time before we downgrade.
TEST_F(VideoAdapterTest,CpuMinTimeRequirement)1214 TEST_F(VideoAdapterTest, CpuMinTimeRequirement) {
1215 CoordinatedVideoAdapter adapter;
1216 CpuAdapterListener cpu_listener;
1217 adapter.SignalCpuAdaptationUnable.connect(
1218 &cpu_listener, &CpuAdapterListener::OnCpuAdaptationSignalled);
1219
1220 adapter.set_cpu_adaptation(true);
1221 adapter.set_cpu_smoothing(true);
1222 VideoFormat format(640, 360, VideoFormat::FpsToInterval(30), FOURCC_I420);
1223 adapter.SetInputFormat(format);
1224 adapter.OnOutputFormatRequest(format);
1225
1226 EXPECT_EQ(3, adapter.cpu_load_min_samples());
1227 adapter.set_cpu_load_min_samples(5);
1228
1229 for (size_t i = 0; i < 4; ++i) {
1230 adapter.OnCpuLoadUpdated(1, 1, 1.0f, 1.0f);
1231 EXPECT_EQ(640, adapter.output_format().width);
1232 EXPECT_EQ(360, adapter.output_format().height);
1233 }
1234 // The computed cpu load should now be around 93.5%, with the coefficient of
1235 // 0.4 and a seed value of 0.5. That should be high enough to adapt, but it
1236 // isn't enough samples, so we shouldn't have adapted on any of the previous
1237 // samples.
1238
1239 // One more sample is enough, though, once enough time has passed.
1240 adapter.OnCpuLoadUpdated(1, 1, 1.0f, 1.0f);
1241 EXPECT_EQ(480, adapter.output_format().width);
1242 EXPECT_EQ(270, adapter.output_format().height);
1243
1244 // Now the cpu is lower, but we still need enough samples to upgrade.
1245 for (size_t i = 0; i < 4; ++i) {
1246 adapter.OnCpuLoadUpdated(1, 1, 0.1f, 0.1f);
1247 EXPECT_EQ(480, adapter.output_format().width);
1248 EXPECT_EQ(270, adapter.output_format().height);
1249 }
1250
1251 // One more sample is enough, once time has elapsed.
1252 adapter.OnCpuLoadUpdated(1, 1, 1.0f, 1.0f);
1253 EXPECT_EQ(640, adapter.output_format().width);
1254 EXPECT_EQ(360, adapter.output_format().height);
1255 }
1256
TEST_F(VideoAdapterTest,CpuIgnoresSpikes)1257 TEST_F(VideoAdapterTest, CpuIgnoresSpikes) {
1258 CoordinatedVideoAdapter adapter;
1259 CpuAdapterListener cpu_listener;
1260 adapter.SignalCpuAdaptationUnable.connect(
1261 &cpu_listener, &CpuAdapterListener::OnCpuAdaptationSignalled);
1262
1263 adapter.set_cpu_adaptation(true);
1264 adapter.set_cpu_smoothing(true);
1265 VideoFormat format(640, 360, VideoFormat::FpsToInterval(30), FOURCC_I420);
1266 adapter.SetInputFormat(format);
1267 adapter.OnOutputFormatRequest(format);
1268
1269 // System load is high. Downgrade.
1270 for (size_t i = 0; i < 5; ++i) {
1271 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
1272 }
1273 EXPECT_EQ(480, adapter.output_format().width);
1274 EXPECT_EQ(270, adapter.output_format().height);
1275
1276 // Now we're in a state where we could upgrade or downgrade, so get to a
1277 // steady state of about 75% cpu usage.
1278 for (size_t i = 0; i < 5; ++i) {
1279 UpdateCpuLoad(&adapter, 1, 1, 0.75f, 0.75f);
1280 EXPECT_EQ(480, adapter.output_format().width);
1281 EXPECT_EQ(270, adapter.output_format().height);
1282 }
1283
1284 // Now, the cpu spikes for two samples, but then goes back to
1285 // normal. This shouldn't cause adaptation.
1286 UpdateCpuLoad(&adapter, 1, 1, 0.90f, 0.90f);
1287 UpdateCpuLoad(&adapter, 1, 1, 0.90f, 0.90f);
1288 EXPECT_EQ(480, adapter.output_format().width);
1289 EXPECT_EQ(270, adapter.output_format().height);
1290 // Back to the steady state for awhile.
1291 for (size_t i = 0; i < 5; ++i) {
1292 UpdateCpuLoad(&adapter, 1, 1, 0.75, 0.75);
1293 EXPECT_EQ(480, adapter.output_format().width);
1294 EXPECT_EQ(270, adapter.output_format().height);
1295 }
1296
1297 // Now, system cpu usage is starting to drop down. But it takes a bit before
1298 // it gets all the way there.
1299 for (size_t i = 0; i < 10; ++i) {
1300 UpdateCpuLoad(&adapter, 1, 1, 0.5f, 0.5f);
1301 }
1302 EXPECT_EQ(640, adapter.output_format().width);
1303 EXPECT_EQ(360, adapter.output_format().height);
1304 }
1305
1306 } // namespace cricket
1307 #endif // HAVE_WEBRTC_VIDEO
1308