Skip to content

Commit

Permalink
Add scroll perf test for protocol in chromoting
Browse files Browse the repository at this point in the history
The new test simulates frame scroll and measures frame-rate and average
latency.

Some results from the new test:

LimitedBandwidth/0 (100Mbps):
ICE: FPS: 29.7853, Average latency: 49.7429
Webrtc: FPS: 10.4109, Average latency: 71.0577

LimitedBandwidth/1 (8Mbps):
ICE: FPS: 5.24054, Average latency: 734.131
Webrtc: FPS: 11.1471, Average latency: 116.915

Review-Url: https://codereview.chromium.org/2182833002
Cr-Commit-Position: refs/heads/master@{#407957}
  • Loading branch information
SergeyUlanov authored and Commit bot committed Jul 26, 2016
1 parent 7b77fb9 commit 8bc24e1
Show file tree
Hide file tree
Showing 9 changed files with 374 additions and 158 deletions.
2 changes: 2 additions & 0 deletions remoting/remoting_test.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@
'test/fake_remote_host_info_fetcher.h',
'test/fake_socket_factory.cc',
'test/fake_socket_factory.h',
'test/frame_generator_util.cc',
'test/frame_generator_util.h',
'test/host_info.cc',
'test/host_info.h',
'test/host_list_fetcher.cc',
Expand Down
4 changes: 4 additions & 0 deletions remoting/test/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ static_library("test_support") {
"fake_remote_host_info_fetcher.h",
"fake_socket_factory.cc",
"fake_socket_factory.h",
"frame_generator_util.cc",
"frame_generator_util.h",
"host_info.cc",
"host_info.h",
"host_list_fetcher.cc",
Expand All @@ -58,6 +60,8 @@ static_library("test_support") {
"remote_host_info_fetcher.h",
"rgb_value.cc",
"rgb_value.h",
"scroll_frame_generator.cc",
"scroll_frame_generator.h",
"test_chromoting_client.cc",
"test_chromoting_client.h",
"test_video_renderer.cc",
Expand Down
103 changes: 6 additions & 97 deletions remoting/test/cyclic_frame_generator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,76 +4,24 @@

#include "remoting/test/cyclic_frame_generator.h"

#include "base/base_paths.h"
#include "base/files/file_util.h"
#include "base/path_service.h"
#include "base/time/default_tick_clock.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "remoting/test/frame_generator_util.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
#include "ui/gfx/codec/png_codec.h"

namespace remoting {
namespace test {

namespace {

const int kBarcodeCellWidth = 8;
const int kBarcodeCellHeight = 8;
const int kBarcodeBits = 10;
const int kBarcodeBlackThreshold = 85;
const int kBarcodeWhiteThreshold = 170;

std::unique_ptr<webrtc::DesktopFrame> LoadDesktopFrameFromPng(
const base::FilePath& file_path) {
std::string file_content;
if (!base::ReadFileToString(file_path, &file_content))
LOG(FATAL) << "Failed to read " << file_path.MaybeAsASCII()
<< ". Please run remoting/test/data/download.sh";
SkBitmap bitmap;
gfx::PNGCodec::Decode(reinterpret_cast<const uint8_t*>(file_content.data()),
file_content.size(), &bitmap);
std::unique_ptr<webrtc::DesktopFrame> frame(new webrtc::BasicDesktopFrame(
webrtc::DesktopSize(bitmap.width(), bitmap.height())));
bitmap.copyPixelsTo(frame->data(),
frame->stride() * frame->size().height(),
frame->stride());
return frame;
}

void DrawRect(webrtc::DesktopFrame* frame,
webrtc::DesktopRect rect,
uint32_t color) {
for (int y = rect.top(); y < rect.bottom(); ++y) {
uint32_t* data = reinterpret_cast<uint32_t*>(
frame->data() + y * frame->stride() +
rect.left() * webrtc::DesktopFrame::kBytesPerPixel);
for (int x = 0; x < rect.width(); ++x) {
data[x] = color;
}
}
}

} // namespace

CyclicFrameGenerator::ChangeInfo::ChangeInfo() = default;
CyclicFrameGenerator::ChangeInfo::ChangeInfo(ChangeType type,
base::TimeTicks timestamp)
: type(type), timestamp(timestamp) {}

// static
scoped_refptr<CyclicFrameGenerator> CyclicFrameGenerator::Create() {
base::FilePath test_data_path;
PathService::Get(base::DIR_SOURCE_ROOT, &test_data_path);
test_data_path = test_data_path.Append(FILE_PATH_LITERAL("remoting"));
test_data_path = test_data_path.Append(FILE_PATH_LITERAL("test"));
test_data_path = test_data_path.Append(FILE_PATH_LITERAL("data"));

std::vector<std::unique_ptr<webrtc::DesktopFrame>> frames;
frames.push_back(
LoadDesktopFrameFromPng(test_data_path.AppendASCII("test_frame1.png")));
frames.push_back(
LoadDesktopFrameFromPng(test_data_path.AppendASCII("test_frame2.png")));
frames.push_back(LoadDesktopFrameFromPng("test_frame1.png"));
frames.push_back(LoadDesktopFrameFromPng("test_frame2.png"));
return new CyclicFrameGenerator(std::move(frames));
}

Expand Down Expand Up @@ -132,23 +80,8 @@ std::unique_ptr<webrtc::DesktopFrame> CyclicFrameGenerator::GenerateFrame(
last_frame_type_ = ChangeType::NO_CHANGES;
}

// Render barcode.
if (draw_barcode_) {
uint32_t value = static_cast<uint32_t>(frame_id);
CHECK(value < (1U << kBarcodeBits));
for (int i = 0; i < kBarcodeBits; ++i) {
DrawRect(frame.get(), webrtc::DesktopRect::MakeXYWH(i * kBarcodeCellWidth,
0, kBarcodeCellWidth,
kBarcodeCellHeight),
(value & 1) ? 0xffffffff : 0xff000000);
value >>= 1;
}

if (frame_id != last_frame_id_) {
frame->mutable_updated_region()->AddRect(webrtc::DesktopRect::MakeXYWH(
0, 0, kBarcodeCellWidth * kBarcodeBits, kBarcodeCellHeight));
}
}
if (draw_barcode_)
DrawBarcode(frame_id, frame_id != last_frame_id_, frame.get());

last_reference_frame_ = reference_frame;
last_cursor_state_ = cursor_state;
Expand All @@ -160,31 +93,7 @@ std::unique_ptr<webrtc::DesktopFrame> CyclicFrameGenerator::GenerateFrame(
CyclicFrameGenerator::ChangeInfoList CyclicFrameGenerator::GetChangeList(
webrtc::DesktopFrame* frame) {
CHECK(draw_barcode_);
int frame_id = 0;
for (int i = kBarcodeBits - 1; i >= 0; --i) {
// Sample barcode in the center of the cell for each bit.
int x = i * kBarcodeCellWidth + kBarcodeCellWidth / 2;
int y = kBarcodeCellHeight / 2;
uint8_t* data = (frame->data() + y * frame->stride() +
x * webrtc::DesktopFrame::kBytesPerPixel);
int b = data[0];
int g = data[1];
int r = data[2];
bool bit = 0;
if (b > kBarcodeWhiteThreshold && g > kBarcodeWhiteThreshold &&
r > kBarcodeWhiteThreshold) {
bit = 1;
} else if (b < kBarcodeBlackThreshold && g < kBarcodeBlackThreshold &&
r < kBarcodeBlackThreshold) {
bit = 0;
} else {
LOG(FATAL) << "Invalid barcode.";
}
frame_id <<= 1;
if (bit)
frame_id |= 1;
}

int frame_id = ReadBarcode(*frame);
CHECK_GE(frame_id, last_identifier_frame_);

ChangeInfoList result;
Expand Down
2 changes: 1 addition & 1 deletion remoting/test/cyclic_frame_generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class CyclicFrameGenerator

static scoped_refptr<CyclicFrameGenerator> Create();

CyclicFrameGenerator(
explicit CyclicFrameGenerator(
std::vector<std::unique_ptr<webrtc::DesktopFrame>> reference_frames);

void set_frame_cycle_period(base::TimeDelta frame_cycle_period) {
Expand Down
105 changes: 105 additions & 0 deletions remoting/test/frame_generator_util.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// 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 "remoting/test/frame_generator_util.h"

#include "base/base_paths.h"
#include "base/files/file_util.h"
#include "base/path_service.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
#include "ui/gfx/codec/png_codec.h"

namespace remoting {
namespace test {

namespace {
const int kBarcodeCellWidth = 8;
const int kBarcodeCellHeight = 8;
const int kBarcodeBits = 10;
const int kBarcodeBlackThreshold = 85;
const int kBarcodeWhiteThreshold = 170;
} // namespace

std::unique_ptr<webrtc::DesktopFrame> LoadDesktopFrameFromPng(
const char* name) {
base::FilePath file_path;
PathService::Get(base::DIR_SOURCE_ROOT, &file_path);
file_path = file_path.AppendASCII("remoting");
file_path = file_path.AppendASCII("test");
file_path = file_path.AppendASCII("data");
file_path = file_path.AppendASCII(name);

std::string file_content;
if (!base::ReadFileToString(file_path, &file_content))
LOG(FATAL) << "Failed to read " << file_path.MaybeAsASCII()
<< ". Please run remoting/test/data/download.sh";
SkBitmap bitmap;
gfx::PNGCodec::Decode(reinterpret_cast<const uint8_t*>(file_content.data()),
file_content.size(), &bitmap);
std::unique_ptr<webrtc::DesktopFrame> frame(new webrtc::BasicDesktopFrame(
webrtc::DesktopSize(bitmap.width(), bitmap.height())));
bitmap.copyPixelsTo(frame->data(),
frame->stride() * frame->size().height(),
frame->stride());
return frame;
}

void DrawRect(webrtc::DesktopFrame* frame,
webrtc::DesktopRect rect,
uint32_t color) {
for (int y = rect.top(); y < rect.bottom(); ++y) {
uint32_t* data = reinterpret_cast<uint32_t*>(
frame->GetFrameDataAtPos(webrtc::DesktopVector(rect.left(), y)));
for (int x = 0; x < rect.width(); ++x) {
data[x] = color;
}
}
}

void DrawBarcode(int value, bool changed, webrtc::DesktopFrame* frame) {
CHECK(value < (1 << kBarcodeBits));
for (int i = 0; i < kBarcodeBits; ++i) {
DrawRect(frame, webrtc::DesktopRect::MakeXYWH(i * kBarcodeCellWidth, 0,
kBarcodeCellWidth,
kBarcodeCellHeight),
(value & 1) ? 0xffffffff : 0xff000000);
value >>= 1;
}
if (changed) {
frame->mutable_updated_region()->AddRect(webrtc::DesktopRect::MakeXYWH(
0, 0, kBarcodeCellWidth * kBarcodeBits, kBarcodeCellHeight));
}
}

int ReadBarcode(const webrtc::DesktopFrame& frame) {
int result = 0;
for (int i = kBarcodeBits - 1; i >= 0; --i) {
// Sample barcode in the center of the cell for each bit.
int x = i * kBarcodeCellWidth + kBarcodeCellWidth / 2;
int y = kBarcodeCellHeight / 2;
uint8_t* data = frame.GetFrameDataAtPos(webrtc::DesktopVector(x, y));
int b = data[0];
int g = data[1];
int r = data[2];
bool bit = 0;
if (b > kBarcodeWhiteThreshold && g > kBarcodeWhiteThreshold &&
r > kBarcodeWhiteThreshold) {
bit = 1;
} else if (b < kBarcodeBlackThreshold && g < kBarcodeBlackThreshold &&
r < kBarcodeBlackThreshold) {
bit = 0;
} else {
LOG(FATAL) << "Invalid barcode.";
}
result <<= 1;
if (bit)
result |= 1;
}
return result;
}

} // namespace test
} // namespace remoting
37 changes: 37 additions & 0 deletions remoting/test/frame_generator_util.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// 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.

#ifndef REMOTING_TEST_FRAME_GENERATOR_UTIL_H_
#define REMOTING_TEST_FRAME_GENERATOR_UTIL_H_

#include <memory>

#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"

namespace webrtc {
class DesktopFrame;
} // namespace webrtc

namespace remoting {
namespace test {

// Loads test image from remoting/test/data.
std::unique_ptr<webrtc::DesktopFrame> LoadDesktopFrameFromPng(const char* name);

// Draws rectangle filled with the given |color|.
void DrawRect(webrtc::DesktopFrame* frame,
webrtc::DesktopRect rect,
uint32_t color);

// Draws barcode that encodes |value| on the |frame|. If |changed| is true then
// frame->updated_region() will be updated as well.
void DrawBarcode(int value, bool changed, webrtc::DesktopFrame* frame);

// Reads barcode from the frame.
int ReadBarcode(const webrtc::DesktopFrame& frame);

} // namespace test
} // namespace remoting

#endif // REMOTING_TEST_FRAME_GENERATOR_UTIL_H_
Loading

0 comments on commit 8bc24e1

Please sign in to comment.