a09a99950e
git-svn-id: http://webrtc.googlecode.com/svn/trunk@6891 4adac7df-926f-26a2-2b94-8c16560cd09d
1286 lines
49 KiB
C++
Executable File
1286 lines
49 KiB
C++
Executable File
/*
|
|
* libjingle
|
|
* Copyright 2010 Google Inc.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
* 3. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
// If we don't have a WebRtcVideoFrame, just skip all of these tests.
|
|
#if defined(HAVE_WEBRTC_VIDEO)
|
|
#include <limits.h> // For INT_MAX
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "talk/media/base/mediachannel.h"
|
|
#include "talk/media/base/testutils.h"
|
|
#include "talk/media/base/videoadapter.h"
|
|
#include "talk/media/devices/filevideocapturer.h"
|
|
#include "talk/media/webrtc/webrtcvideoframe.h"
|
|
#include "webrtc/base/gunit.h"
|
|
#include "webrtc/base/logging.h"
|
|
#include "webrtc/base/sigslot.h"
|
|
|
|
namespace cricket {
|
|
|
|
namespace {
|
|
static const uint32 kWaitTimeout = 3000U; // 3 seconds.
|
|
static const uint32 kShortWaitTimeout = 1000U; // 1 second.
|
|
void UpdateCpuLoad(CoordinatedVideoAdapter* adapter,
|
|
int current_cpus, int max_cpus, float process_load, float system_load) {
|
|
adapter->set_cpu_load_min_samples(1);
|
|
adapter->OnCpuLoadUpdated(current_cpus, max_cpus,
|
|
process_load, system_load);
|
|
}
|
|
}
|
|
|
|
class VideoAdapterTest : public testing::Test {
|
|
public:
|
|
virtual void SetUp() {
|
|
capturer_.reset(new FileVideoCapturer);
|
|
EXPECT_TRUE(capturer_->Init(GetTestFilePath(
|
|
"captured-320x240-2s-48.frames")));
|
|
capture_format_ = capturer_->GetSupportedFormats()->at(0);
|
|
capture_format_.interval = VideoFormat::FpsToInterval(50);
|
|
adapter_.reset(new VideoAdapter());
|
|
adapter_->SetInputFormat(capture_format_);
|
|
|
|
listener_.reset(new VideoCapturerListener(adapter_.get()));
|
|
capturer_->SignalFrameCaptured.connect(
|
|
listener_.get(), &VideoCapturerListener::OnFrameCaptured);
|
|
}
|
|
|
|
void VerifyAdaptedResolution(int width, int height) {
|
|
EXPECT_TRUE(NULL != listener_->adapted_frame());
|
|
EXPECT_EQ(static_cast<size_t>(width),
|
|
listener_->adapted_frame()->GetWidth());
|
|
EXPECT_EQ(static_cast<size_t>(height),
|
|
listener_->adapted_frame()->GetHeight());
|
|
}
|
|
|
|
protected:
|
|
class VideoCapturerListener: public sigslot::has_slots<> {
|
|
public:
|
|
explicit VideoCapturerListener(VideoAdapter* adapter)
|
|
: video_adapter_(adapter),
|
|
adapted_frame_(NULL),
|
|
copied_output_frame_(),
|
|
captured_frames_(0),
|
|
dropped_frames_(0),
|
|
last_adapt_was_no_op_(false) {
|
|
}
|
|
|
|
void OnFrameCaptured(VideoCapturer* capturer,
|
|
const CapturedFrame* captured_frame) {
|
|
WebRtcVideoFrame temp_i420;
|
|
EXPECT_TRUE(temp_i420.Init(captured_frame,
|
|
captured_frame->width, abs(captured_frame->height)));
|
|
VideoFrame* out_frame = NULL;
|
|
EXPECT_TRUE(video_adapter_->AdaptFrame(&temp_i420, &out_frame));
|
|
if (out_frame) {
|
|
if (out_frame == &temp_i420) {
|
|
last_adapt_was_no_op_ = true;
|
|
copied_output_frame_.reset(temp_i420.Copy());
|
|
adapted_frame_ = copied_output_frame_.get();
|
|
} else {
|
|
last_adapt_was_no_op_ = false;
|
|
adapted_frame_ = out_frame;
|
|
copied_output_frame_.reset();
|
|
}
|
|
} else {
|
|
++dropped_frames_;
|
|
}
|
|
++captured_frames_;
|
|
}
|
|
|
|
const VideoFrame* adapted_frame() const { return adapted_frame_; }
|
|
int captured_frames() const { return captured_frames_; }
|
|
int dropped_frames() const { return dropped_frames_; }
|
|
bool last_adapt_was_no_op() const { return last_adapt_was_no_op_; }
|
|
|
|
private:
|
|
VideoAdapter* video_adapter_;
|
|
const VideoFrame* adapted_frame_;
|
|
rtc::scoped_ptr<VideoFrame> copied_output_frame_;
|
|
int captured_frames_;
|
|
int dropped_frames_;
|
|
bool last_adapt_was_no_op_;
|
|
};
|
|
|
|
class CpuAdapterListener: public sigslot::has_slots<> {
|
|
public:
|
|
CpuAdapterListener() : received_cpu_signal_(false) {}
|
|
void OnCpuAdaptationSignalled() { received_cpu_signal_ = true; }
|
|
bool received_cpu_signal() { return received_cpu_signal_; }
|
|
private:
|
|
bool received_cpu_signal_;
|
|
};
|
|
|
|
rtc::scoped_ptr<FileVideoCapturer> capturer_;
|
|
rtc::scoped_ptr<VideoAdapter> adapter_;
|
|
rtc::scoped_ptr<VideoCapturerListener> listener_;
|
|
VideoFormat capture_format_;
|
|
};
|
|
|
|
|
|
// Test adapter remembers exact pixel count
|
|
TEST_F(VideoAdapterTest, AdaptNumPixels) {
|
|
adapter_->SetOutputNumPixels(123456);
|
|
EXPECT_EQ(123456, adapter_->GetOutputNumPixels());
|
|
}
|
|
|
|
// Test adapter is constructed but not activated. Expect no frame drop and no
|
|
// resolution change.
|
|
TEST_F(VideoAdapterTest, AdaptInactive) {
|
|
// Output resolution is not set.
|
|
EXPECT_EQ(INT_MAX, adapter_->GetOutputNumPixels());
|
|
|
|
// Call Adapter with some frames.
|
|
EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
|
|
EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
|
|
listener_->captured_frames() >= 10, kWaitTimeout);
|
|
|
|
// Verify no frame drop and no resolution change.
|
|
EXPECT_GE(listener_->captured_frames(), 10);
|
|
EXPECT_EQ(0, listener_->dropped_frames());
|
|
VerifyAdaptedResolution(capture_format_.width, capture_format_.height);
|
|
}
|
|
|
|
// Do not adapt the frame rate or the resolution. Expect no frame drop and no
|
|
// resolution change.
|
|
TEST_F(VideoAdapterTest, AdaptNothing) {
|
|
adapter_->SetOutputFormat(capture_format_);
|
|
EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
|
|
EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
|
|
listener_->captured_frames() >= 10, kWaitTimeout);
|
|
|
|
// Verify no frame drop and no resolution change.
|
|
EXPECT_GE(listener_->captured_frames(), 10);
|
|
EXPECT_EQ(0, listener_->dropped_frames());
|
|
VerifyAdaptedResolution(capture_format_.width, capture_format_.height);
|
|
EXPECT_TRUE(listener_->last_adapt_was_no_op());
|
|
}
|
|
|
|
TEST_F(VideoAdapterTest, AdaptZeroInterval) {
|
|
VideoFormat format = capturer_->GetSupportedFormats()->at(0);
|
|
format.interval = 0;
|
|
adapter_->SetInputFormat(format);
|
|
adapter_->SetOutputFormat(format);
|
|
EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
|
|
EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
|
|
listener_->captured_frames() >= 10, kWaitTimeout);
|
|
|
|
// Verify no crash and that frames aren't dropped.
|
|
EXPECT_GE(listener_->captured_frames(), 10);
|
|
EXPECT_EQ(0, listener_->dropped_frames());
|
|
VerifyAdaptedResolution(capture_format_.width, capture_format_.height);
|
|
}
|
|
|
|
// Adapt the frame rate to be half of the capture rate at the beginning. Expect
|
|
// the number of dropped frames to be half of the number the captured frames.
|
|
TEST_F(VideoAdapterTest, AdaptFramerate) {
|
|
VideoFormat request_format = capture_format_;
|
|
request_format.interval *= 2;
|
|
adapter_->SetOutputFormat(request_format);
|
|
EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
|
|
EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
|
|
listener_->captured_frames() >= 10, kWaitTimeout);
|
|
|
|
// Verify frame drop and no resolution change.
|
|
EXPECT_GE(listener_->captured_frames(), 10);
|
|
EXPECT_EQ(listener_->captured_frames() / 2, listener_->dropped_frames());
|
|
VerifyAdaptedResolution(capture_format_.width, capture_format_.height);
|
|
}
|
|
|
|
// Adapt the frame rate to be half of the capture rate at the beginning. Expect
|
|
// the number of dropped frames to be half of the number the captured frames.
|
|
TEST_F(VideoAdapterTest, AdaptFramerateVariable) {
|
|
VideoFormat request_format = capture_format_;
|
|
request_format.interval = request_format.interval * 3 / 2;
|
|
adapter_->SetOutputFormat(request_format);
|
|
EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
|
|
EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
|
|
listener_->captured_frames() >= 30, kWaitTimeout);
|
|
|
|
// Verify frame drop and no resolution change.
|
|
EXPECT_GE(listener_->captured_frames(), 30);
|
|
// Verify 2 / 3 kept (20) and 1 / 3 dropped (10).
|
|
EXPECT_EQ(listener_->captured_frames() * 1 / 3, listener_->dropped_frames());
|
|
VerifyAdaptedResolution(capture_format_.width, capture_format_.height);
|
|
}
|
|
|
|
// Adapt the frame rate to be half of the capture rate after capturing no less
|
|
// than 10 frames. Expect no frame dropped before adaptation and frame dropped
|
|
// after adaptation.
|
|
TEST_F(VideoAdapterTest, AdaptFramerateOntheFly) {
|
|
VideoFormat request_format = capture_format_;
|
|
adapter_->SetOutputFormat(request_format);
|
|
EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
|
|
EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
|
|
listener_->captured_frames() >= 10, kWaitTimeout);
|
|
|
|
// Verify no frame drop before adaptation.
|
|
EXPECT_EQ(0, listener_->dropped_frames());
|
|
|
|
// Adapat the frame rate.
|
|
request_format.interval *= 2;
|
|
adapter_->SetOutputFormat(request_format);
|
|
|
|
EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
|
|
listener_->captured_frames() >= 20, kWaitTimeout);
|
|
|
|
// Verify frame drop after adaptation.
|
|
EXPECT_GT(listener_->dropped_frames(), 0);
|
|
}
|
|
|
|
// Adapt the frame resolution to be a quarter of the capture resolution at the
|
|
// beginning. Expect resolution change.
|
|
TEST_F(VideoAdapterTest, AdaptResolution) {
|
|
VideoFormat request_format = capture_format_;
|
|
request_format.width /= 2;
|
|
request_format.height /= 2;
|
|
adapter_->SetOutputFormat(request_format);
|
|
EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
|
|
EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
|
|
listener_->captured_frames() >= 10, kWaitTimeout);
|
|
|
|
// Verify no frame drop and resolution change.
|
|
EXPECT_EQ(0, listener_->dropped_frames());
|
|
VerifyAdaptedResolution(request_format.width, request_format.height);
|
|
}
|
|
|
|
// Adapt the frame resolution to half width. Expect resolution change.
|
|
TEST_F(VideoAdapterTest, AdaptResolutionNarrow) {
|
|
VideoFormat request_format = capture_format_;
|
|
request_format.width /= 2;
|
|
adapter_->set_scale_third(true);
|
|
adapter_->SetOutputFormat(request_format);
|
|
EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
|
|
EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
|
|
listener_->captured_frames() >= 10, kWaitTimeout);
|
|
|
|
// Verify resolution change.
|
|
VerifyAdaptedResolution(213, 160);
|
|
}
|
|
|
|
// Adapt the frame resolution to half height. Expect resolution change.
|
|
TEST_F(VideoAdapterTest, AdaptResolutionWide) {
|
|
VideoFormat request_format = capture_format_;
|
|
request_format.height /= 2;
|
|
adapter_->set_scale_third(true);
|
|
adapter_->SetOutputFormat(request_format);
|
|
EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
|
|
EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
|
|
listener_->captured_frames() >= 10, kWaitTimeout);
|
|
|
|
// Verify resolution change.
|
|
VerifyAdaptedResolution(213, 160);
|
|
}
|
|
|
|
// Adapt the frame resolution to be a quarter of the capture resolution after
|
|
// capturing no less than 10 frames. Expect no resolution change before
|
|
// adaptation and resolution change after adaptation.
|
|
TEST_F(VideoAdapterTest, AdaptResolutionOnTheFly) {
|
|
VideoFormat request_format = capture_format_;
|
|
adapter_->SetOutputFormat(request_format);
|
|
EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
|
|
EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
|
|
listener_->captured_frames() >= 10, kWaitTimeout);
|
|
|
|
// Verify no resolution change before adaptation.
|
|
VerifyAdaptedResolution(request_format.width, request_format.height);
|
|
|
|
// Adapt the frame resolution.
|
|
request_format.width /= 2;
|
|
request_format.height /= 2;
|
|
adapter_->SetOutputFormat(request_format);
|
|
EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
|
|
listener_->captured_frames() >= 20, kWaitTimeout);
|
|
|
|
|
|
// Verify resolution change after adaptation.
|
|
VerifyAdaptedResolution(request_format.width, request_format.height);
|
|
}
|
|
|
|
// Black the output frame.
|
|
TEST_F(VideoAdapterTest, BlackOutput) {
|
|
adapter_->SetOutputFormat(capture_format_);
|
|
EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
|
|
EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
|
|
listener_->captured_frames() >= 10, kWaitTimeout);
|
|
// Verify that the output frame is not black.
|
|
EXPECT_NE(16, *listener_->adapted_frame()->GetYPlane());
|
|
EXPECT_NE(128, *listener_->adapted_frame()->GetUPlane());
|
|
EXPECT_NE(128, *listener_->adapted_frame()->GetVPlane());
|
|
|
|
adapter_->SetBlackOutput(true);
|
|
EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
|
|
listener_->captured_frames() >= 20, kWaitTimeout);
|
|
// Verify that the output frame is black.
|
|
EXPECT_EQ(16, *listener_->adapted_frame()->GetYPlane());
|
|
EXPECT_EQ(128, *listener_->adapted_frame()->GetUPlane());
|
|
EXPECT_EQ(128, *listener_->adapted_frame()->GetVPlane());
|
|
|
|
// Verify that the elapsed time and timestamp of the black frame increase.
|
|
int64 elapsed_time = listener_->adapted_frame()->GetElapsedTime();
|
|
int64 timestamp = listener_->adapted_frame()->GetTimeStamp();
|
|
EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
|
|
listener_->captured_frames() >= 22, kWaitTimeout);
|
|
EXPECT_GT(listener_->adapted_frame()->GetElapsedTime(), elapsed_time);
|
|
EXPECT_GT(listener_->adapted_frame()->GetTimeStamp(), timestamp);
|
|
|
|
// Change the output size
|
|
VideoFormat request_format = capture_format_;
|
|
request_format.width /= 2;
|
|
request_format.height /= 2;
|
|
adapter_->SetOutputFormat(request_format);
|
|
|
|
EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
|
|
listener_->captured_frames() >= 40, kWaitTimeout);
|
|
// Verify resolution change after adaptation.
|
|
VerifyAdaptedResolution(request_format.width, request_format.height);
|
|
// Verify that the output frame is black.
|
|
EXPECT_EQ(16, *listener_->adapted_frame()->GetYPlane());
|
|
EXPECT_EQ(128, *listener_->adapted_frame()->GetUPlane());
|
|
EXPECT_EQ(128, *listener_->adapted_frame()->GetVPlane());
|
|
}
|
|
|
|
// Drop all frames.
|
|
TEST_F(VideoAdapterTest, DropAllFrames) {
|
|
VideoFormat format; // with resolution 0x0.
|
|
adapter_->SetOutputFormat(format);
|
|
EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_));
|
|
EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
|
|
listener_->captured_frames() >= 10, kWaitTimeout);
|
|
|
|
// Verify all frames are dropped.
|
|
EXPECT_GE(listener_->captured_frames(), 10);
|
|
EXPECT_EQ(listener_->captured_frames(), listener_->dropped_frames());
|
|
}
|
|
|
|
TEST(CoordinatedVideoAdapterTest, TestCoordinatedWithoutCpuAdaptation) {
|
|
CoordinatedVideoAdapter adapter;
|
|
adapter.set_cpu_adaptation(false);
|
|
|
|
VideoFormat format(640, 400, VideoFormat::FpsToInterval(30), FOURCC_I420);
|
|
adapter.SetInputFormat(format);
|
|
adapter.set_scale_third(true);
|
|
EXPECT_EQ(format, adapter.input_format());
|
|
EXPECT_TRUE(adapter.output_format().IsSize0x0());
|
|
|
|
// Server format request 640x400.
|
|
format.height = 400;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(640, adapter.output_format().width);
|
|
EXPECT_EQ(400, adapter.output_format().height);
|
|
|
|
// Server format request 1280x720, higher than input. Adapt nothing.
|
|
format.width = 1280;
|
|
format.height = 720;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(640, adapter.output_format().width);
|
|
EXPECT_EQ(400, adapter.output_format().height);
|
|
|
|
// Cpu load is high, but cpu adaptation is disabled. Adapt nothing.
|
|
adapter.OnCpuLoadUpdated(1, 1, 0.99f, 0.99f);
|
|
EXPECT_EQ(640, adapter.output_format().width);
|
|
EXPECT_EQ(400, adapter.output_format().height);
|
|
|
|
// Encoder resolution request: downgrade with different size. Adapt nothing.
|
|
adapter.OnEncoderResolutionRequest(320, 200,
|
|
CoordinatedVideoAdapter::DOWNGRADE);
|
|
EXPECT_EQ(640, adapter.output_format().width);
|
|
EXPECT_EQ(400, adapter.output_format().height);
|
|
|
|
// Encoder resolution request: downgrade.
|
|
adapter.OnEncoderResolutionRequest(640, 400,
|
|
CoordinatedVideoAdapter::DOWNGRADE);
|
|
EXPECT_EQ(480, adapter.output_format().width);
|
|
EXPECT_EQ(300, adapter.output_format().height);
|
|
|
|
// Encoder resolution request: downgrade. But GD off. Adapt nothing.
|
|
adapter.set_gd_adaptation(false);
|
|
adapter.OnEncoderResolutionRequest(480, 300,
|
|
CoordinatedVideoAdapter::DOWNGRADE);
|
|
EXPECT_EQ(480, adapter.output_format().width);
|
|
EXPECT_EQ(300, adapter.output_format().height);
|
|
adapter.set_gd_adaptation(true);
|
|
|
|
// Encoder resolution request: downgrade.
|
|
adapter.OnEncoderResolutionRequest(480, 300,
|
|
CoordinatedVideoAdapter::DOWNGRADE);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(200, adapter.output_format().height);
|
|
|
|
// Encoder resolution request: keep. Adapt nothing.
|
|
adapter.OnEncoderResolutionRequest(320, 200,
|
|
CoordinatedVideoAdapter::KEEP);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(200, adapter.output_format().height);
|
|
|
|
// Encoder resolution request: upgrade.
|
|
adapter.OnEncoderResolutionRequest(320, 200,
|
|
CoordinatedVideoAdapter::UPGRADE);
|
|
EXPECT_EQ(480, adapter.output_format().width);
|
|
EXPECT_EQ(300, adapter.output_format().height);
|
|
|
|
// Server format request 0x0.
|
|
format.width = 0;
|
|
format.height = 0;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_TRUE(adapter.output_format().IsSize0x0());
|
|
|
|
// Server format request 320x200.
|
|
format.width = 320;
|
|
format.height = 200;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(200, adapter.output_format().height);
|
|
|
|
// Server format request 160x100. But view disabled. Adapt nothing.
|
|
adapter.set_view_adaptation(false);
|
|
format.width = 160;
|
|
format.height = 100;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(200, adapter.output_format().height);
|
|
adapter.set_view_adaptation(true);
|
|
|
|
// Enable View Switch. Expect adapt down.
|
|
adapter.set_view_switch(true);
|
|
format.width = 160;
|
|
format.height = 100;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(160, adapter.output_format().width);
|
|
EXPECT_EQ(100, adapter.output_format().height);
|
|
|
|
// Encoder resolution request: upgrade. Adapt nothing.
|
|
adapter.OnEncoderResolutionRequest(160, 100,
|
|
CoordinatedVideoAdapter::UPGRADE);
|
|
EXPECT_EQ(160, adapter.output_format().width);
|
|
EXPECT_EQ(100, adapter.output_format().height);
|
|
|
|
// Request View of 2 / 3. Expect adapt down.
|
|
adapter.set_view_switch(true);
|
|
format.width = (640 * 2 + 1) / 3;
|
|
format.height = (400 * 2 + 1) / 3;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ((640 * 2 + 1) / 3, adapter.output_format().width);
|
|
EXPECT_EQ((400 * 2 + 1) / 3, adapter.output_format().height);
|
|
|
|
|
|
// Request View of 3 / 8. Expect adapt down.
|
|
adapter.set_view_switch(true);
|
|
format.width = 640 * 3 / 8;
|
|
format.height = 400 * 3 / 8;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(640 * 3 / 8, adapter.output_format().width);
|
|
EXPECT_EQ(400 * 3 / 8, adapter.output_format().height);
|
|
|
|
// View Switch back up. Expect adapt.
|
|
format.width = 320;
|
|
format.height = 200;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(200, adapter.output_format().height);
|
|
|
|
adapter.set_view_switch(false);
|
|
|
|
// Encoder resolution request: upgrade. Constrained by server request.
|
|
adapter.OnEncoderResolutionRequest(320, 200,
|
|
CoordinatedVideoAdapter::UPGRADE);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(200, adapter.output_format().height);
|
|
|
|
// Server format request 480x300.
|
|
format.width = 480;
|
|
format.height = 300;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(480, adapter.output_format().width);
|
|
EXPECT_EQ(300, adapter.output_format().height);
|
|
}
|
|
|
|
TEST(CoordinatedVideoAdapterTest, TestCoordinatedWithCpuAdaptation) {
|
|
CoordinatedVideoAdapter adapter;
|
|
adapter.set_cpu_adaptation(true);
|
|
EXPECT_FALSE(adapter.cpu_smoothing());
|
|
VideoFormat format(640, 400, VideoFormat::FpsToInterval(30), FOURCC_I420);
|
|
adapter.SetInputFormat(format);
|
|
|
|
// Server format request 640x400.
|
|
format.height = 400;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(640, adapter.output_format().width);
|
|
EXPECT_EQ(400, adapter.output_format().height);
|
|
|
|
// Process load is medium, but system load is high. Downgrade.
|
|
UpdateCpuLoad(&adapter, 1, 1, 0.55f, 0.98f);
|
|
EXPECT_EQ(480, adapter.output_format().width);
|
|
EXPECT_EQ(300, adapter.output_format().height);
|
|
|
|
// CPU high, but cpu adaptation disabled. Adapt nothing.
|
|
adapter.set_cpu_adaptation(false);
|
|
adapter.OnCpuLoadUpdated(1, 1, 0.55f, 0.98f);
|
|
EXPECT_EQ(480, adapter.output_format().width);
|
|
EXPECT_EQ(300, adapter.output_format().height);
|
|
adapter.set_cpu_adaptation(true);
|
|
|
|
// System load is high, but time has not elaspsed. Adapt nothing.
|
|
adapter.set_cpu_load_min_samples(2);
|
|
adapter.OnCpuLoadUpdated(1, 1, 0.55f, 0.98f);
|
|
EXPECT_EQ(480, adapter.output_format().width);
|
|
EXPECT_EQ(300, adapter.output_format().height);
|
|
|
|
// Process load is medium, but system load is high. Downgrade.
|
|
UpdateCpuLoad(&adapter, 1, 1, 0.55f, 0.98f);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(200, adapter.output_format().height);
|
|
|
|
// Test reason for adapting is CPU.
|
|
EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_CPU,
|
|
adapter.adapt_reason());
|
|
|
|
// Server format request 320x200. Same as CPU. Do nothing.
|
|
format.width = 320;
|
|
format.height = 200;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(200, adapter.output_format().height);
|
|
|
|
// Test reason for adapting is CPU and VIEW.
|
|
EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_CPU +
|
|
CoordinatedVideoAdapter::ADAPTREASON_VIEW,
|
|
adapter.adapt_reason());
|
|
|
|
// Process load and system load are normal. Adapt nothing.
|
|
UpdateCpuLoad(&adapter, 1, 1, 0.5f, 0.8f);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(200, adapter.output_format().height);
|
|
|
|
// Process load and system load are low, but view is still low. Adapt nothing.
|
|
UpdateCpuLoad(&adapter, 1, 1, 0.2f, 0.3f);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(200, adapter.output_format().height);
|
|
|
|
// Test reason for adapting is VIEW.
|
|
EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_VIEW,
|
|
adapter.adapt_reason());
|
|
|
|
// Server format request 640x400. Cpu is still low. Upgrade.
|
|
format.width = 640;
|
|
format.height = 400;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(480, adapter.output_format().width);
|
|
EXPECT_EQ(300, adapter.output_format().height);
|
|
|
|
// Test reason for adapting is CPU.
|
|
EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_CPU,
|
|
adapter.adapt_reason());
|
|
|
|
// Encoder resolution request: downgrade.
|
|
adapter.OnEncoderResolutionRequest(480, 300,
|
|
CoordinatedVideoAdapter::DOWNGRADE);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(200, adapter.output_format().height);
|
|
|
|
// Test reason for adapting is BANDWIDTH.
|
|
EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_BANDWIDTH,
|
|
adapter.adapt_reason());
|
|
|
|
// Process load and system load are low. Constrained by GD. Adapt nothing
|
|
adapter.OnCpuLoadUpdated(1, 1, 0.2f, 0.3f);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(200, adapter.output_format().height);
|
|
|
|
// Encoder resolution request: upgrade.
|
|
adapter.OnEncoderResolutionRequest(320, 200,
|
|
CoordinatedVideoAdapter::UPGRADE);
|
|
EXPECT_EQ(480, adapter.output_format().width);
|
|
EXPECT_EQ(300, adapter.output_format().height);
|
|
|
|
// Encoder resolution request: upgrade. Constrained by CPU.
|
|
adapter.OnEncoderResolutionRequest(480, 300,
|
|
CoordinatedVideoAdapter::UPGRADE);
|
|
EXPECT_EQ(480, adapter.output_format().width);
|
|
EXPECT_EQ(300, adapter.output_format().height);
|
|
|
|
// Server format request 640x400. Constrained by CPU.
|
|
format.width = 640;
|
|
format.height = 400;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(480, adapter.output_format().width);
|
|
EXPECT_EQ(300, adapter.output_format().height);
|
|
}
|
|
|
|
TEST(CoordinatedVideoAdapterTest, TestCoordinatedWithCpuRequest) {
|
|
CoordinatedVideoAdapter adapter;
|
|
adapter.set_cpu_adaptation(true);
|
|
EXPECT_FALSE(adapter.cpu_smoothing());
|
|
VideoFormat format(640, 400, VideoFormat::FpsToInterval(30), FOURCC_I420);
|
|
adapter.SetInputFormat(format);
|
|
|
|
// Server format request 640x400.
|
|
format.height = 400;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(640, adapter.output_format().width);
|
|
EXPECT_EQ(400, adapter.output_format().height);
|
|
|
|
// CPU resolution request: downgrade. Adapt down.
|
|
adapter.OnCpuResolutionRequest(CoordinatedVideoAdapter::DOWNGRADE);
|
|
EXPECT_EQ(480, adapter.output_format().width);
|
|
EXPECT_EQ(300, adapter.output_format().height);
|
|
|
|
// CPU resolution request: keep. Do nothing.
|
|
adapter.OnCpuResolutionRequest(CoordinatedVideoAdapter::KEEP);
|
|
EXPECT_EQ(480, adapter.output_format().width);
|
|
EXPECT_EQ(300, adapter.output_format().height);
|
|
|
|
// CPU resolution request: downgrade, but cpu adaptation disabled.
|
|
// Adapt nothing.
|
|
adapter.set_cpu_adaptation(false);
|
|
adapter.OnCpuResolutionRequest(CoordinatedVideoAdapter::DOWNGRADE);
|
|
EXPECT_EQ(480, adapter.output_format().width);
|
|
EXPECT_EQ(300, adapter.output_format().height);
|
|
|
|
// CPU resolution request: downgrade. Adapt down.
|
|
adapter.set_cpu_adaptation(true);
|
|
adapter.OnCpuResolutionRequest(CoordinatedVideoAdapter::DOWNGRADE);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(200, adapter.output_format().height);
|
|
|
|
// Test reason for adapting is CPU.
|
|
EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_CPU,
|
|
adapter.adapt_reason());
|
|
|
|
// CPU resolution request: downgrade, but already at minimum. Do nothing.
|
|
adapter.OnCpuResolutionRequest(CoordinatedVideoAdapter::DOWNGRADE);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(200, adapter.output_format().height);
|
|
|
|
// Server format request 320x200. Same as CPU. Do nothing.
|
|
format.width = 320;
|
|
format.height = 200;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(200, adapter.output_format().height);
|
|
|
|
// Test reason for adapting is CPU and VIEW.
|
|
EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_CPU +
|
|
CoordinatedVideoAdapter::ADAPTREASON_VIEW,
|
|
adapter.adapt_reason());
|
|
|
|
// CPU resolution request: upgrade, but view request still low. Do nothing.
|
|
adapter.OnCpuResolutionRequest(CoordinatedVideoAdapter::UPGRADE);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(200, adapter.output_format().height);
|
|
|
|
// Test reason for adapting is VIEW.
|
|
EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_VIEW,
|
|
adapter.adapt_reason());
|
|
|
|
// Server format request 640x400. Cpu is still low. Upgrade.
|
|
format.width = 640;
|
|
format.height = 400;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(480, adapter.output_format().width);
|
|
EXPECT_EQ(300, adapter.output_format().height);
|
|
|
|
// Test reason for adapting is CPU.
|
|
EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_CPU,
|
|
adapter.adapt_reason());
|
|
|
|
// Encoder resolution request: downgrade.
|
|
adapter.OnEncoderResolutionRequest(480, 300,
|
|
CoordinatedVideoAdapter::DOWNGRADE);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(200, adapter.output_format().height);
|
|
|
|
// Test reason for adapting is BANDWIDTH.
|
|
EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_BANDWIDTH,
|
|
adapter.adapt_reason());
|
|
|
|
// Process load and system load are low. Constrained by GD. Adapt nothing
|
|
adapter.OnCpuLoadUpdated(1, 1, 0.2f, 0.3f);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(200, adapter.output_format().height);
|
|
|
|
// Encoder resolution request: upgrade.
|
|
adapter.OnEncoderResolutionRequest(320, 200,
|
|
CoordinatedVideoAdapter::UPGRADE);
|
|
EXPECT_EQ(480, adapter.output_format().width);
|
|
EXPECT_EQ(300, adapter.output_format().height);
|
|
|
|
// Encoder resolution request: upgrade. Constrained by CPU.
|
|
adapter.OnEncoderResolutionRequest(480, 300,
|
|
CoordinatedVideoAdapter::UPGRADE);
|
|
EXPECT_EQ(480, adapter.output_format().width);
|
|
EXPECT_EQ(300, adapter.output_format().height);
|
|
|
|
// Server format request 640x400. Constrained by CPU.
|
|
format.width = 640;
|
|
format.height = 400;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(480, adapter.output_format().width);
|
|
EXPECT_EQ(300, adapter.output_format().height);
|
|
}
|
|
|
|
TEST(CoordinatedVideoAdapterTest, TestViewRequestPlusCameraSwitch) {
|
|
CoordinatedVideoAdapter adapter;
|
|
adapter.set_view_switch(true);
|
|
|
|
// Start at HD.
|
|
VideoFormat format(1280, 720, VideoFormat::FpsToInterval(30), FOURCC_I420);
|
|
adapter.SetInputFormat(format);
|
|
EXPECT_EQ(format, adapter.input_format());
|
|
EXPECT_TRUE(adapter.output_format().IsSize0x0());
|
|
|
|
// View request for VGA.
|
|
format.width = 640;
|
|
format.height = 360;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(640, adapter.output_format().width);
|
|
EXPECT_EQ(360, adapter.output_format().height);
|
|
EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_VIEW, adapter.adapt_reason());
|
|
|
|
// Now, the camera reopens at VGA.
|
|
// Both the frame and the output format should be 640x360.
|
|
WebRtcVideoFrame in_frame;
|
|
in_frame.InitToBlack(640, 360, 1, 1, 33, 33);
|
|
VideoFrame* out_frame;
|
|
adapter.AdaptFrame(&in_frame, &out_frame);
|
|
EXPECT_EQ(640u, out_frame->GetWidth());
|
|
EXPECT_EQ(360u, out_frame->GetHeight());
|
|
// At this point, the view is no longer adapted, since the input has resized
|
|
// small enough to fit the last view request.
|
|
EXPECT_EQ(0, adapter.adapt_reason());
|
|
|
|
// And another view request comes in for 640x360, which should have no
|
|
// real impact.
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(640, adapter.output_format().width);
|
|
EXPECT_EQ(360, adapter.output_format().height);
|
|
EXPECT_EQ(0, adapter.adapt_reason());
|
|
}
|
|
|
|
TEST(CoordinatedVideoAdapterTest, TestVGAWidth) {
|
|
CoordinatedVideoAdapter adapter;
|
|
adapter.set_view_switch(true);
|
|
|
|
// Start at 640x480, for cameras that don't support 640x360.
|
|
VideoFormat format(640, 480, VideoFormat::FpsToInterval(30), FOURCC_I420);
|
|
adapter.SetInputFormat(format);
|
|
EXPECT_EQ(format, adapter.input_format());
|
|
EXPECT_TRUE(adapter.output_format().IsSize0x0());
|
|
|
|
// Output format is 640x360, though.
|
|
format.width = 640;
|
|
format.height = 360;
|
|
adapter.SetOutputFormat(format);
|
|
|
|
// And also a view request comes for 640x360.
|
|
adapter.OnOutputFormatRequest(format);
|
|
// At this point, we have to adapt down to something lower.
|
|
EXPECT_EQ(480, adapter.output_format().width);
|
|
EXPECT_EQ(360, adapter.output_format().height);
|
|
|
|
// But if frames come in at 640x360, we shouldn't adapt them down.
|
|
// Fake a 640x360 frame.
|
|
WebRtcVideoFrame in_frame;
|
|
in_frame.InitToBlack(640, 360, 1, 1, 33, 33);
|
|
VideoFrame* out_frame;
|
|
adapter.AdaptFrame(&in_frame, &out_frame);
|
|
|
|
EXPECT_EQ(640u, out_frame->GetWidth());
|
|
EXPECT_EQ(360u, out_frame->GetHeight());
|
|
|
|
// Similarly, no-op adapt requests for other reasons shouldn't change
|
|
// adaptation state (before a previous bug, the previous EXPECTs would
|
|
// fail and the following would succeed, as the no-op CPU request would
|
|
// fix the adaptation state).
|
|
adapter.set_cpu_adaptation(true);
|
|
UpdateCpuLoad(&adapter, 1, 1, 0.7f, 0.7f);
|
|
adapter.AdaptFrame(&in_frame, &out_frame);
|
|
|
|
EXPECT_EQ(640u, out_frame->GetWidth());
|
|
EXPECT_EQ(360u, out_frame->GetHeight());
|
|
}
|
|
|
|
// When adapting resolution for CPU or GD, the quantity of pixels that the
|
|
// request is based on is reduced to half or double, and then an actual
|
|
// resolution is snapped to, rounding to the closest actual resolution.
|
|
// This works well for some tolerance to 3/4, odd widths and aspect ratios
|
|
// that dont exactly match, but is not best behavior for ViewRequests which
|
|
// need to be be strictly respected to avoid going over the resolution budget
|
|
// given to the codec - 854x480 total pixels.
|
|
// ViewRequest must find a lower resolution.
|
|
TEST(CoordinatedVideoAdapterTest, TestCoordinatedViewRequestDown) {
|
|
CoordinatedVideoAdapter adapter;
|
|
adapter.set_cpu_adaptation(false);
|
|
|
|
VideoFormat format(960, 540, VideoFormat::FpsToInterval(30), FOURCC_I420);
|
|
adapter.SetInputFormat(format);
|
|
adapter.set_scale_third(true);
|
|
EXPECT_EQ(format, adapter.input_format());
|
|
EXPECT_TRUE(adapter.output_format().IsSize0x0());
|
|
|
|
// Server format request 640x400. Expect HVGA.
|
|
format.width = 640;
|
|
format.height = 400;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(640, adapter.output_format().width);
|
|
EXPECT_EQ(360, adapter.output_format().height);
|
|
|
|
// Test reason for adapting is VIEW.
|
|
EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_VIEW, adapter.adapt_reason());
|
|
}
|
|
|
|
// Test that we downgrade video for cpu up to two times.
|
|
TEST(CoordinatedVideoAdapterTest, TestCpuDowngradeTimes) {
|
|
CoordinatedVideoAdapter adapter;
|
|
adapter.set_cpu_adaptation(true);
|
|
EXPECT_FALSE(adapter.cpu_smoothing());
|
|
VideoFormat format(640, 400, VideoFormat::FpsToInterval(30), FOURCC_I420);
|
|
adapter.SetInputFormat(format);
|
|
|
|
// Server format request 640x400.
|
|
format.height = 400;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(640, adapter.output_format().width);
|
|
EXPECT_EQ(400, adapter.output_format().height);
|
|
|
|
// Process load and system load are low. Do not change the cpu desired format
|
|
// and do not adapt.
|
|
adapter.OnCpuLoadUpdated(1, 1, 0.2f, 0.3f);
|
|
EXPECT_EQ(640, adapter.output_format().width);
|
|
EXPECT_EQ(400, adapter.output_format().height);
|
|
|
|
// System load is high. Downgrade.
|
|
UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
|
|
EXPECT_EQ(480, adapter.output_format().width);
|
|
EXPECT_EQ(300, adapter.output_format().height);
|
|
|
|
// System load is high. Downgrade again.
|
|
UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(200, adapter.output_format().height);
|
|
|
|
// System load is still high. Do not downgrade any more.
|
|
UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(200, adapter.output_format().height);
|
|
|
|
// Process load and system load are low. Upgrade.
|
|
UpdateCpuLoad(&adapter, 1, 1, 0.2f, 0.3f);
|
|
EXPECT_EQ(480, adapter.output_format().width);
|
|
EXPECT_EQ(300, adapter.output_format().height);
|
|
|
|
// System load is high. Downgrade.
|
|
UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(200, adapter.output_format().height);
|
|
|
|
// System load is still high. Do not downgrade any more.
|
|
UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(200, adapter.output_format().height);
|
|
}
|
|
|
|
// Test that we respect CPU adapter threshold values.
|
|
TEST(CoordinatedVideoAdapterTest, TestAdapterCpuThreshold) {
|
|
CoordinatedVideoAdapter adapter;
|
|
adapter.set_cpu_adaptation(true);
|
|
EXPECT_FALSE(adapter.cpu_smoothing());
|
|
VideoFormat format(640, 400, VideoFormat::FpsToInterval(30), FOURCC_I420);
|
|
adapter.SetInputFormat(format);
|
|
|
|
// Server format request 640x400.
|
|
format.height = 400;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(640, adapter.output_format().width);
|
|
EXPECT_EQ(400, adapter.output_format().height);
|
|
|
|
// Process load and system load are low. Do not change the cpu desired format
|
|
// and do not adapt.
|
|
adapter.OnCpuLoadUpdated(1, 1, 0.2f, 0.3f);
|
|
EXPECT_EQ(640, adapter.output_format().width);
|
|
EXPECT_EQ(400, adapter.output_format().height);
|
|
|
|
// System load is high. Downgrade.
|
|
UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
|
|
EXPECT_EQ(480, adapter.output_format().width);
|
|
EXPECT_EQ(300, adapter.output_format().height);
|
|
|
|
// Test reason for adapting is CPU.
|
|
EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_CPU, adapter.adapt_reason());
|
|
|
|
// System load is high. Normally downgrade but threshold is high. Do nothing.
|
|
adapter.set_high_system_threshold(0.98f); // Set threshold high.
|
|
UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
|
|
EXPECT_EQ(480, adapter.output_format().width);
|
|
EXPECT_EQ(300, adapter.output_format().height);
|
|
|
|
// System load is medium. Normally do nothing, threshold is low. Adapt down.
|
|
adapter.set_high_system_threshold(0.75f); // Set threshold low.
|
|
UpdateCpuLoad(&adapter, 1, 1, 0.8f, 0.8f);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(200, adapter.output_format().height);
|
|
}
|
|
|
|
|
|
// Test that for an upgrade cpu request, we actually upgrade the desired format;
|
|
// for a downgrade request, we downgrade from the output format.
|
|
TEST(CoordinatedVideoAdapterTest, TestRealCpuUpgrade) {
|
|
CoordinatedVideoAdapter adapter;
|
|
adapter.set_cpu_adaptation(true);
|
|
adapter.set_cpu_smoothing(true);
|
|
VideoFormat format(640, 400, VideoFormat::FpsToInterval(30), FOURCC_I420);
|
|
adapter.SetInputFormat(format);
|
|
|
|
// Server format request 640x400.
|
|
format.width = 640;
|
|
format.height = 400;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(640, adapter.output_format().width);
|
|
EXPECT_EQ(400, adapter.output_format().height);
|
|
|
|
// Process load and system load are low. Do not change the cpu desired format
|
|
// and do not adapt.
|
|
UpdateCpuLoad(&adapter, 1, 1, 0.2f, 0.3f);
|
|
EXPECT_EQ(640, adapter.output_format().width);
|
|
EXPECT_EQ(400, adapter.output_format().height);
|
|
|
|
// Server format request 320x200.
|
|
format.width = 320;
|
|
format.height = 200;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(200, adapter.output_format().height);
|
|
|
|
// Process load and system load are low. Do not change the cpu desired format
|
|
// and do not adapt.
|
|
UpdateCpuLoad(&adapter, 1, 1, 0.2f, 0.3f);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(200, adapter.output_format().height);
|
|
|
|
// Server format request 640x400. Set to 640x400 immediately.
|
|
format.width = 640;
|
|
format.height = 400;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(640, adapter.output_format().width);
|
|
EXPECT_EQ(400, adapter.output_format().height);
|
|
|
|
// Server format request 320x200.
|
|
format.width = 320;
|
|
format.height = 200;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(200, adapter.output_format().height);
|
|
|
|
// Process load is high, but system is not. Do not change the cpu desired
|
|
// format and do not adapt.
|
|
for (size_t i = 0; i < 10; ++i) {
|
|
UpdateCpuLoad(&adapter, 1, 1, 0.75f, 0.8f);
|
|
}
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(200, adapter.output_format().height);
|
|
}
|
|
|
|
// Test that for an upgrade encoder request, we actually upgrade the desired
|
|
// format; for a downgrade request, we downgrade from the output format.
|
|
TEST(CoordinatedVideoAdapterTest, TestRealEncoderUpgrade) {
|
|
CoordinatedVideoAdapter adapter;
|
|
adapter.set_cpu_adaptation(true);
|
|
adapter.set_cpu_smoothing(true);
|
|
VideoFormat format(640, 400, VideoFormat::FpsToInterval(30), FOURCC_I420);
|
|
adapter.SetInputFormat(format);
|
|
|
|
// Server format request 640x400.
|
|
format.width = 640;
|
|
format.height = 400;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(640, adapter.output_format().width);
|
|
EXPECT_EQ(400, adapter.output_format().height);
|
|
|
|
// Encoder resolution request. Do not change the encoder desired format and
|
|
// do not adapt.
|
|
adapter.OnEncoderResolutionRequest(640, 400,
|
|
CoordinatedVideoAdapter::UPGRADE);
|
|
EXPECT_EQ(640, adapter.output_format().width);
|
|
EXPECT_EQ(400, adapter.output_format().height);
|
|
|
|
// Server format request 320x200.
|
|
format.width = 320;
|
|
format.height = 200;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(200, adapter.output_format().height);
|
|
|
|
// Encoder resolution request. Do not change the encoder desired format and
|
|
// do not adapt.
|
|
adapter.OnEncoderResolutionRequest(320, 200,
|
|
CoordinatedVideoAdapter::UPGRADE);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(200, adapter.output_format().height);
|
|
|
|
// Server format request 640x400. Set to 640x400 immediately.
|
|
format.width = 640;
|
|
format.height = 400;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(480, adapter.output_format().width);
|
|
EXPECT_EQ(300, adapter.output_format().height);
|
|
|
|
// Test reason for adapting is BANDWIDTH.
|
|
EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_BANDWIDTH,
|
|
adapter.adapt_reason());
|
|
|
|
// Server format request 320x200.
|
|
format.width = 320;
|
|
format.height = 200;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(200, adapter.output_format().height);
|
|
|
|
// Encoder resolution request. Downgrade from 320x200.
|
|
adapter.OnEncoderResolutionRequest(320, 200,
|
|
CoordinatedVideoAdapter::DOWNGRADE);
|
|
EXPECT_EQ(240, adapter.output_format().width);
|
|
EXPECT_EQ(150, adapter.output_format().height);
|
|
}
|
|
|
|
TEST(CoordinatedVideoAdapterTest, TestNormalizeOutputFormat) {
|
|
CoordinatedVideoAdapter adapter;
|
|
// The input format is 640x360 and the output is limited to 16:9.
|
|
VideoFormat format(640, 360, VideoFormat::FpsToInterval(30), FOURCC_I420);
|
|
adapter.SetInputFormat(format);
|
|
|
|
format.width = 320;
|
|
format.height = 180;
|
|
format.interval = VideoFormat::FpsToInterval(15);
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(180, adapter.output_format().height);
|
|
EXPECT_EQ(VideoFormat::FpsToInterval(15), adapter.output_format().interval);
|
|
|
|
format.width = 320;
|
|
format.height = 200;
|
|
format.interval = VideoFormat::FpsToInterval(40);
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(180, adapter.output_format().height);
|
|
EXPECT_EQ(VideoFormat::FpsToInterval(30), adapter.output_format().interval);
|
|
|
|
// Test reason for adapting is VIEW. Should work even with normalization.
|
|
EXPECT_EQ(CoordinatedVideoAdapter::ADAPTREASON_VIEW,
|
|
adapter.adapt_reason());
|
|
|
|
format.width = 320;
|
|
format.height = 240;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(180, adapter.output_format().height);
|
|
|
|
// The input format is 640x480 and the output will be 4:3.
|
|
format.width = 640;
|
|
format.height = 480;
|
|
adapter.SetInputFormat(format);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(240, adapter.output_format().height);
|
|
|
|
format.width = 320;
|
|
format.height = 240;
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(240, adapter.output_format().height);
|
|
|
|
// The input format is initialized after the output. At that time, the output
|
|
// height is adjusted.
|
|
format.width = 0;
|
|
format.height = 0;
|
|
adapter.SetInputFormat(format);
|
|
|
|
format.width = 320;
|
|
format.height = 240;
|
|
format.interval = VideoFormat::FpsToInterval(30);
|
|
adapter.OnOutputFormatRequest(format);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(240, adapter.output_format().height);
|
|
EXPECT_EQ(VideoFormat::FpsToInterval(30), adapter.output_format().interval);
|
|
|
|
format.width = 640;
|
|
format.height = 480;
|
|
format.interval = VideoFormat::FpsToInterval(15);
|
|
adapter.SetInputFormat(format);
|
|
EXPECT_EQ(320, adapter.output_format().width);
|
|
EXPECT_EQ(240, adapter.output_format().height);
|
|
EXPECT_EQ(VideoFormat::FpsToInterval(15), adapter.output_format().interval);
|
|
}
|
|
|
|
// Test that we downgrade video for cpu up to two times.
|
|
TEST_F(VideoAdapterTest, CpuDowngradeAndSignal) {
|
|
CoordinatedVideoAdapter adapter;
|
|
CpuAdapterListener cpu_listener;
|
|
adapter.SignalCpuAdaptationUnable.connect(
|
|
&cpu_listener, &CpuAdapterListener::OnCpuAdaptationSignalled);
|
|
|
|
adapter.set_cpu_adaptation(true);
|
|
EXPECT_FALSE(adapter.cpu_smoothing());
|
|
VideoFormat format(640, 360, VideoFormat::FpsToInterval(30), FOURCC_I420);
|
|
adapter.SetInputFormat(format);
|
|
adapter.OnOutputFormatRequest(format);
|
|
|
|
// System load is high. Downgrade.
|
|
UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
|
|
|
|
// System load is high. Downgrade again.
|
|
UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
|
|
|
|
// System load is still high. Do not downgrade any more. Ensure we have not
|
|
// signalled until after the cpu warning though.
|
|
EXPECT_TRUE(!cpu_listener.received_cpu_signal());
|
|
UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
|
|
EXPECT_TRUE_WAIT(cpu_listener.received_cpu_signal(), kWaitTimeout);
|
|
}
|
|
|
|
// Test that we downgrade video for cpu up to two times.
|
|
TEST_F(VideoAdapterTest, CpuDowngradeAndDontSignal) {
|
|
CoordinatedVideoAdapter adapter;
|
|
CpuAdapterListener cpu_listener;
|
|
adapter.SignalCpuAdaptationUnable.connect(
|
|
&cpu_listener, &CpuAdapterListener::OnCpuAdaptationSignalled);
|
|
|
|
adapter.set_cpu_adaptation(true);
|
|
adapter.set_cpu_smoothing(true);
|
|
VideoFormat format(640, 360, VideoFormat::FpsToInterval(30), FOURCC_I420);
|
|
adapter.SetInputFormat(format);
|
|
adapter.OnOutputFormatRequest(format);
|
|
|
|
// System load is high. Downgrade.
|
|
UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
|
|
|
|
// System load is high, process is not, Do not downgrade again.
|
|
UpdateCpuLoad(&adapter, 1, 1, 0.25f, 0.95f);
|
|
|
|
// System load is high, process is not, Do not downgrade again and do not
|
|
// signal.
|
|
adapter.set_cpu_adaptation(false);
|
|
UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
|
|
rtc::Thread::Current()->ProcessMessages(kShortWaitTimeout);
|
|
EXPECT_TRUE(!cpu_listener.received_cpu_signal());
|
|
adapter.set_cpu_adaptation(true);
|
|
}
|
|
|
|
// Test that we require enough time before we downgrade.
|
|
TEST_F(VideoAdapterTest, CpuMinTimeRequirement) {
|
|
CoordinatedVideoAdapter adapter;
|
|
CpuAdapterListener cpu_listener;
|
|
adapter.SignalCpuAdaptationUnable.connect(
|
|
&cpu_listener, &CpuAdapterListener::OnCpuAdaptationSignalled);
|
|
|
|
adapter.set_cpu_adaptation(true);
|
|
adapter.set_cpu_smoothing(true);
|
|
VideoFormat format(640, 360, VideoFormat::FpsToInterval(30), FOURCC_I420);
|
|
adapter.SetInputFormat(format);
|
|
adapter.OnOutputFormatRequest(format);
|
|
|
|
EXPECT_EQ(3, adapter.cpu_load_min_samples());
|
|
adapter.set_cpu_load_min_samples(5);
|
|
|
|
for (size_t i = 0; i < 4; ++i) {
|
|
adapter.OnCpuLoadUpdated(1, 1, 1.0f, 1.0f);
|
|
EXPECT_EQ(640, adapter.output_format().width);
|
|
EXPECT_EQ(360, adapter.output_format().height);
|
|
}
|
|
// The computed cpu load should now be around 93.5%, with the coefficient of
|
|
// 0.4 and a seed value of 0.5. That should be high enough to adapt, but it
|
|
// isn't enough samples, so we shouldn't have adapted on any of the previous
|
|
// samples.
|
|
|
|
// One more sample is enough, though, once enough time has passed.
|
|
adapter.OnCpuLoadUpdated(1, 1, 1.0f, 1.0f);
|
|
EXPECT_EQ(480, adapter.output_format().width);
|
|
EXPECT_EQ(270, adapter.output_format().height);
|
|
|
|
// Now the cpu is lower, but we still need enough samples to upgrade.
|
|
for (size_t i = 0; i < 4; ++i) {
|
|
adapter.OnCpuLoadUpdated(1, 1, 0.1f, 0.1f);
|
|
EXPECT_EQ(480, adapter.output_format().width);
|
|
EXPECT_EQ(270, adapter.output_format().height);
|
|
}
|
|
|
|
// One more sample is enough, once time has elapsed.
|
|
adapter.OnCpuLoadUpdated(1, 1, 1.0f, 1.0f);
|
|
EXPECT_EQ(640, adapter.output_format().width);
|
|
EXPECT_EQ(360, adapter.output_format().height);
|
|
}
|
|
|
|
TEST_F(VideoAdapterTest, CpuIgnoresSpikes) {
|
|
CoordinatedVideoAdapter adapter;
|
|
CpuAdapterListener cpu_listener;
|
|
adapter.SignalCpuAdaptationUnable.connect(
|
|
&cpu_listener, &CpuAdapterListener::OnCpuAdaptationSignalled);
|
|
|
|
adapter.set_cpu_adaptation(true);
|
|
adapter.set_cpu_smoothing(true);
|
|
VideoFormat format(640, 360, VideoFormat::FpsToInterval(30), FOURCC_I420);
|
|
adapter.SetInputFormat(format);
|
|
adapter.OnOutputFormatRequest(format);
|
|
|
|
// System load is high. Downgrade.
|
|
for (size_t i = 0; i < 5; ++i) {
|
|
UpdateCpuLoad(&adapter, 1, 1, 0.95f, 0.95f);
|
|
}
|
|
EXPECT_EQ(480, adapter.output_format().width);
|
|
EXPECT_EQ(270, adapter.output_format().height);
|
|
|
|
// Now we're in a state where we could upgrade or downgrade, so get to a
|
|
// steady state of about 75% cpu usage.
|
|
for (size_t i = 0; i < 5; ++i) {
|
|
UpdateCpuLoad(&adapter, 1, 1, 0.75f, 0.75f);
|
|
EXPECT_EQ(480, adapter.output_format().width);
|
|
EXPECT_EQ(270, adapter.output_format().height);
|
|
}
|
|
|
|
// Now, the cpu spikes for two samples, but then goes back to
|
|
// normal. This shouldn't cause adaptation.
|
|
UpdateCpuLoad(&adapter, 1, 1, 0.90f, 0.90f);
|
|
UpdateCpuLoad(&adapter, 1, 1, 0.90f, 0.90f);
|
|
EXPECT_EQ(480, adapter.output_format().width);
|
|
EXPECT_EQ(270, adapter.output_format().height);
|
|
// Back to the steady state for awhile.
|
|
for (size_t i = 0; i < 5; ++i) {
|
|
UpdateCpuLoad(&adapter, 1, 1, 0.75, 0.75);
|
|
EXPECT_EQ(480, adapter.output_format().width);
|
|
EXPECT_EQ(270, adapter.output_format().height);
|
|
}
|
|
|
|
// Now, system cpu usage is starting to drop down. But it takes a bit before
|
|
// it gets all the way there.
|
|
for (size_t i = 0; i < 10; ++i) {
|
|
UpdateCpuLoad(&adapter, 1, 1, 0.5f, 0.5f);
|
|
}
|
|
EXPECT_EQ(640, adapter.output_format().width);
|
|
EXPECT_EQ(360, adapter.output_format().height);
|
|
}
|
|
|
|
} // namespace cricket
|
|
#endif // HAVE_WEBRTC_VIDEO
|