blob: e157b88763b69c934c7fcad3aba908a4ce8abbfd [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/test/simple_test_tick_clock.h"
#include "remoting/codec/video_encoder_vpx.h"
#include "remoting/proto/video.pb.h"
#include "remoting/test/cyclic_frame_generator.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
namespace remoting {
namespace test {
static const int kIntervalBetweenFramesMs = 33;
struct CodecParams {
CodecParams(bool use_vp9, bool lossless, bool lossless_color)
: use_vp9(use_vp9), lossless(lossless), lossless_color(lossless_color) {}
bool use_vp9;
bool lossless;
bool lossless_color;
};
class CodecPerfTest : public testing::Test,
public testing::WithParamInterface<CodecParams> {
public:
void SetUp() override {
if (GetParam().use_vp9) {
encoder_ = VideoEncoderVpx::CreateForVP9();
encoder_->SetLosslessEncode(GetParam().lossless);
encoder_->SetLosslessColor(GetParam().lossless_color);
} else {
encoder_ = VideoEncoderVpx::CreateForVP8();
}
encoder_->SetTickClockForTests(&clock_);
frame_generator_ = CyclicFrameGenerator::Create();
frame_generator_->SetTickClock(&clock_);
}
protected:
base::SimpleTestTickClock clock_;
scoped_refptr<CyclicFrameGenerator> frame_generator_;
scoped_ptr<VideoEncoderVpx> encoder_;
};
INSTANTIATE_TEST_CASE_P(VP8,
CodecPerfTest,
::testing::Values(CodecParams(false, false, false)));
INSTANTIATE_TEST_CASE_P(VP9,
CodecPerfTest,
::testing::Values(CodecParams(true, false, false)));
INSTANTIATE_TEST_CASE_P(VP9Lossless,
CodecPerfTest,
::testing::Values(CodecParams(true, true, false)));
INSTANTIATE_TEST_CASE_P(VP9LosslessColor,
CodecPerfTest,
::testing::Values(CodecParams(true, false, true)));
TEST_P(CodecPerfTest, EncodeLatency) {
const int kTotalFrames = 300;
base::TimeDelta total_latency;
base::TimeDelta total_latency_big_frames;
int big_frame_count = 0;
base::TimeDelta total_latency_small_frames;
int small_frame_count = 0;
base::TimeDelta total_latency_empty_frames;
int empty_frame_count = 0;
int total_bytes = 0;
for (int i = 0; i < kTotalFrames; ++i) {
scoped_ptr<webrtc::DesktopFrame> frame =
frame_generator_->GenerateFrame(nullptr);
base::TimeTicks started = base::TimeTicks::Now();
scoped_ptr<VideoPacket> packet = encoder_->Encode(*frame);
base::TimeTicks ended = base::TimeTicks::Now();
base::TimeDelta latency = ended - started;
total_latency += latency;
if (packet)
total_bytes += packet->data().size();
switch (frame_generator_->last_frame_type()) {
case CyclicFrameGenerator::FrameType::EMPTY:
total_latency_empty_frames += latency;
++empty_frame_count;
break;
case CyclicFrameGenerator::FrameType::FULL:
total_latency_big_frames += latency;
++big_frame_count;
break;
case CyclicFrameGenerator::FrameType::CURSOR:
total_latency_small_frames += latency;
++small_frame_count;
break;
}
clock_.Advance(base::TimeDelta::FromMilliseconds(kIntervalBetweenFramesMs));
}
VLOG(0) << "Total time: " << total_latency.InMillisecondsF();
VLOG(0) << "Average encode latency: "
<< (total_latency / kTotalFrames).InMillisecondsF();
CHECK(big_frame_count);
VLOG(0) << "Average encode latency for big frames: "
<< (total_latency_big_frames / big_frame_count).InMillisecondsF();
if (small_frame_count) {
VLOG(0) << "Average encode latency for small frames: "
<< (total_latency_small_frames / small_frame_count)
.InMillisecondsF();
}
if (empty_frame_count) {
VLOG(0) << "Average encode latency for empty frames: "
<< (total_latency_empty_frames / empty_frame_count)
.InMillisecondsF();
}
VLOG(0) << "Encoded bytes: " << total_bytes;
}
TEST_P(CodecPerfTest, MaxFramerate) {
const int kTotalFrames = 100;
base::TimeDelta total_latency;
// Update the whole screen on every frame.
frame_generator_->set_frame_cycle_period(
base::TimeDelta::FromMilliseconds(kIntervalBetweenFramesMs));
for (int i = 0; i < kTotalFrames; ++i) {
scoped_ptr<webrtc::DesktopFrame> frame =
frame_generator_->GenerateFrame(nullptr);
base::TimeTicks started = base::TimeTicks::Now();
scoped_ptr<VideoPacket> packet = encoder_->Encode(*frame);
base::TimeTicks ended = base::TimeTicks::Now();
base::TimeDelta latency = ended - started;
total_latency += latency;
clock_.Advance(base::TimeDelta::FromMilliseconds(kIntervalBetweenFramesMs));
}
VLOG(0) << "Max framerate: "
<< (kTotalFrames * base::TimeDelta::FromSeconds(1) / total_latency);
}
} // namespace test
} // namespace remoting