blob: 518c18329fbd6eeba6cdb58883dd1ad516fdb0db [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
magjed@webrtc.orgf58b4552014-11-19 18:09:14 +0000295// Set a very high output pixel resolution. Expect no resolution change.
296TEST_F(VideoAdapterTest, AdaptFrameResolutionHighLimit) {
297 adapter_->SetOutputNumPixels(INT_MAX);
298 VideoFormat adapted_format = adapter_->AdaptFrameResolution(
299 capture_format_.width, capture_format_.height);
300 EXPECT_EQ(capture_format_.width, adapted_format.width);
301 EXPECT_EQ(capture_format_.height, adapted_format.height);
302
303 adapter_->SetOutputNumPixels(987654321);
304 adapted_format = capture_format_,
305 adapter_->AdaptFrameResolution(capture_format_.width, capture_format_.height);
306 EXPECT_EQ(capture_format_.width, adapted_format.width);
307 EXPECT_EQ(capture_format_.height, adapted_format.height);
308}
309
310// Adapt the frame resolution to be the same as capture resolution. Expect no
311// resolution change.
312TEST_F(VideoAdapterTest, AdaptFrameResolutionIdentical) {
313 adapter_->SetOutputFormat(capture_format_);
314 const VideoFormat adapted_format = adapter_->AdaptFrameResolution(
315 capture_format_.width, capture_format_.height);
316 EXPECT_EQ(capture_format_.width, adapted_format.width);
317 EXPECT_EQ(capture_format_.height, adapted_format.height);
318}
319
320// Adapt the frame resolution to be a quarter of the capture resolution. Expect
321// resolution change.
322TEST_F(VideoAdapterTest, AdaptFrameResolutionQuarter) {
323 VideoFormat request_format = capture_format_;
324 request_format.width /= 2;
325 request_format.height /= 2;
326 adapter_->SetOutputFormat(request_format);
327 const VideoFormat adapted_format = adapter_->AdaptFrameResolution(
328 request_format.width, request_format.height);
329 EXPECT_EQ(request_format.width, adapted_format.width);
330 EXPECT_EQ(request_format.height, adapted_format.height);
331}
332
333// Adapt the pixel resolution to 0. Expect frame drop.
334TEST_F(VideoAdapterTest, AdaptFrameResolutionDrop) {
335 adapter_->SetOutputNumPixels(0);
336 EXPECT_TRUE(
337 adapter_->AdaptFrameResolution(capture_format_.width,
338 capture_format_.height).IsSize0x0());
339}
340
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000341// Adapt the frame resolution to be a quarter of the capture resolution at the
342// beginning. Expect resolution change.
343TEST_F(VideoAdapterTest, AdaptResolution) {
344 VideoFormat request_format = capture_format_;
345 request_format.width /= 2;
346 request_format.height /= 2;
347 adapter_->SetOutputFormat(request_format);
348 EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
349 EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000350 listener_->GetStats().captured_frames >= 10, kWaitTimeout);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000351
352 // Verify no frame drop and resolution change.
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000353 VideoCapturerListener::Stats stats = listener_->GetStats();
354 EXPECT_EQ(0, stats.dropped_frames);
355 VerifyAdaptedResolution(stats, request_format.width, request_format.height);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000356}
357
358// Adapt the frame resolution to half width. Expect resolution change.
359TEST_F(VideoAdapterTest, AdaptResolutionNarrow) {
360 VideoFormat request_format = capture_format_;
361 request_format.width /= 2;
362 adapter_->set_scale_third(true);
363 adapter_->SetOutputFormat(request_format);
364 EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
365 EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000366 listener_->GetStats().captured_frames >= 10, kWaitTimeout);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000367
368 // Verify resolution change.
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000369 VerifyAdaptedResolution(listener_->GetStats(), 213, 160);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000370}
371
372// Adapt the frame resolution to half height. Expect resolution change.
373TEST_F(VideoAdapterTest, AdaptResolutionWide) {
374 VideoFormat request_format = capture_format_;
375 request_format.height /= 2;
376 adapter_->set_scale_third(true);
377 adapter_->SetOutputFormat(request_format);
378 EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
379 EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000380 listener_->GetStats().captured_frames >= 10, kWaitTimeout);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000381
382 // Verify resolution change.
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000383 VerifyAdaptedResolution(listener_->GetStats(), 213, 160);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000384}
385
386// Adapt the frame resolution to be a quarter of the capture resolution after
387// capturing no less than 10 frames. Expect no resolution change before
388// adaptation and resolution change after adaptation.
389TEST_F(VideoAdapterTest, AdaptResolutionOnTheFly) {
390 VideoFormat request_format = capture_format_;
391 adapter_->SetOutputFormat(request_format);
392 EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
393 EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000394 listener_->GetStats().captured_frames >= 10, kWaitTimeout);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000395
396 // Verify no resolution change before adaptation.
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000397 VerifyAdaptedResolution(
398 listener_->GetStats(), request_format.width, request_format.height);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000399
400 // Adapt the frame resolution.
401 request_format.width /= 2;
402 request_format.height /= 2;
403 adapter_->SetOutputFormat(request_format);
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000404 int captured_frames = listener_->GetStats().captured_frames;
405 EXPECT_TRUE_WAIT(
406 !capturer_->IsRunning() ||
407 listener_->GetStats().captured_frames >= captured_frames + 10,
408 kWaitTimeout);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000409
410 // Verify resolution change after adaptation.
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000411 VerifyAdaptedResolution(
412 listener_->GetStats(), request_format.width, request_format.height);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000413}
414
415// Black the output frame.
416TEST_F(VideoAdapterTest, BlackOutput) {
417 adapter_->SetOutputFormat(capture_format_);
418 EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
419 EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000420 listener_->GetStats().captured_frames >= 10, kWaitTimeout);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000421 // Verify that the output frame is not black.
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000422 rtc::scoped_ptr<VideoFrame> adapted_frame(listener_->CopyAdaptedFrame());
423 EXPECT_NE(16, *adapted_frame->GetYPlane());
424 EXPECT_NE(128, *adapted_frame->GetUPlane());
425 EXPECT_NE(128, *adapted_frame->GetVPlane());
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000426
427 adapter_->SetBlackOutput(true);
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000428 int captured_frames = listener_->GetStats().captured_frames;
429 EXPECT_TRUE_WAIT(
430 !capturer_->IsRunning() ||
431 listener_->GetStats().captured_frames >= captured_frames + 10,
432 kWaitTimeout);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000433 // Verify that the output frame is black.
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000434 adapted_frame.reset(listener_->CopyAdaptedFrame());
435 EXPECT_EQ(16, *adapted_frame->GetYPlane());
436 EXPECT_EQ(128, *adapted_frame->GetUPlane());
437 EXPECT_EQ(128, *adapted_frame->GetVPlane());
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000438
439 // Verify that the elapsed time and timestamp of the black frame increase.
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000440 int64 elapsed_time = adapted_frame->GetElapsedTime();
441 int64 timestamp = adapted_frame->GetTimeStamp();
442 captured_frames = listener_->GetStats().captured_frames;
443 EXPECT_TRUE_WAIT(
444 !capturer_->IsRunning() ||
445 listener_->GetStats().captured_frames >= captured_frames + 10,
446 kWaitTimeout);
447
448 adapted_frame.reset(listener_->CopyAdaptedFrame());
449 EXPECT_GT(adapted_frame->GetElapsedTime(), elapsed_time);
450 EXPECT_GT(adapted_frame->GetTimeStamp(), timestamp);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000451
452 // Change the output size
453 VideoFormat request_format = capture_format_;
454 request_format.width /= 2;
455 request_format.height /= 2;
456 adapter_->SetOutputFormat(request_format);
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000457 captured_frames = listener_->GetStats().captured_frames;
458 EXPECT_TRUE_WAIT(
459 !capturer_->IsRunning() ||
460 listener_->GetStats().captured_frames >= captured_frames + 10,
461 kWaitTimeout);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000462
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000463 // Verify resolution change after adaptation.
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000464 VerifyAdaptedResolution(
465 listener_->GetStats(), request_format.width, request_format.height);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000466 // Verify that the output frame is black.
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000467 adapted_frame.reset(listener_->CopyAdaptedFrame());
468 EXPECT_EQ(16, *adapted_frame->GetYPlane());
469 EXPECT_EQ(128, *adapted_frame->GetUPlane());
470 EXPECT_EQ(128, *adapted_frame->GetVPlane());
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000471}
472
473// Drop all frames.
474TEST_F(VideoAdapterTest, DropAllFrames) {
475 VideoFormat format; // with resolution 0x0.
476 adapter_->SetOutputFormat(format);
477 EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
478 EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000479 listener_->GetStats().captured_frames >= 10, kWaitTimeout);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000480
481 // Verify all frames are dropped.
pbos@webrtc.orgc9b3f772014-08-26 12:33:18 +0000482 VideoCapturerListener::Stats stats = listener_->GetStats();
483 EXPECT_GE(stats.captured_frames, 10);
484 EXPECT_EQ(stats.captured_frames, stats.dropped_frames);
buildbot@webrtc.org4f0d4012014-08-07 04:47:36 +0000485}
486
487TEST(CoordinatedVideoAdapterTest, TestCoordinatedWithoutCpuAdaptation) {
488 CoordinatedVideoAdapter adapter;
489 adapter.set_cpu_adaptation(false);
490
491 VideoFormat format(640, 400, VideoFormat::FpsToInterval(30), FOURCC_I420);
492 adapter.SetInputFormat(format);
493 adapter.set_scale_third(true);
494 EXPECT_EQ(format, adapter.input_format());
495 EXPECT_TRUE(adapter.output_format().IsSize0x0());
496
497 // Server format request 640x400.
498 format.height = 400;
499 adapter.OnOutputFormatRequest(format);
500 EXPECT_EQ(640, adapter.output_format().width);
501 EXPECT_EQ(400, adapter.output_format().height);
502
503 // Server format request 1280x720, higher than input. Adapt nothing.
504 format.width = 1280;
505 format.height = 720;
506 adapter.OnOutputFormatRequest(format);
507 EXPECT_EQ(640, adapter.output_format().width);
508 EXPECT_EQ(400, adapter.output_format().height);
509
510 // Cpu load is high, but cpu adaptation is disabled. Adapt nothing.
511 adapter.OnCpuLoadUpdated(1, 1, 0.99f, 0.99f);
512 EXPECT_EQ(640, adapter.output_format().width);
513 EXPECT_EQ(400, adapter.output_format().height);
514
515 // Encoder resolution request: downgrade with different size. Adapt nothing.
516 adapter.OnEncoderResolutionRequest(320, 200,
517 CoordinatedVideoAdapter::DOWNGRADE);
518 EXPECT_EQ(640, adapter.output_format().width);
519 EXPECT_EQ(400, adapter.output_format().height);
520
521 // Encoder resolution request: downgrade.
522 adapter.OnEncoderResolutionRequest(640, 400,
523 CoordinatedVideoAdapter::DOWNGRADE);
524 EXPECT_EQ(480, adapter.output_format().width);
525 EXPECT_EQ(300, adapter.output_format().height);
526
527 // Encoder resolution request: downgrade. But GD off. Adapt nothing.
528 adapter.set_gd_adaptation(false);
529 adapter.OnEncoderResolutionRequest(480, 300,
530 CoordinatedVideoAdapter::DOWNGRADE);
531 EXPECT_EQ(480, adapter.output_format().width);
532 EXPECT_EQ(300, adapter.output_format().height);
533 adapter.set_gd_adaptation(true);
534
535 // Encoder resolution request: downgrade.
536 adapter.OnEncoderResolutionRequest(480, 300,
537 CoordinatedVideoAdapter::DOWNGRADE);
538 EXPECT_EQ(320, adapter.output_format().width);
539 EXPECT_EQ(200, adapter.output_format().height);
540
541 // Encoder resolution request: keep. Adapt nothing.
542 adapter.OnEncoderResolutionRequest(320, 200,
543 CoordinatedVideoAdapter::KEEP);
544 EXPECT_EQ(320, adapter.output_format().width);
545 EXPECT_EQ(200, adapter.output_format().height);
546
547 // Encoder resolution request: upgrade.
548 adapter.OnEncoderResolutionRequest(320, 200,
549 CoordinatedVideoAdapter::UPGRADE);
550 EXPECT_EQ(480, adapter.output_format().width);
551 EXPECT_EQ(300, adapter.output_format().height);
552
553 // Server format request 0x0.
554 format.width = 0;
555 format.height = 0;
556 adapter.OnOutputFormatRequest(format);
557 EXPECT_TRUE(adapter.output_format().IsSize0x0());
558
559 // Server format request 320x200.
560 format.width = 320;
561 format.height = 200;
562 adapter.OnOutputFormatRequest(format);
563 EXPECT_EQ(320, adapter.output_format().width);
564 EXPECT_EQ(200, adapter.output_format().height);
565
566 // Server format request 160x100. But view disabled. Adapt nothing.
567 adapter.set_view_adaptation(false);
568 format.width = 160;
569 format.height = 100;
570 adapter.OnOutputFormatRequest(format);
571 EXPECT_EQ(320, adapter.output_format().width);
572 EXPECT_EQ(200, adapter.output_format().height);
573 adapter.set_view_adaptation(true);
574
575 // Enable View Switch. Expect adapt down.
576 adapter.set_view_switch(true);
577 format.width = 160;
578 format.height = 100;
579 adapter.OnOutputFormatRequest(format);
580 EXPECT_EQ(160, adapter.output_format().width);
581 EXPECT_EQ(100, adapter.output_format().height);
582
583 // Encoder resolution request: upgrade. Adapt nothing.
584 adapter.OnEncoderResolutionRequest(160, 100,
585 CoordinatedVideoAdapter::UPGRADE);
586 EXPECT_EQ(160, adapter.output_format().width);
587 EXPECT_EQ(100, adapter.output_format().height);
588
589 // Request View of 2 / 3. Expect adapt down.
590 adapter.set_view_switch(true);
591 format.width = (640 * 2 + 1) / 3;
592 format.height = (400 * 2 + 1) / 3;
593 adapter.OnOutputFormatRequest(format);
594 EXPECT_EQ((640 * 2 + 1) / 3, adapter.output_format().width);
595 EXPECT_EQ((400 * 2 + 1) / 3, adapter.output_format().height);
596
597
598 // Request View of 3 / 8. Expect adapt down.
599 adapter.set_view_switch(true);
600 format.width = 640 * 3 / 8;
601 format.height = 400 * 3 / 8;
602 adapter.OnOutputFormatRequest(format);
603 EXPECT_EQ(640 * 3 / 8, adapter.output_format().width);
604 EXPECT_EQ(400 * 3 / 8, adapter.output_format().height);
605
606 // View Switch back up. Expect adapt.
607 format.width = 320;
608 format.height = 200;
609 adapter.OnOutputFormatRequest(format);
610 EXPECT_EQ(320, adapter.output_format().width);
611 EXPECT_EQ(200, adapter.output_format().height);
612
613 adapter.set_view_switch(false);
614
615 // Encoder resolution request: upgrade. Constrained by server request.
616 adapter.OnEncoderResolutionRequest(320, 200,
617 CoordinatedVideoAdapter::UPGRADE);
618 EXPECT_EQ(320, adapter.output_format().width);
619 EXPECT_EQ(200, adapter.output_format().height);
620
621 // Server format request 480x300.
622 format.width = 480;
623 format.height = 300;
624 adapter.OnOutputFormatRequest(format);
625 EXPECT_EQ(480, adapter.output_format().width);
626 EXPECT_EQ(300, adapter.output_format().height);
627}
628
629TEST(CoordinatedVideoAdapterTest, TestCoordinatedWithCpuAdaptation) {
630 CoordinatedVideoAdapter adapter;
631 adapter.set_cpu_adaptation(true);
632 EXPECT_FALSE(adapter.cpu_smoothing());
633 VideoFormat format(640, 400, VideoFormat::FpsToInterval(30), FOURCC_I420);
634 adapter.SetInputFormat(format);
635
636 // Server format request 640x400.
637 format.height = 400;
638 adapter.OnOutputFormatRequest(format);
639 EXPECT_EQ(640, adapter.output_format().width);
640 EXPECT_EQ(400, adapter.output_format().height);
641
642 // Process load is medium, but system load is high. Downgrade.
643 UpdateCpuLoad(&adapter, 1, 1, 0.55f, 0.98f);
644 EXPECT_EQ(480, adapter.output_format().width);
645 EXPECT_EQ(300, adapter.output_format().height);
646
647 // CPU high, but cpu adaptation disabled. Adapt nothing.
648 adapter.set_cpu_adaptation(false);
649 adapter.OnCpuLoadUpdated(1, 1, 0.55f, 0.98f);
650 EXPECT_EQ(480, adapter.output_format().width);
651 EXPECT_EQ(300, adapter.output_format().height);
652 adapter.set_cpu_adaptation(true);
653
654 // System load is high, but time has not elaspsed. Adapt nothing.
655 adapter.set_cpu_load_min_samples(2);
656 adapter.OnCpuLoadUpdated(1, 1, 0.55f, 0.98f);
657 EXPECT_EQ(480, adapter.output_format().width);
658 EXPECT_EQ(300, adapter.output_format().height);
659
660 // Process load is medium, but system load is high. Downgrade.
661 UpdateCpuLoad(&adapter, 1, 1, 0.55f, 0.98f);
662 EXPECT_EQ(320, adapter.output_format().width);
663 EXPECT_EQ(200, adapter.output_format().height);
664
665 // Test reason for adapting is CPU.
666 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_CPU,
667 adapter.adapt_reason());
668
669 // Server format request 320x200. Same as CPU. Do nothing.
670 format.width = 320;
671 format.height = 200;
672 adapter.OnOutputFormatRequest(format);
673 EXPECT_EQ(320, adapter.output_format().width);
674 EXPECT_EQ(200, adapter.output_format().height);
675
676 // Test reason for adapting is CPU and VIEW.
677 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_CPU +
678 CoordinatedVideoAdapter::ADAPTREASON_VIEW,
679 adapter.adapt_reason());
680
681 // Process load and system load are normal. Adapt nothing.
682 UpdateCpuLoad(&adapter, 1, 1, 0.5f, 0.8f);
683 EXPECT_EQ(320, adapter.output_format().width);
684 EXPECT_EQ(200, adapter.output_format().height);
685
686 // Process load and system load are low, but view is still low. Adapt nothing.
687 UpdateCpuLoad(&adapter, 1, 1, 0.2f, 0.3f);
688 EXPECT_EQ(320, adapter.output_format().width);
689 EXPECT_EQ(200, adapter.output_format().height);
690
691 // Test reason for adapting is VIEW.
692 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_VIEW,
693 adapter.adapt_reason());
694
695 // Server format request 640x400. Cpu is still low. Upgrade.
696 format.width = 640;
697 format.height = 400;
698 adapter.OnOutputFormatRequest(format);
699 EXPECT_EQ(480, adapter.output_format().width);
700 EXPECT_EQ(300, adapter.output_format().height);
701
702 // Test reason for adapting is CPU.
703 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_CPU,
704 adapter.adapt_reason());
705
706 // Encoder resolution request: downgrade.
707 adapter.OnEncoderResolutionRequest(480, 300,
708 CoordinatedVideoAdapter::DOWNGRADE);
709 EXPECT_EQ(320, adapter.output_format().width);
710 EXPECT_EQ(200, adapter.output_format().height);
711
712 // Test reason for adapting is BANDWIDTH.
713 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_BANDWIDTH,
714 adapter.adapt_reason());
715
716 // Process load and system load are low. Constrained by GD. Adapt nothing
717 adapter.OnCpuLoadUpdated(1, 1, 0.2f, 0.3f);
718 EXPECT_EQ(320, adapter.output_format().width);
719 EXPECT_EQ(200, adapter.output_format().height);
720
721 // Encoder resolution request: upgrade.
722 adapter.OnEncoderResolutionRequest(320, 200,
723 CoordinatedVideoAdapter::UPGRADE);
724 EXPECT_EQ(480, adapter.output_format().width);
725 EXPECT_EQ(300, adapter.output_format().height);
726
727 // Encoder resolution request: upgrade. Constrained by CPU.
728 adapter.OnEncoderResolutionRequest(480, 300,
729 CoordinatedVideoAdapter::UPGRADE);
730 EXPECT_EQ(480, adapter.output_format().width);
731 EXPECT_EQ(300, adapter.output_format().height);
732
733 // Server format request 640x400. Constrained by CPU.
734 format.width = 640;
735 format.height = 400;
736 adapter.OnOutputFormatRequest(format);
737 EXPECT_EQ(480, adapter.output_format().width);
738 EXPECT_EQ(300, adapter.output_format().height);
739}
740
741TEST(CoordinatedVideoAdapterTest, TestCoordinatedWithCpuRequest) {
742 CoordinatedVideoAdapter adapter;
743 adapter.set_cpu_adaptation(true);
744 EXPECT_FALSE(adapter.cpu_smoothing());
745 VideoFormat format(640, 400, VideoFormat::FpsToInterval(30), FOURCC_I420);
746 adapter.SetInputFormat(format);
747
748 // Server format request 640x400.
749 format.height = 400;
750 adapter.OnOutputFormatRequest(format);
751 EXPECT_EQ(640, adapter.output_format().width);
752 EXPECT_EQ(400, adapter.output_format().height);
753
754 // CPU resolution request: downgrade. Adapt down.
755 adapter.OnCpuResolutionRequest(CoordinatedVideoAdapter::DOWNGRADE);
756 EXPECT_EQ(480, adapter.output_format().width);
757 EXPECT_EQ(300, adapter.output_format().height);
758
759 // CPU resolution request: keep. Do nothing.
760 adapter.OnCpuResolutionRequest(CoordinatedVideoAdapter::KEEP);
761 EXPECT_EQ(480, adapter.output_format().width);
762 EXPECT_EQ(300, adapter.output_format().height);
763
764 // CPU resolution request: downgrade, but cpu adaptation disabled.
765 // Adapt nothing.
766 adapter.set_cpu_adaptation(false);
767 adapter.OnCpuResolutionRequest(CoordinatedVideoAdapter::DOWNGRADE);
768 EXPECT_EQ(480, adapter.output_format().width);
769 EXPECT_EQ(300, adapter.output_format().height);
770
771 // CPU resolution request: downgrade. Adapt down.
772 adapter.set_cpu_adaptation(true);
773 adapter.OnCpuResolutionRequest(CoordinatedVideoAdapter::DOWNGRADE);
774 EXPECT_EQ(320, adapter.output_format().width);
775 EXPECT_EQ(200, adapter.output_format().height);
776
777 // Test reason for adapting is CPU.
778 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_CPU,
779 adapter.adapt_reason());
780
781 // CPU resolution request: downgrade, but already at minimum. Do nothing.
782 adapter.OnCpuResolutionRequest(CoordinatedVideoAdapter::DOWNGRADE);
783 EXPECT_EQ(320, adapter.output_format().width);
784 EXPECT_EQ(200, adapter.output_format().height);
785
786 // Server format request 320x200. Same as CPU. Do nothing.
787 format.width = 320;
788 format.height = 200;
789 adapter.OnOutputFormatRequest(format);
790 EXPECT_EQ(320, adapter.output_format().width);
791 EXPECT_EQ(200, adapter.output_format().height);
792
793 // Test reason for adapting is CPU and VIEW.
794 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_CPU +
795 CoordinatedVideoAdapter::ADAPTREASON_VIEW,
796 adapter.adapt_reason());
797
798 // CPU resolution request: upgrade, but view request still low. Do nothing.
799 adapter.OnCpuResolutionRequest(CoordinatedVideoAdapter::UPGRADE);
800 EXPECT_EQ(320, adapter.output_format().width);
801 EXPECT_EQ(200, adapter.output_format().height);
802
803 // Test reason for adapting is VIEW.
804 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_VIEW,
805 adapter.adapt_reason());
806
807 // Server format request 640x400. Cpu is still low. Upgrade.
808 format.width = 640;
809 format.height = 400;
810 adapter.OnOutputFormatRequest(format);
811 EXPECT_EQ(480, adapter.output_format().width);
812 EXPECT_EQ(300, adapter.output_format().height);
813
814 // Test reason for adapting is CPU.
815 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_CPU,
816 adapter.adapt_reason());
817
818 // Encoder resolution request: downgrade.
819 adapter.OnEncoderResolutionRequest(480, 300,
820 CoordinatedVideoAdapter::DOWNGRADE);
821 EXPECT_EQ(320, adapter.output_format().width);
822 EXPECT_EQ(200, adapter.output_format().height);
823
824 // Test reason for adapting is BANDWIDTH.
825 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_BANDWIDTH,
826 adapter.adapt_reason());
827
828 // Process load and system load are low. Constrained by GD. Adapt nothing
829 adapter.OnCpuLoadUpdated(1, 1, 0.2f, 0.3f);
830 EXPECT_EQ(320, adapter.output_format().width);
831 EXPECT_EQ(200, adapter.output_format().height);
832
833 // Encoder resolution request: upgrade.
834 adapter.OnEncoderResolutionRequest(320, 200,
835 CoordinatedVideoAdapter::UPGRADE);
836 EXPECT_EQ(480, adapter.output_format().width);
837 EXPECT_EQ(300, adapter.output_format().height);
838
839 // Encoder resolution request: upgrade. Constrained by CPU.
840 adapter.OnEncoderResolutionRequest(480, 300,
841 CoordinatedVideoAdapter::UPGRADE);
842 EXPECT_EQ(480, adapter.output_format().width);
843 EXPECT_EQ(300, adapter.output_format().height);
844
845 // Server format request 640x400. Constrained by CPU.
846 format.width = 640;
847 format.height = 400;
848 adapter.OnOutputFormatRequest(format);
849 EXPECT_EQ(480, adapter.output_format().width);
850 EXPECT_EQ(300, adapter.output_format().height);
851}
852
853TEST(CoordinatedVideoAdapterTest, TestViewRequestPlusCameraSwitch) {
854 CoordinatedVideoAdapter adapter;
855 adapter.set_view_switch(true);
856
857 // Start at HD.
858 VideoFormat format(1280, 720, VideoFormat::FpsToInterval(30), FOURCC_I420);
859 adapter.SetInputFormat(format);
860 EXPECT_EQ(format, adapter.input_format());
861 EXPECT_TRUE(adapter.output_format().IsSize0x0());
862
863 // View request for VGA.
864 format.width = 640;
865 format.height = 360;
866 adapter.OnOutputFormatRequest(format);
867 EXPECT_EQ(640, adapter.output_format().width);
868 EXPECT_EQ(360, adapter.output_format().height);
869 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_VIEW, adapter.adapt_reason());
870
871 // Now, the camera reopens at VGA.
872 // Both the frame and the output format should be 640x360.
873 WebRtcVideoFrame in_frame;
874 in_frame.InitToBlack(640, 360, 1, 1, 33, 33);
875 VideoFrame* out_frame;
876 adapter.AdaptFrame(&in_frame, &out_frame);
877 EXPECT_EQ(640u, out_frame->GetWidth());
878 EXPECT_EQ(360u, out_frame->GetHeight());
879 // At this point, the view is no longer adapted, since the input has resized
880 // small enough to fit the last view request.
881 EXPECT_EQ(0, adapter.adapt_reason());
882
883 // And another view request comes in for 640x360, which should have no
884 // real impact.
885 adapter.OnOutputFormatRequest(format);
886 EXPECT_EQ(640, adapter.output_format().width);
887 EXPECT_EQ(360, adapter.output_format().height);
888 EXPECT_EQ(0, adapter.adapt_reason());
889}
890
891TEST(CoordinatedVideoAdapterTest, TestVGAWidth) {
892 CoordinatedVideoAdapter adapter;
893 adapter.set_view_switch(true);
894
895 // Start at 640x480, for cameras that don't support 640x360.
896 VideoFormat format(640, 480, VideoFormat::FpsToInterval(30), FOURCC_I420);
897 adapter.SetInputFormat(format);
898 EXPECT_EQ(format, adapter.input_format());
899 EXPECT_TRUE(adapter.output_format().IsSize0x0());
900
901 // Output format is 640x360, though.
902 format.width = 640;
903 format.height = 360;
904 adapter.SetOutputFormat(format);
905
906 // And also a view request comes for 640x360.
907 adapter.OnOutputFormatRequest(format);
908 // At this point, we have to adapt down to something lower.
909 EXPECT_EQ(480, adapter.output_format().width);
910 EXPECT_EQ(360, adapter.output_format().height);
911
912 // But if frames come in at 640x360, we shouldn't adapt them down.
913 // Fake a 640x360 frame.
914 WebRtcVideoFrame in_frame;
915 in_frame.InitToBlack(640, 360, 1, 1, 33, 33);
916 VideoFrame* out_frame;
917 adapter.AdaptFrame(&in_frame, &out_frame);
918
919 EXPECT_EQ(640u, out_frame->GetWidth());
920 EXPECT_EQ(360u, out_frame->GetHeight());
921
922 // Similarly, no-op adapt requests for other reasons shouldn't change
923 // adaptation state (before a previous bug, the previous EXPECTs would
924 // fail and the following would succeed, as the no-op CPU request would
925 // fix the adaptation state).
926 adapter.set_cpu_adaptation(true);
927 UpdateCpuLoad(&adapter, 1, 1, 0.7f, 0.7f);
928 adapter.AdaptFrame(&in_frame, &out_frame);
929
930 EXPECT_EQ(640u, out_frame->GetWidth());
931 EXPECT_EQ(360u, out_frame->GetHeight());
932}
933
934// When adapting resolution for CPU or GD, the quantity of pixels that the
935// request is based on is reduced to half or double, and then an actual
936// resolution is snapped to, rounding to the closest actual resolution.
937// This works well for some tolerance to 3/4, odd widths and aspect ratios
938// that dont exactly match, but is not best behavior for ViewRequests which
939// need to be be strictly respected to avoid going over the resolution budget
940// given to the codec - 854x480 total pixels.
941// ViewRequest must find a lower resolution.
942TEST(CoordinatedVideoAdapterTest, TestCoordinatedViewRequestDown) {
943 CoordinatedVideoAdapter adapter;
944 adapter.set_cpu_adaptation(false);
945
946 VideoFormat format(960, 540, VideoFormat::FpsToInterval(30), FOURCC_I420);
947 adapter.SetInputFormat(format);
948 adapter.set_scale_third(true);
949 EXPECT_EQ(format, adapter.input_format());
950 EXPECT_TRUE(adapter.output_format().IsSize0x0());
951
952 // Server format request 640x400. Expect HVGA.
953 format.width = 640;
954 format.height = 400;
955 adapter.OnOutputFormatRequest(format);
956 EXPECT_EQ(640, adapter.output_format().width);
957 EXPECT_EQ(360, adapter.output_format().height);
958
959 // Test reason for adapting is VIEW.
960 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_VIEW, adapter.adapt_reason());
961}
962
963// Test that we downgrade video for cpu up to two times.
964TEST(CoordinatedVideoAdapterTest, TestCpuDowngradeTimes) {
965 CoordinatedVideoAdapter adapter;
966 adapter.set_cpu_adaptation(true);
967 EXPECT_FALSE(adapter.cpu_smoothing());
968 VideoFormat format(640, 400, VideoFormat::FpsToInterval(30), FOURCC_I420);
969 adapter.SetInputFormat(format);
970
971 // Server format request 640x400.
972 format.height = 400;
973 adapter.OnOutputFormatRequest(format);
974 EXPECT_EQ(640, adapter.output_format().width);
975 EXPECT_EQ(400, adapter.output_format().height);
976
977 // Process load and system load are low. Do not change the cpu desired format
978 // and do not adapt.
979 adapter.OnCpuLoadUpdated(1, 1, 0.2f, 0.3f);
980 EXPECT_EQ(640, adapter.output_format().width);
981 EXPECT_EQ(400, adapter.output_format().height);
982
983 // System load is high. Downgrade.
984 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
985 EXPECT_EQ(480, adapter.output_format().width);
986 EXPECT_EQ(300, adapter.output_format().height);
987
988 // System load is high. Downgrade again.
989 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
990 EXPECT_EQ(320, adapter.output_format().width);
991 EXPECT_EQ(200, adapter.output_format().height);
992
993 // System load is still high. Do not downgrade any more.
994 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
995 EXPECT_EQ(320, adapter.output_format().width);
996 EXPECT_EQ(200, adapter.output_format().height);
997
998 // Process load and system load are low. Upgrade.
999 UpdateCpuLoad(&adapter, 1, 1, 0.2f, 0.3f);
1000 EXPECT_EQ(480, adapter.output_format().width);
1001 EXPECT_EQ(300, adapter.output_format().height);
1002
1003 // System load is high. Downgrade.
1004 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
1005 EXPECT_EQ(320, adapter.output_format().width);
1006 EXPECT_EQ(200, adapter.output_format().height);
1007
1008 // System load is still high. Do not downgrade any more.
1009 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
1010 EXPECT_EQ(320, adapter.output_format().width);
1011 EXPECT_EQ(200, adapter.output_format().height);
1012}
1013
1014// Test that we respect CPU adapter threshold values.
1015TEST(CoordinatedVideoAdapterTest, TestAdapterCpuThreshold) {
1016 CoordinatedVideoAdapter adapter;
1017 adapter.set_cpu_adaptation(true);
1018 EXPECT_FALSE(adapter.cpu_smoothing());
1019 VideoFormat format(640, 400, VideoFormat::FpsToInterval(30), FOURCC_I420);
1020 adapter.SetInputFormat(format);
1021
1022 // Server format request 640x400.
1023 format.height = 400;
1024 adapter.OnOutputFormatRequest(format);
1025 EXPECT_EQ(640, adapter.output_format().width);
1026 EXPECT_EQ(400, adapter.output_format().height);
1027
1028 // Process load and system load are low. Do not change the cpu desired format
1029 // and do not adapt.
1030 adapter.OnCpuLoadUpdated(1, 1, 0.2f, 0.3f);
1031 EXPECT_EQ(640, adapter.output_format().width);
1032 EXPECT_EQ(400, adapter.output_format().height);
1033
1034 // System load is high. Downgrade.
1035 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
1036 EXPECT_EQ(480, adapter.output_format().width);
1037 EXPECT_EQ(300, adapter.output_format().height);
1038
1039 // Test reason for adapting is CPU.
1040 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_CPU, adapter.adapt_reason());
1041
1042 // System load is high. Normally downgrade but threshold is high. Do nothing.
1043 adapter.set_high_system_threshold(0.98f); // Set threshold high.
1044 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
1045 EXPECT_EQ(480, adapter.output_format().width);
1046 EXPECT_EQ(300, adapter.output_format().height);
1047
1048 // System load is medium. Normally do nothing, threshold is low. Adapt down.
1049 adapter.set_high_system_threshold(0.75f); // Set threshold low.
1050 UpdateCpuLoad(&adapter, 1, 1, 0.8f, 0.8f);
1051 EXPECT_EQ(320, adapter.output_format().width);
1052 EXPECT_EQ(200, adapter.output_format().height);
1053}
1054
1055
1056// Test that for an upgrade cpu request, we actually upgrade the desired format;
1057// for a downgrade request, we downgrade from the output format.
1058TEST(CoordinatedVideoAdapterTest, TestRealCpuUpgrade) {
1059 CoordinatedVideoAdapter adapter;
1060 adapter.set_cpu_adaptation(true);
1061 adapter.set_cpu_smoothing(true);
1062 VideoFormat format(640, 400, VideoFormat::FpsToInterval(30), FOURCC_I420);
1063 adapter.SetInputFormat(format);
1064
1065 // Server format request 640x400.
1066 format.width = 640;
1067 format.height = 400;
1068 adapter.OnOutputFormatRequest(format);
1069 EXPECT_EQ(640, adapter.output_format().width);
1070 EXPECT_EQ(400, adapter.output_format().height);
1071
1072 // Process load and system load are low. Do not change the cpu desired format
1073 // and do not adapt.
1074 UpdateCpuLoad(&adapter, 1, 1, 0.2f, 0.3f);
1075 EXPECT_EQ(640, adapter.output_format().width);
1076 EXPECT_EQ(400, adapter.output_format().height);
1077
1078 // Server format request 320x200.
1079 format.width = 320;
1080 format.height = 200;
1081 adapter.OnOutputFormatRequest(format);
1082 EXPECT_EQ(320, adapter.output_format().width);
1083 EXPECT_EQ(200, adapter.output_format().height);
1084
1085 // Process load and system load are low. Do not change the cpu desired format
1086 // and do not adapt.
1087 UpdateCpuLoad(&adapter, 1, 1, 0.2f, 0.3f);
1088 EXPECT_EQ(320, adapter.output_format().width);
1089 EXPECT_EQ(200, adapter.output_format().height);
1090
1091 // Server format request 640x400. Set to 640x400 immediately.
1092 format.width = 640;
1093 format.height = 400;
1094 adapter.OnOutputFormatRequest(format);
1095 EXPECT_EQ(640, adapter.output_format().width);
1096 EXPECT_EQ(400, adapter.output_format().height);
1097
1098 // Server format request 320x200.
1099 format.width = 320;
1100 format.height = 200;
1101 adapter.OnOutputFormatRequest(format);
1102 EXPECT_EQ(320, adapter.output_format().width);
1103 EXPECT_EQ(200, adapter.output_format().height);
1104
1105 // Process load is high, but system is not. Do not change the cpu desired
1106 // format and do not adapt.
1107 for (size_t i = 0; i < 10; ++i) {
1108 UpdateCpuLoad(&adapter, 1, 1, 0.75f, 0.8f);
1109 }
1110 EXPECT_EQ(320, adapter.output_format().width);
1111 EXPECT_EQ(200, adapter.output_format().height);
1112}
1113
1114// Test that for an upgrade encoder request, we actually upgrade the desired
1115// format; for a downgrade request, we downgrade from the output format.
1116TEST(CoordinatedVideoAdapterTest, TestRealEncoderUpgrade) {
1117 CoordinatedVideoAdapter adapter;
1118 adapter.set_cpu_adaptation(true);
1119 adapter.set_cpu_smoothing(true);
1120 VideoFormat format(640, 400, VideoFormat::FpsToInterval(30), FOURCC_I420);
1121 adapter.SetInputFormat(format);
1122
1123 // Server format request 640x400.
1124 format.width = 640;
1125 format.height = 400;
1126 adapter.OnOutputFormatRequest(format);
1127 EXPECT_EQ(640, adapter.output_format().width);
1128 EXPECT_EQ(400, adapter.output_format().height);
1129
1130 // Encoder resolution request. Do not change the encoder desired format and
1131 // do not adapt.
1132 adapter.OnEncoderResolutionRequest(640, 400,
1133 CoordinatedVideoAdapter::UPGRADE);
1134 EXPECT_EQ(640, adapter.output_format().width);
1135 EXPECT_EQ(400, adapter.output_format().height);
1136
1137 // Server format request 320x200.
1138 format.width = 320;
1139 format.height = 200;
1140 adapter.OnOutputFormatRequest(format);
1141 EXPECT_EQ(320, adapter.output_format().width);
1142 EXPECT_EQ(200, adapter.output_format().height);
1143
1144 // Encoder resolution request. Do not change the encoder desired format and
1145 // do not adapt.
1146 adapter.OnEncoderResolutionRequest(320, 200,
1147 CoordinatedVideoAdapter::UPGRADE);
1148 EXPECT_EQ(320, adapter.output_format().width);
1149 EXPECT_EQ(200, adapter.output_format().height);
1150
1151 // Server format request 640x400. Set to 640x400 immediately.
1152 format.width = 640;
1153 format.height = 400;
1154 adapter.OnOutputFormatRequest(format);
1155 EXPECT_EQ(480, adapter.output_format().width);
1156 EXPECT_EQ(300, adapter.output_format().height);
1157
1158 // Test reason for adapting is BANDWIDTH.
1159 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_BANDWIDTH,
1160 adapter.adapt_reason());
1161
1162 // Server format request 320x200.
1163 format.width = 320;
1164 format.height = 200;
1165 adapter.OnOutputFormatRequest(format);
1166 EXPECT_EQ(320, adapter.output_format().width);
1167 EXPECT_EQ(200, adapter.output_format().height);
1168
1169 // Encoder resolution request. Downgrade from 320x200.
1170 adapter.OnEncoderResolutionRequest(320, 200,
1171 CoordinatedVideoAdapter::DOWNGRADE);
1172 EXPECT_EQ(240, adapter.output_format().width);
1173 EXPECT_EQ(150, adapter.output_format().height);
1174}
1175
1176TEST(CoordinatedVideoAdapterTest, TestNormalizeOutputFormat) {
1177 CoordinatedVideoAdapter adapter;
1178 // The input format is 640x360 and the output is limited to 16:9.
1179 VideoFormat format(640, 360, VideoFormat::FpsToInterval(30), FOURCC_I420);
1180 adapter.SetInputFormat(format);
1181
1182 format.width = 320;
1183 format.height = 180;
1184 format.interval = VideoFormat::FpsToInterval(15);
1185 adapter.OnOutputFormatRequest(format);
1186 EXPECT_EQ(320, adapter.output_format().width);
1187 EXPECT_EQ(180, adapter.output_format().height);
1188 EXPECT_EQ(VideoFormat::FpsToInterval(15), adapter.output_format().interval);
1189
1190 format.width = 320;
1191 format.height = 200;
1192 format.interval = VideoFormat::FpsToInterval(40);
1193 adapter.OnOutputFormatRequest(format);
1194 EXPECT_EQ(320, adapter.output_format().width);
1195 EXPECT_EQ(180, adapter.output_format().height);
1196 EXPECT_EQ(VideoFormat::FpsToInterval(30), adapter.output_format().interval);
1197
1198 // Test reason for adapting is VIEW. Should work even with normalization.
1199 EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_VIEW,
1200 adapter.adapt_reason());
1201
1202 format.width = 320;
1203 format.height = 240;
1204 adapter.OnOutputFormatRequest(format);
1205 EXPECT_EQ(320, adapter.output_format().width);
1206 EXPECT_EQ(180, adapter.output_format().height);
1207
1208 // The input format is 640x480 and the output will be 4:3.
1209 format.width = 640;
1210 format.height = 480;
1211 adapter.SetInputFormat(format);
1212 EXPECT_EQ(320, adapter.output_format().width);
1213 EXPECT_EQ(240, adapter.output_format().height);
1214
1215 format.width = 320;
1216 format.height = 240;
1217 adapter.OnOutputFormatRequest(format);
1218 EXPECT_EQ(320, adapter.output_format().width);
1219 EXPECT_EQ(240, adapter.output_format().height);
1220
1221 // The input format is initialized after the output. At that time, the output
1222 // height is adjusted.
1223 format.width = 0;
1224 format.height = 0;
1225 adapter.SetInputFormat(format);
1226
1227 format.width = 320;
1228 format.height = 240;
1229 format.interval = VideoFormat::FpsToInterval(30);
1230 adapter.OnOutputFormatRequest(format);
1231 EXPECT_EQ(320, adapter.output_format().width);
1232 EXPECT_EQ(240, adapter.output_format().height);
1233 EXPECT_EQ(VideoFormat::FpsToInterval(30), adapter.output_format().interval);
1234
1235 format.width = 640;
1236 format.height = 480;
1237 format.interval = VideoFormat::FpsToInterval(15);
1238 adapter.SetInputFormat(format);
1239 EXPECT_EQ(320, adapter.output_format().width);
1240 EXPECT_EQ(240, adapter.output_format().height);
1241 EXPECT_EQ(VideoFormat::FpsToInterval(15), adapter.output_format().interval);
1242}
1243
1244// Test that we downgrade video for cpu up to two times.
1245TEST_F(VideoAdapterTest, CpuDowngradeAndSignal) {
1246 CoordinatedVideoAdapter adapter;
1247 CpuAdapterListener cpu_listener;
1248 adapter.SignalCpuAdaptationUnable.connect(
1249 &cpu_listener, &CpuAdapterListener::OnCpuAdaptationSignalled);
1250
1251 adapter.set_cpu_adaptation(true);
1252 EXPECT_FALSE(adapter.cpu_smoothing());
1253 VideoFormat format(640, 360, VideoFormat::FpsToInterval(30), FOURCC_I420);
1254 adapter.SetInputFormat(format);
1255 adapter.OnOutputFormatRequest(format);
1256
1257 // System load is high. Downgrade.
1258 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
1259
1260 // System load is high. Downgrade again.
1261 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
1262
1263 // System load is still high. Do not downgrade any more. Ensure we have not
1264 // signalled until after the cpu warning though.
1265 EXPECT_TRUE(!cpu_listener.received_cpu_signal());
1266 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
1267 EXPECT_TRUE_WAIT(cpu_listener.received_cpu_signal(), kWaitTimeout);
1268}
1269
1270// Test that we downgrade video for cpu up to two times.
1271TEST_F(VideoAdapterTest, CpuDowngradeAndDontSignal) {
1272 CoordinatedVideoAdapter adapter;
1273 CpuAdapterListener cpu_listener;
1274 adapter.SignalCpuAdaptationUnable.connect(
1275 &cpu_listener, &CpuAdapterListener::OnCpuAdaptationSignalled);
1276
1277 adapter.set_cpu_adaptation(true);
1278 adapter.set_cpu_smoothing(true);
1279 VideoFormat format(640, 360, VideoFormat::FpsToInterval(30), FOURCC_I420);
1280 adapter.SetInputFormat(format);
1281 adapter.OnOutputFormatRequest(format);
1282
1283 // System load is high. Downgrade.
1284 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
1285
1286 // System load is high, process is not, Do not downgrade again.
1287 UpdateCpuLoad(&adapter, 1, 1, 0.25f, 0.95f);
1288
1289 // System load is high, process is not, Do not downgrade again and do not
1290 // signal.
1291 adapter.set_cpu_adaptation(false);
1292 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
1293 rtc::Thread::Current()->ProcessMessages(kShortWaitTimeout);
1294 EXPECT_TRUE(!cpu_listener.received_cpu_signal());
1295 adapter.set_cpu_adaptation(true);
1296}
1297
1298// Test that we require enough time before we downgrade.
1299TEST_F(VideoAdapterTest, CpuMinTimeRequirement) {
1300 CoordinatedVideoAdapter adapter;
1301 CpuAdapterListener cpu_listener;
1302 adapter.SignalCpuAdaptationUnable.connect(
1303 &cpu_listener, &CpuAdapterListener::OnCpuAdaptationSignalled);
1304
1305 adapter.set_cpu_adaptation(true);
1306 adapter.set_cpu_smoothing(true);
1307 VideoFormat format(640, 360, VideoFormat::FpsToInterval(30), FOURCC_I420);
1308 adapter.SetInputFormat(format);
1309 adapter.OnOutputFormatRequest(format);
1310
1311 EXPECT_EQ(3, adapter.cpu_load_min_samples());
1312 adapter.set_cpu_load_min_samples(5);
1313
1314 for (size_t i = 0; i < 4; ++i) {
1315 adapter.OnCpuLoadUpdated(1, 1, 1.0f, 1.0f);
1316 EXPECT_EQ(640, adapter.output_format().width);
1317 EXPECT_EQ(360, adapter.output_format().height);
1318 }
1319 // The computed cpu load should now be around 93.5%, with the coefficient of
1320 // 0.4 and a seed value of 0.5. That should be high enough to adapt, but it
1321 // isn't enough samples, so we shouldn't have adapted on any of the previous
1322 // samples.
1323
1324 // One more sample is enough, though, once enough time has passed.
1325 adapter.OnCpuLoadUpdated(1, 1, 1.0f, 1.0f);
1326 EXPECT_EQ(480, adapter.output_format().width);
1327 EXPECT_EQ(270, adapter.output_format().height);
1328
1329 // Now the cpu is lower, but we still need enough samples to upgrade.
1330 for (size_t i = 0; i < 4; ++i) {
1331 adapter.OnCpuLoadUpdated(1, 1, 0.1f, 0.1f);
1332 EXPECT_EQ(480, adapter.output_format().width);
1333 EXPECT_EQ(270, adapter.output_format().height);
1334 }
1335
1336 // One more sample is enough, once time has elapsed.
1337 adapter.OnCpuLoadUpdated(1, 1, 1.0f, 1.0f);
1338 EXPECT_EQ(640, adapter.output_format().width);
1339 EXPECT_EQ(360, adapter.output_format().height);
1340}
1341
1342TEST_F(VideoAdapterTest, CpuIgnoresSpikes) {
1343 CoordinatedVideoAdapter adapter;
1344 CpuAdapterListener cpu_listener;
1345 adapter.SignalCpuAdaptationUnable.connect(
1346 &cpu_listener, &CpuAdapterListener::OnCpuAdaptationSignalled);
1347
1348 adapter.set_cpu_adaptation(true);
1349 adapter.set_cpu_smoothing(true);
1350 VideoFormat format(640, 360, VideoFormat::FpsToInterval(30), FOURCC_I420);
1351 adapter.SetInputFormat(format);
1352 adapter.OnOutputFormatRequest(format);
1353
1354 // System load is high. Downgrade.
1355 for (size_t i = 0; i < 5; ++i) {
1356 UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
1357 }
1358 EXPECT_EQ(480, adapter.output_format().width);
1359 EXPECT_EQ(270, adapter.output_format().height);
1360
1361 // Now we're in a state where we could upgrade or downgrade, so get to a
1362 // steady state of about 75% cpu usage.
1363 for (size_t i = 0; i < 5; ++i) {
1364 UpdateCpuLoad(&adapter, 1, 1, 0.75f, 0.75f);
1365 EXPECT_EQ(480, adapter.output_format().width);
1366 EXPECT_EQ(270, adapter.output_format().height);
1367 }
1368
1369 // Now, the cpu spikes for two samples, but then goes back to
1370 // normal. This shouldn't cause adaptation.
1371 UpdateCpuLoad(&adapter, 1, 1, 0.90f, 0.90f);
1372 UpdateCpuLoad(&adapter, 1, 1, 0.90f, 0.90f);
1373 EXPECT_EQ(480, adapter.output_format().width);
1374 EXPECT_EQ(270, adapter.output_format().height);
1375 // Back to the steady state for awhile.
1376 for (size_t i = 0; i < 5; ++i) {
1377 UpdateCpuLoad(&adapter, 1, 1, 0.75, 0.75);
1378 EXPECT_EQ(480, adapter.output_format().width);
1379 EXPECT_EQ(270, adapter.output_format().height);
1380 }
1381
1382 // Now, system cpu usage is starting to drop down. But it takes a bit before
1383 // it gets all the way there.
1384 for (size_t i = 0; i < 10; ++i) {
1385 UpdateCpuLoad(&adapter, 1, 1, 0.5f, 0.5f);
1386 }
1387 EXPECT_EQ(640, adapter.output_format().width);
1388 EXPECT_EQ(360, adapter.output_format().height);
1389}
1390
1391} // namespace cricket
1392#endif // HAVE_WEBRTC_VIDEO