From 8bc24e1f6de205377e3dbb814aeecaf8fe05a867 Mon Sep 17 00:00:00 2001 From: sergeyu Date: Tue, 26 Jul 2016 16:10:57 -0700 Subject: [PATCH] Add scroll perf test for protocol in chromoting 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} --- remoting/remoting_test.gypi | 2 + remoting/test/BUILD.gn | 4 + remoting/test/cyclic_frame_generator.cc | 103 +------------- remoting/test/cyclic_frame_generator.h | 2 +- remoting/test/frame_generator_util.cc | 105 ++++++++++++++ remoting/test/frame_generator_util.h | 37 +++++ remoting/test/protocol_perftest.cc | 173 ++++++++++++++++-------- remoting/test/scroll_frame_generator.cc | 60 ++++++++ remoting/test/scroll_frame_generator.h | 46 +++++++ 9 files changed, 374 insertions(+), 158 deletions(-) create mode 100644 remoting/test/frame_generator_util.cc create mode 100644 remoting/test/frame_generator_util.h create mode 100644 remoting/test/scroll_frame_generator.cc create mode 100644 remoting/test/scroll_frame_generator.h diff --git a/remoting/remoting_test.gypi b/remoting/remoting_test.gypi index d4e0c73c01b79b..1c3fcd8904981c 100644 --- a/remoting/remoting_test.gypi +++ b/remoting/remoting_test.gypi @@ -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', diff --git a/remoting/test/BUILD.gn b/remoting/test/BUILD.gn index af2d75cf96c743..86e0fca15aa0aa 100644 --- a/remoting/test/BUILD.gn +++ b/remoting/test/BUILD.gn @@ -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", @@ -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", diff --git a/remoting/test/cyclic_frame_generator.cc b/remoting/test/cyclic_frame_generator.cc index c8f566c5638ef5..11c8bc57a2d8eb 100644 --- a/remoting/test/cyclic_frame_generator.cc +++ b/remoting/test/cyclic_frame_generator.cc @@ -4,58 +4,14 @@ #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 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(file_content.data()), - file_content.size(), &bitmap); - std::unique_ptr 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( - 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) @@ -63,17 +19,9 @@ CyclicFrameGenerator::ChangeInfo::ChangeInfo(ChangeType type, // static scoped_refptr 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> 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)); } @@ -132,23 +80,8 @@ std::unique_ptr CyclicFrameGenerator::GenerateFrame( last_frame_type_ = ChangeType::NO_CHANGES; } - // Render barcode. - if (draw_barcode_) { - uint32_t value = static_cast(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; @@ -160,31 +93,7 @@ std::unique_ptr 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; diff --git a/remoting/test/cyclic_frame_generator.h b/remoting/test/cyclic_frame_generator.h index fbe9ca86296d3d..d03118a718921b 100644 --- a/remoting/test/cyclic_frame_generator.h +++ b/remoting/test/cyclic_frame_generator.h @@ -47,7 +47,7 @@ class CyclicFrameGenerator static scoped_refptr Create(); - CyclicFrameGenerator( + explicit CyclicFrameGenerator( std::vector> reference_frames); void set_frame_cycle_period(base::TimeDelta frame_cycle_period) { diff --git a/remoting/test/frame_generator_util.cc b/remoting/test/frame_generator_util.cc new file mode 100644 index 00000000000000..c84115a482a8a2 --- /dev/null +++ b/remoting/test/frame_generator_util.cc @@ -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 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(file_content.data()), + file_content.size(), &bitmap); + std::unique_ptr 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( + 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 diff --git a/remoting/test/frame_generator_util.h b/remoting/test/frame_generator_util.h new file mode 100644 index 00000000000000..e0f7c53422520e --- /dev/null +++ b/remoting/test/frame_generator_util.h @@ -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 + +#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 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_ diff --git a/remoting/test/protocol_perftest.cc b/remoting/test/protocol_perftest.cc index ce9eea4f758178..f0c32cc00f0667 100644 --- a/remoting/test/protocol_perftest.cc +++ b/remoting/test/protocol_perftest.cc @@ -43,6 +43,7 @@ #include "remoting/test/fake_network_dispatcher.h" #include "remoting/test/fake_port_allocator.h" #include "remoting/test/fake_socket_factory.h" +#include "remoting/test/scroll_frame_generator.h" #include "testing/gtest/include/gtest/gtest.h" namespace remoting { @@ -415,63 +416,8 @@ class ProtocolPerfTest secret_fetched_callback.Run(kHostPin); } - void MeasureTotalLatency(bool webrtc) { - scoped_refptr frame_generator = - test::CyclicFrameGenerator::Create(); - frame_generator->set_draw_barcode(true); - - desktop_environment_factory_.set_frame_generator(base::Bind( - &test::CyclicFrameGenerator::GenerateFrame, frame_generator)); - - StartHostAndClient(webrtc, protocol::ChannelConfig::CODEC_VP8); - ASSERT_NO_FATAL_FAILURE(WaitConnected()); - - int skipped_frames = 0; - while (skipped_frames < 10) { - std::unique_ptr frame = ReceiveFrame(); - test::CyclicFrameGenerator::ChangeInfoList changes = - frame_generator->GetChangeList(frame.get()); - skipped_frames += changes.size(); - } - - base::TimeDelta total_latency_big_frames; - int big_frame_count = 0; - base::TimeDelta total_latency_small_frames; - int small_frame_count = 0; - - while (big_frame_count + small_frame_count < 30) { - std::unique_ptr frame = ReceiveFrame(); - base::TimeTicks frame_received_time = base::TimeTicks::Now(); - test::CyclicFrameGenerator::ChangeInfoList changes = - frame_generator->GetChangeList(frame.get()); - for (auto& change_info : changes) { - base::TimeDelta latency = frame_received_time - change_info.timestamp; - switch (change_info.type) { - case test::CyclicFrameGenerator::ChangeType::NO_CHANGES: - NOTREACHED(); - break; - case test::CyclicFrameGenerator::ChangeType::FULL: - total_latency_big_frames += latency; - ++big_frame_count; - break; - case test::CyclicFrameGenerator::ChangeType::CURSOR: - total_latency_small_frames += latency; - ++small_frame_count; - break; - } - } - } - - CHECK(big_frame_count); - VLOG(0) << "Average latency for big frames: " - << (total_latency_big_frames / big_frame_count).InMillisecondsF(); - - if (small_frame_count) { - VLOG(0) - << "Average latency for small frames: " - << (total_latency_small_frames / small_frame_count).InMillisecondsF(); - } - } + void MeasureTotalLatency(bool use_webrtc); + void MeasureScrollPerformance(bool use_webrtc); base::MessageLoopForIO message_loop_; @@ -535,9 +481,9 @@ INSTANTIATE_TEST_CASE_P( LimitedBandwidth, ProtocolPerfTest, ::testing::Values( - // 100 MBps - NetworkPerformanceParams(800000000, 800000000, 2, 1, 0.0), - // 8 MBps + // 100 Mbps + NetworkPerformanceParams(12500000, 12500000, 2, 1, 0.0), + // 8 Mbps NetworkPerformanceParams(1000000, 300000, 30, 5, 0.01), NetworkPerformanceParams(1000000, 2000000, 30, 5, 0.01), // 800 kBps @@ -637,6 +583,68 @@ TEST_P(ProtocolPerfTest, IntermittentChanges) { LOG(INFO) << "Average: " << (sum / kFrames).InMillisecondsF(); } +// TotalLatency[Ice|Webrtc] tests measure video latency in the case when the +// whole screen is updated occasionally. It's intended to simulate the case when +// user actions (e.g. Alt-Tab, click on the task bar) cause whole screen to be +// updated. +void ProtocolPerfTest::MeasureTotalLatency(bool use_webrtc) { + scoped_refptr frame_generator = + test::CyclicFrameGenerator::Create(); + frame_generator->set_draw_barcode(true); + + desktop_environment_factory_.set_frame_generator( + base::Bind(&test::CyclicFrameGenerator::GenerateFrame, frame_generator)); + + StartHostAndClient(use_webrtc, protocol::ChannelConfig::CODEC_VP8); + ASSERT_NO_FATAL_FAILURE(WaitConnected()); + + int skipped_frames = 0; + while (skipped_frames < 10) { + std::unique_ptr frame = ReceiveFrame(); + test::CyclicFrameGenerator::ChangeInfoList changes = + frame_generator->GetChangeList(frame.get()); + skipped_frames += changes.size(); + } + + base::TimeDelta total_latency_big_frames; + int big_frame_count = 0; + base::TimeDelta total_latency_small_frames; + int small_frame_count = 0; + + while (big_frame_count + small_frame_count < 30) { + std::unique_ptr frame = ReceiveFrame(); + base::TimeTicks frame_received_time = base::TimeTicks::Now(); + test::CyclicFrameGenerator::ChangeInfoList changes = + frame_generator->GetChangeList(frame.get()); + for (auto& change_info : changes) { + base::TimeDelta latency = frame_received_time - change_info.timestamp; + switch (change_info.type) { + case test::CyclicFrameGenerator::ChangeType::NO_CHANGES: + NOTREACHED(); + break; + case test::CyclicFrameGenerator::ChangeType::FULL: + total_latency_big_frames += latency; + ++big_frame_count; + break; + case test::CyclicFrameGenerator::ChangeType::CURSOR: + total_latency_small_frames += latency; + ++small_frame_count; + break; + } + } + } + + CHECK(big_frame_count); + VLOG(0) << "Average latency for big frames: " + << (total_latency_big_frames / big_frame_count).InMillisecondsF(); + + if (small_frame_count) { + VLOG(0) + << "Average latency for small frames: " + << (total_latency_small_frames / small_frame_count).InMillisecondsF(); + } +} + TEST_P(ProtocolPerfTest, TotalLatencyIce) { MeasureTotalLatency(false); } @@ -645,4 +653,49 @@ TEST_P(ProtocolPerfTest, TotalLatencyWebrtc) { MeasureTotalLatency(true); } +// ScrollPerformance[Ice|Webrtc] tests simulate whole screen being scrolled +// continuously. They measure FPS and video latency. +void ProtocolPerfTest::MeasureScrollPerformance(bool use_webrtc) { + scoped_refptr frame_generator = + new test::ScrollFrameGenerator(); + + desktop_environment_factory_.set_frame_generator( + base::Bind(&test::ScrollFrameGenerator::GenerateFrame, frame_generator)); + + StartHostAndClient(use_webrtc, protocol::ChannelConfig::CODEC_VP8); + ASSERT_NO_FATAL_FAILURE(WaitConnected()); + + base::TimeTicks start_time = base::TimeTicks::Now(); + const base::TimeDelta kWarmUpTime = base::TimeDelta::FromSeconds(2); + while ((base::TimeTicks::Now() - start_time) < kWarmUpTime) { + ReceiveFrame(); + } + + // Run the test for 2 seconds. + const base::TimeDelta kTestTime = base::TimeDelta::FromSeconds(2); + + int num_frames = 0; + base::TimeDelta total_latency; + start_time = base::TimeTicks::Now(); + while ((base::TimeTicks::Now() - start_time) < kTestTime) { + std::unique_ptr frame = ReceiveFrame(); + ++num_frames; + total_latency += frame_generator->GetFrameLatency(*frame); + } + + VLOG(0) << "FPS: " + << num_frames / (base::TimeTicks::Now() - start_time).InSecondsF(); + + VLOG(0) << "Average latency: " + << (total_latency).InMillisecondsF() / num_frames; +} + +TEST_P(ProtocolPerfTest, ScrollPerformanceIce) { + MeasureScrollPerformance(false); +} + +TEST_P(ProtocolPerfTest, ScrollPerformanceWebrtc) { + MeasureScrollPerformance(true); +} + } // namespace remoting diff --git a/remoting/test/scroll_frame_generator.cc b/remoting/test/scroll_frame_generator.cc new file mode 100644 index 00000000000000..1a6a1ec0b6834d --- /dev/null +++ b/remoting/test/scroll_frame_generator.cc @@ -0,0 +1,60 @@ +// 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/scroll_frame_generator.h" + +#include "remoting/test/frame_generator_util.h" +#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h" + +namespace remoting { +namespace test { + +namespace { +int kScrollSpeedPixelsPerSecond = 500; +} // namespace + +ScrollFrameGenerator::ScrollFrameGenerator() + : base_frame_(LoadDesktopFrameFromPng("test_frame2.png")), + start_time_(base::TimeTicks::Now()) {} +ScrollFrameGenerator::~ScrollFrameGenerator() {} + +std::unique_ptr ScrollFrameGenerator::GenerateFrame( + webrtc::SharedMemoryFactory* shared_memory_factory) { + base::TimeTicks now = base::TimeTicks::Now(); + int position = static_cast(kScrollSpeedPixelsPerSecond * + (now - start_time_).InSecondsF()) % + base_frame_->size().height(); + std::unique_ptr result( + new webrtc::BasicDesktopFrame(base_frame_->size())); + + int top_height = base_frame_->size().height() - position; + + result->CopyPixelsFrom(*base_frame_, webrtc::DesktopVector(0, position), + webrtc::DesktopRect::MakeLTRB( + 0, 0, base_frame_->size().width(), top_height)); + result->CopyPixelsFrom( + *base_frame_, webrtc::DesktopVector(0, 0), + webrtc::DesktopRect::MakeLTRB(0, top_height, base_frame_->size().width(), + base_frame_->size().height())); + + result->mutable_updated_region()->SetRect( + webrtc::DesktopRect::MakeSize(result->size())); + + ++last_frame_id_; + frame_timestamp_[last_frame_id_] = now; + DrawBarcode(last_frame_id_, true, result.get()); + + return result; +} + +base::TimeDelta ScrollFrameGenerator::GetFrameLatency( + const webrtc::DesktopFrame& frame) { + int frame_id = ReadBarcode(frame); + if (!frame_timestamp_.count(frame_id)) + LOG(FATAL) << "Unknown frame_id."; + return base::TimeTicks::Now() - frame_timestamp_[frame_id]; +} + +} // namespace test +} // namespace remoting diff --git a/remoting/test/scroll_frame_generator.h b/remoting/test/scroll_frame_generator.h new file mode 100644 index 00000000000000..762ad7bd0c19dc --- /dev/null +++ b/remoting/test/scroll_frame_generator.h @@ -0,0 +1,46 @@ +// 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_SCROLL_FRAME_GENERATOR_H_ +#define REMOTING_TEST_SCROLL_FRAME_GENERATOR_H_ + +#include +#include + +#include "base/memory/ref_counted.h" +#include "base/time/time.h" +#include "third_party/webrtc/modules/desktop_capture/desktop_capturer.h" + +namespace remoting { +namespace test { + +class ScrollFrameGenerator + : public base::RefCountedThreadSafe { + public: + ScrollFrameGenerator(); + + std::unique_ptr GenerateFrame( + webrtc::SharedMemoryFactory* shared_memory_factory); + + base::TimeDelta GetFrameLatency(const webrtc::DesktopFrame& frame); + + private: + ~ScrollFrameGenerator(); + friend class base::RefCountedThreadSafe; + + std::unique_ptr base_frame_; + base::TimeTicks start_time_; + + std::unordered_map frame_timestamp_; + + // Id of the last frame encoded on the barcode. + int last_frame_id_ = -1; + + DISALLOW_COPY_AND_ASSIGN(ScrollFrameGenerator); +}; + +} // namespace test +} // namespace remoting + +#endif // REMOTING_TEST_SCROLL_FRAME_GENERATOR_H_