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