An early analysis shows in DirectX based capturer, Windows API returns larger
dirty region than the real screen change. A similar behavior may happen on other platforms with damage notification support. So it's better to have an individual layer to handle the Differ logic, and remove capturing independent logic out of each ScreenCapturer* implementation. So this change does following things, 1. Update differ_block to handle variable height. differ_block_sse2 has been renamed to differ_vector_sse2. 2. A new ScreenCapturerDifferWrapper implementation to help set DesktopFrame::updated_region(). It uses an underlying ScreenCapturer to do the real capture work, and updates the updated region of DesktopFrame returned from OnCaptureResult function. 3. FakeDesktopCapturer and FakeScreenCapturer to generate controllable DesktopFrame by using DesktopFrameGenerator and DesktopFramePainter. 4. Test ScreenCapturerDifferWrapper by using FakeScreenCapturer. After this change, we can eventually remove all Differ logic from ScreenCapturer* implementations, and fix a potential crash bug in ScreenCapturerLinux class. It wrongly assumes previous_frame() has a same size as current_frame(). https://goo.gl/3nSqOC BUG=633802 TBR=kjellander@webrtc.org Review-Url: https://codereview.webrtc.org/2202443002 Cr-Commit-Position: refs/heads/master@{#14076}
This commit is contained in:
parent
f71d298217
commit
fef8653c5a
@ -504,7 +504,13 @@ if (rtc_include_tests) {
|
||||
deps += [ "desktop_capture" ]
|
||||
sources += [
|
||||
"desktop_capture/desktop_and_cursor_composer_unittest.cc",
|
||||
"desktop_capture/desktop_frame_generator.cc",
|
||||
"desktop_capture/desktop_frame_generator.h",
|
||||
"desktop_capture/fake_desktop_capturer.h",
|
||||
"desktop_capture/fake_screen_capturer.cc",
|
||||
"desktop_capture/fake_screen_capturer.h",
|
||||
"desktop_capture/mouse_cursor_monitor_unittest.cc",
|
||||
"desktop_capture/screen_capturer_differ_wrapper_unittest.cc",
|
||||
"desktop_capture/screen_capturer_helper_unittest.cc",
|
||||
"desktop_capture/screen_capturer_mac_unittest.cc",
|
||||
"desktop_capture/screen_capturer_mock_objects.h",
|
||||
|
||||
@ -128,6 +128,8 @@ rtc_source_set("desktop_capture") {
|
||||
"differ.h",
|
||||
"differ_block.cc",
|
||||
"differ_block.h",
|
||||
"screen_capturer_differ_wrapper.cc",
|
||||
"screen_capturer_differ_wrapper.h",
|
||||
]
|
||||
}
|
||||
|
||||
@ -169,8 +171,8 @@ if (use_desktop_capture_differ_sse2) {
|
||||
rtc_source_set("desktop_capture_differ_sse2") {
|
||||
visibility = [ ":*" ]
|
||||
sources = [
|
||||
"differ_block_sse2.cc",
|
||||
"differ_block_sse2.h",
|
||||
"differ_vector_sse2.cc",
|
||||
"differ_vector_sse2.h",
|
||||
]
|
||||
|
||||
if (is_posix) {
|
||||
|
||||
@ -101,7 +101,6 @@
|
||||
'window_capturer.h',
|
||||
'window_capturer_mac.mm',
|
||||
'window_capturer_win.cc',
|
||||
|
||||
],
|
||||
'conditions': [
|
||||
['OS!="ios" and (target_arch=="ia32" or target_arch=="x64")', {
|
||||
@ -145,6 +144,8 @@
|
||||
'differ.h',
|
||||
'differ_block.cc',
|
||||
'differ_block.h',
|
||||
'screen_capturer_differ_wrapper.cc',
|
||||
'screen_capturer_differ_wrapper.h',
|
||||
],
|
||||
}],
|
||||
['OS=="mac"', {
|
||||
@ -182,8 +183,8 @@
|
||||
'target_name': 'desktop_capture_differ_sse2',
|
||||
'type': 'static_library',
|
||||
'sources': [
|
||||
'differ_block_sse2.cc',
|
||||
'differ_block_sse2.h',
|
||||
'differ_vector_sse2.cc',
|
||||
'differ_vector_sse2.h',
|
||||
],
|
||||
'conditions': [
|
||||
['os_posix==1', {
|
||||
|
||||
179
webrtc/modules/desktop_capture/desktop_frame_generator.cc
Normal file
179
webrtc/modules/desktop_capture/desktop_frame_generator.cc
Normal file
@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/modules/desktop_capture/desktop_frame_generator.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "webrtc/base/random.h"
|
||||
#include "webrtc/base/timeutils.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
// Sets |updated_region| to |frame|. If |enlarge_updated_region| is
|
||||
// true, this function will randomly enlarge each DesktopRect in
|
||||
// |updated_region|. But the enlarged DesktopRegion won't excceed the
|
||||
// frame->size(). If |add_random_updated_region| is true, several random
|
||||
// rectangles will also be included in |frame|.
|
||||
void SetUpdatedRegion(DesktopFrame* frame,
|
||||
const DesktopRegion& updated_region,
|
||||
bool enlarge_updated_region,
|
||||
int enlarge_range,
|
||||
bool add_random_updated_region) {
|
||||
const DesktopRect screen_rect = DesktopRect::MakeSize(frame->size());
|
||||
Random random(rtc::TimeMicros());
|
||||
frame->mutable_updated_region()->Clear();
|
||||
for (DesktopRegion::Iterator it(updated_region); !it.IsAtEnd();
|
||||
it.Advance()) {
|
||||
DesktopRect rect = it.rect();
|
||||
if (enlarge_updated_region && enlarge_range > 0) {
|
||||
rect.Extend(random.Rand(enlarge_range), random.Rand(enlarge_range),
|
||||
random.Rand(enlarge_range), random.Rand(enlarge_range));
|
||||
rect.IntersectWith(screen_rect);
|
||||
}
|
||||
frame->mutable_updated_region()->AddRect(rect);
|
||||
}
|
||||
|
||||
if (add_random_updated_region) {
|
||||
for (int i = random.Rand(10); i >= 0; i--) {
|
||||
// At least a 1 x 1 updated region.
|
||||
const int left = random.Rand(0, frame->size().width() - 2);
|
||||
const int top = random.Rand(0, frame->size().height() - 2);
|
||||
const int right = random.Rand(left + 1, frame->size().width());
|
||||
const int bottom = random.Rand(top + 1, frame->size().height());
|
||||
frame->mutable_updated_region()->AddRect(
|
||||
DesktopRect::MakeLTRB(left, top, right, bottom));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Paints pixels in |rect| of |frame| to |color|.
|
||||
void PaintRect(DesktopFrame* frame, DesktopRect rect, uint32_t color) {
|
||||
static_assert(DesktopFrame::kBytesPerPixel == sizeof(uint32_t),
|
||||
"kBytesPerPixel should be 4.");
|
||||
RTC_DCHECK(frame->size().width() >= rect.right() &&
|
||||
frame->size().height() >= rect.bottom());
|
||||
uint8_t* row = frame->GetFrameDataAtPos(rect.top_left());
|
||||
for (int i = 0; i < rect.height(); i++) {
|
||||
uint32_t* column = reinterpret_cast<uint32_t*>(row);
|
||||
for (int j = 0; j < rect.width(); j++) {
|
||||
column[j] = color;
|
||||
}
|
||||
row += frame->stride();
|
||||
}
|
||||
}
|
||||
|
||||
// Paints pixels in |region| of |frame| to |color|.
|
||||
void PaintRegion(DesktopFrame* frame, DesktopRegion* region, uint32_t color) {
|
||||
region->IntersectWith(DesktopRect::MakeSize(frame->size()));
|
||||
for (DesktopRegion::Iterator it(*region); !it.IsAtEnd(); it.Advance()) {
|
||||
PaintRect(frame, it.rect(), color);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
DesktopFrameGenerator::DesktopFrameGenerator() {}
|
||||
DesktopFrameGenerator::~DesktopFrameGenerator() {}
|
||||
|
||||
DesktopFramePainter::DesktopFramePainter() {}
|
||||
DesktopFramePainter::~DesktopFramePainter() {}
|
||||
|
||||
PainterDesktopFrameGenerator::PainterDesktopFrameGenerator()
|
||||
: size_(1024, 768),
|
||||
return_frame_(true),
|
||||
provide_updated_region_hints_(false),
|
||||
enlarge_updated_region_(false),
|
||||
enlarge_range_(20),
|
||||
add_random_updated_region_(false),
|
||||
painter_(nullptr) {}
|
||||
PainterDesktopFrameGenerator::~PainterDesktopFrameGenerator() {}
|
||||
|
||||
std::unique_ptr<DesktopFrame> PainterDesktopFrameGenerator::GetNextFrame(
|
||||
SharedMemoryFactory* factory) {
|
||||
if (!return_frame_) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<DesktopFrame> frame = std::unique_ptr<DesktopFrame>(
|
||||
factory ? SharedMemoryDesktopFrame::Create(size_, factory).release()
|
||||
: new BasicDesktopFrame(size_));
|
||||
if (painter_) {
|
||||
DesktopRegion updated_region;
|
||||
if (!painter_->Paint(frame.get(), &updated_region)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (provide_updated_region_hints_) {
|
||||
SetUpdatedRegion(frame.get(), updated_region, enlarge_updated_region_,
|
||||
enlarge_range_, add_random_updated_region_);
|
||||
} else {
|
||||
frame->mutable_updated_region()->SetRect(
|
||||
DesktopRect::MakeSize(frame->size()));
|
||||
}
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
DesktopSize* PainterDesktopFrameGenerator::size() {
|
||||
return &size_;
|
||||
}
|
||||
|
||||
void PainterDesktopFrameGenerator::set_return_frame(bool return_frame) {
|
||||
return_frame_ = return_frame;
|
||||
}
|
||||
|
||||
void PainterDesktopFrameGenerator::set_provide_updated_region_hints(
|
||||
bool provide_updated_region_hints) {
|
||||
provide_updated_region_hints_ = provide_updated_region_hints;
|
||||
}
|
||||
|
||||
void PainterDesktopFrameGenerator::set_enlarge_updated_region(
|
||||
bool enlarge_updated_region) {
|
||||
enlarge_updated_region_ = enlarge_updated_region;
|
||||
}
|
||||
|
||||
void PainterDesktopFrameGenerator::set_enlarge_range(int enlarge_range) {
|
||||
enlarge_range_ = enlarge_range;
|
||||
}
|
||||
|
||||
void PainterDesktopFrameGenerator::set_add_random_updated_region(
|
||||
bool add_random_updated_region) {
|
||||
add_random_updated_region_ = add_random_updated_region;
|
||||
}
|
||||
|
||||
void PainterDesktopFrameGenerator::set_desktop_frame_painter(
|
||||
DesktopFramePainter* painter) {
|
||||
painter_ = painter;
|
||||
}
|
||||
|
||||
BlackWhiteDesktopFramePainter::BlackWhiteDesktopFramePainter() {}
|
||||
BlackWhiteDesktopFramePainter::~BlackWhiteDesktopFramePainter() {}
|
||||
|
||||
DesktopRegion* BlackWhiteDesktopFramePainter::updated_region() {
|
||||
return &updated_region_;
|
||||
}
|
||||
|
||||
bool BlackWhiteDesktopFramePainter::Paint(DesktopFrame* frame,
|
||||
DesktopRegion* updated_region) {
|
||||
RTC_DCHECK(updated_region->is_empty());
|
||||
memset(frame->data(), 0, frame->stride() * frame->size().height());
|
||||
PaintRegion(frame, &updated_region_, UINT32_MAX);
|
||||
updated_region_.Swap(updated_region);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
121
webrtc/modules/desktop_capture/desktop_frame_generator.h
Normal file
121
webrtc/modules/desktop_capture/desktop_frame_generator.h
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_DESKTOP_FRAME_GENERATOR_H_
|
||||
#define WEBRTC_MODULES_DESKTOP_CAPTURE_DESKTOP_FRAME_GENERATOR_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "webrtc/modules/desktop_capture/desktop_frame.h"
|
||||
#include "webrtc/modules/desktop_capture/desktop_geometry.h"
|
||||
#include "webrtc/modules/desktop_capture/desktop_region.h"
|
||||
#include "webrtc/modules/desktop_capture/shared_memory.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// An interface to generate a DesktopFrame.
|
||||
class DesktopFrameGenerator {
|
||||
public:
|
||||
DesktopFrameGenerator();
|
||||
virtual ~DesktopFrameGenerator();
|
||||
|
||||
virtual std::unique_ptr<DesktopFrame> GetNextFrame(
|
||||
SharedMemoryFactory* factory) = 0;
|
||||
};
|
||||
|
||||
// An interface to paint a DesktopFrame. This interface is used by
|
||||
// PainterDesktopFrameGenerator.
|
||||
class DesktopFramePainter {
|
||||
public:
|
||||
DesktopFramePainter();
|
||||
virtual ~DesktopFramePainter();
|
||||
|
||||
virtual bool Paint(DesktopFrame* frame, DesktopRegion* updated_region) = 0;
|
||||
};
|
||||
|
||||
// An implementation of DesktopFrameGenerator to take care about the
|
||||
// DesktopFrame size, filling updated_region(), etc, but leaves the real
|
||||
// painting work to a DesktopFramePainter implementation.
|
||||
class PainterDesktopFrameGenerator final : public DesktopFrameGenerator {
|
||||
public:
|
||||
PainterDesktopFrameGenerator();
|
||||
~PainterDesktopFrameGenerator() override;
|
||||
|
||||
std::unique_ptr<DesktopFrame> GetNextFrame(
|
||||
SharedMemoryFactory* factory) override;
|
||||
|
||||
// Sets the size of the frame which will be returned in next GetNextFrame()
|
||||
// call.
|
||||
DesktopSize* size();
|
||||
|
||||
// Decides whether BaseDesktopFrameGenerator returns a frame in next Capture()
|
||||
// callback. If return_frame_ is true, BaseDesktopFrameGenerator will create a
|
||||
// frame according to both size_ and SharedMemoryFactory input, and uses
|
||||
// Paint() function to paint it.
|
||||
void set_return_frame(bool return_frame);
|
||||
|
||||
// Decides whether MockScreenCapturer returns a frame with updated regions.
|
||||
// MockScreenCapturer will keep DesktopFrame::updated_region() empty if this
|
||||
// field is false.
|
||||
void set_provide_updated_region_hints(bool provide_updated_region_hints);
|
||||
|
||||
// Decides whether MockScreenCapturer randomly enlarges updated regions in the
|
||||
// DesktopFrame. Set this field to true to simulate an inaccurate updated
|
||||
// regions' return from OS APIs.
|
||||
void set_enlarge_updated_region(bool enlarge_updated_region);
|
||||
|
||||
// The range to enlarge a updated region if |enlarge_updated_region_| is true.
|
||||
// If this field is less than zero, it will be treated as zero, and
|
||||
// |enlarge_updated_region_| will be ignored.
|
||||
void set_enlarge_range(int enlarge_range);
|
||||
|
||||
// Decides whether BaseDesktopFrameGenerator randomly add some updated regions
|
||||
// in the DesktopFrame. Set this field to true to simulate an inaccurate
|
||||
// updated regions' return from OS APIs.
|
||||
void set_add_random_updated_region(bool add_random_updated_region);
|
||||
|
||||
// Sets the painter object to do the real painting work, if no |painter_| has
|
||||
// been set to this instance, the DesktopFrame returned by GetNextFrame()
|
||||
// function will keep in an undefined but valid state.
|
||||
// PainterDesktopFrameGenerator does not take ownership of the |painter|.
|
||||
void set_desktop_frame_painter(DesktopFramePainter* painter);
|
||||
|
||||
private:
|
||||
DesktopSize size_;
|
||||
bool return_frame_;
|
||||
bool provide_updated_region_hints_;
|
||||
bool enlarge_updated_region_;
|
||||
int enlarge_range_;
|
||||
bool add_random_updated_region_;
|
||||
DesktopFramePainter* painter_;
|
||||
};
|
||||
|
||||
// An implementation of DesktopFramePainter to paint black on
|
||||
// mutable_updated_region(), and white elsewhere.
|
||||
class BlackWhiteDesktopFramePainter final : public DesktopFramePainter {
|
||||
public:
|
||||
BlackWhiteDesktopFramePainter();
|
||||
~BlackWhiteDesktopFramePainter() override;
|
||||
|
||||
// The black regions of the frame which will be returned in next Paint()
|
||||
// call. BlackWhiteDesktopFramePainter will draw a white frame, with black
|
||||
// in the updated_region_. Each Paint() call will consume updated_region_.
|
||||
DesktopRegion* updated_region();
|
||||
|
||||
// DesktopFramePainter interface.
|
||||
bool Paint(DesktopFrame* frame, DesktopRegion* updated_region) override;
|
||||
|
||||
private:
|
||||
DesktopRegion updated_region_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_DESKTOP_FRAME_GENERATOR_H_
|
||||
@ -44,5 +44,15 @@ void DesktopRect::Translate(int32_t dx, int32_t dy) {
|
||||
bottom_ += dy;
|
||||
}
|
||||
|
||||
void DesktopRect::Extend(int32_t left_offset,
|
||||
int32_t top_offset,
|
||||
int32_t right_offset,
|
||||
int32_t bottom_offset) {
|
||||
left_ -= left_offset;
|
||||
top_ -= top_offset;
|
||||
right_ += right_offset;
|
||||
bottom_ += bottom_offset;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
|
||||
@ -128,6 +128,16 @@ class DesktopRect {
|
||||
void Translate(int32_t dx, int32_t dy);
|
||||
void Translate(DesktopVector d) { Translate(d.x(), d.y()); };
|
||||
|
||||
// Enlarges current DesktopRect by subtracting |left_offset| and |top_offset|
|
||||
// from |left_| and |top_|, and adding |right_offset| and |bottom_offset| to
|
||||
// |right_| and |bottom_|. This function does not normalize the result, so
|
||||
// |left_| and |top_| may be less than zero or larger than |right_| and
|
||||
// |bottom_|.
|
||||
void Extend(int32_t left_offset,
|
||||
int32_t top_offset,
|
||||
int32_t right_offset,
|
||||
int32_t bottom_offset);
|
||||
|
||||
private:
|
||||
DesktopRect(int32_t left, int32_t top, int32_t right, int32_t bottom)
|
||||
: left_(left), top_(top), right_(right), bottom_(bottom) {
|
||||
|
||||
@ -13,49 +13,59 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "webrtc/typedefs.h"
|
||||
#include "webrtc/modules/desktop_capture/differ_block_sse2.h"
|
||||
#include "webrtc/modules/desktop_capture/differ_vector_sse2.h"
|
||||
#include "webrtc/system_wrappers/include/cpu_features_wrapper.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
bool BlockDifference_C(const uint8_t* image1,
|
||||
const uint8_t* image2,
|
||||
int stride) {
|
||||
int width_bytes = kBlockSize * kBytesPerPixel;
|
||||
namespace {
|
||||
|
||||
for (int y = 0; y < kBlockSize; y++) {
|
||||
if (memcmp(image1, image2, width_bytes) != 0)
|
||||
bool VectorDifference_C(const uint8_t* image1, const uint8_t* image2) {
|
||||
return memcmp(image1, image2, kBlockSize * kBytesPerPixel) != 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool VectorDifference(const uint8_t* image1, const uint8_t* image2) {
|
||||
static bool (*diff_proc)(const uint8_t*, const uint8_t*) = nullptr;
|
||||
|
||||
if (!diff_proc) {
|
||||
#if defined(WEBRTC_ARCH_ARM_FAMILY) || defined(WEBRTC_ARCH_MIPS_FAMILY)
|
||||
// For ARM and MIPS processors, always use C version.
|
||||
// TODO(hclam): Implement a NEON version.
|
||||
diff_proc = &VectorDifference_C;
|
||||
#else
|
||||
bool have_sse2 = WebRtc_GetCPUInfo(kSSE2) != 0;
|
||||
// For x86 processors, check if SSE2 is supported.
|
||||
if (have_sse2 && kBlockSize == 32) {
|
||||
diff_proc = &VectorDifference_SSE2_W32;
|
||||
} else if (have_sse2 && kBlockSize == 16) {
|
||||
diff_proc = &VectorDifference_SSE2_W16;
|
||||
} else {
|
||||
diff_proc = &VectorDifference_C;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return diff_proc(image1, image2);
|
||||
}
|
||||
|
||||
bool BlockDifference(const uint8_t* image1,
|
||||
const uint8_t* image2,
|
||||
int height,
|
||||
int stride) {
|
||||
for (int i = 0; i < height; i++) {
|
||||
if (VectorDifference(image1, image2)) {
|
||||
return true;
|
||||
}
|
||||
image1 += stride;
|
||||
image2 += stride;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BlockDifference(const uint8_t* image1,
|
||||
const uint8_t* image2,
|
||||
int stride) {
|
||||
static bool (*diff_proc)(const uint8_t*, const uint8_t*, int) = NULL;
|
||||
|
||||
if (!diff_proc) {
|
||||
#if defined(WEBRTC_ARCH_ARM_FAMILY) || defined(WEBRTC_ARCH_MIPS_FAMILY)
|
||||
// For ARM and MIPS processors, always use C version.
|
||||
// TODO(hclam): Implement a NEON version.
|
||||
diff_proc = &BlockDifference_C;
|
||||
#else
|
||||
bool have_sse2 = WebRtc_GetCPUInfo(kSSE2) != 0;
|
||||
// For x86 processors, check if SSE2 is supported.
|
||||
if (have_sse2 && kBlockSize == 32) {
|
||||
diff_proc = &BlockDifference_SSE2_W32;
|
||||
} else if (have_sse2 && kBlockSize == 16) {
|
||||
diff_proc = &BlockDifference_SSE2_W16;
|
||||
} else {
|
||||
diff_proc = &BlockDifference_C;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return diff_proc(image1, image2, stride);
|
||||
bool BlockDifference(const uint8_t* image1, const uint8_t* image2, int stride) {
|
||||
return BlockDifference(image1, image2, kBlockSize, stride);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -22,6 +22,17 @@ const int kBlockSize = 32;
|
||||
// Format: BGRA 32 bit.
|
||||
const int kBytesPerPixel = 4;
|
||||
|
||||
// Low level function to compare 2 vectors of pixels of size kBlockSize. Returns
|
||||
// whether the blocks differ.
|
||||
bool VectorDifference(const uint8_t* image1, const uint8_t* image2);
|
||||
|
||||
// Low level function to compare 2 blocks of pixels of size
|
||||
// (kBlockSize, |height|). Returns whether the blocks differ.
|
||||
bool BlockDifference(const uint8_t* image1,
|
||||
const uint8_t* image2,
|
||||
int height,
|
||||
int stride);
|
||||
|
||||
// Low level function to compare 2 blocks of pixels of size
|
||||
// (kBlockSize, kBlockSize). Returns whether the blocks differ.
|
||||
bool BlockDifference(const uint8_t* image1,
|
||||
|
||||
@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/modules/desktop_capture/differ_block_sse2.h"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
#else
|
||||
#include <mmintrin.h>
|
||||
#include <emmintrin.h>
|
||||
#endif
|
||||
|
||||
#include "webrtc/modules/desktop_capture/differ_block.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
extern bool BlockDifference_SSE2_W16(const uint8_t* image1,
|
||||
const uint8_t* image2,
|
||||
int stride) {
|
||||
__m128i acc = _mm_setzero_si128();
|
||||
__m128i v0;
|
||||
__m128i v1;
|
||||
__m128i sad;
|
||||
for (int y = 0; y < kBlockSize; ++y) {
|
||||
const __m128i* i1 = reinterpret_cast<const __m128i*>(image1);
|
||||
const __m128i* i2 = reinterpret_cast<const __m128i*>(image2);
|
||||
v0 = _mm_loadu_si128(i1);
|
||||
v1 = _mm_loadu_si128(i2);
|
||||
sad = _mm_sad_epu8(v0, v1);
|
||||
acc = _mm_adds_epu16(acc, sad);
|
||||
v0 = _mm_loadu_si128(i1 + 1);
|
||||
v1 = _mm_loadu_si128(i2 + 1);
|
||||
sad = _mm_sad_epu8(v0, v1);
|
||||
acc = _mm_adds_epu16(acc, sad);
|
||||
v0 = _mm_loadu_si128(i1 + 2);
|
||||
v1 = _mm_loadu_si128(i2 + 2);
|
||||
sad = _mm_sad_epu8(v0, v1);
|
||||
acc = _mm_adds_epu16(acc, sad);
|
||||
v0 = _mm_loadu_si128(i1 + 3);
|
||||
v1 = _mm_loadu_si128(i2 + 3);
|
||||
sad = _mm_sad_epu8(v0, v1);
|
||||
acc = _mm_adds_epu16(acc, sad);
|
||||
|
||||
// This essential means sad = acc >> 64. We only care about the lower 16
|
||||
// bits.
|
||||
sad = _mm_shuffle_epi32(acc, 0xEE);
|
||||
sad = _mm_adds_epu16(sad, acc);
|
||||
int diff = _mm_cvtsi128_si32(sad);
|
||||
if (diff)
|
||||
return true;
|
||||
image1 += stride;
|
||||
image2 += stride;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
extern bool BlockDifference_SSE2_W32(const uint8_t* image1,
|
||||
const uint8_t* image2,
|
||||
int stride) {
|
||||
__m128i acc = _mm_setzero_si128();
|
||||
__m128i v0;
|
||||
__m128i v1;
|
||||
__m128i sad;
|
||||
for (int y = 0; y < kBlockSize; ++y) {
|
||||
const __m128i* i1 = reinterpret_cast<const __m128i*>(image1);
|
||||
const __m128i* i2 = reinterpret_cast<const __m128i*>(image2);
|
||||
v0 = _mm_loadu_si128(i1);
|
||||
v1 = _mm_loadu_si128(i2);
|
||||
sad = _mm_sad_epu8(v0, v1);
|
||||
acc = _mm_adds_epu16(acc, sad);
|
||||
v0 = _mm_loadu_si128(i1 + 1);
|
||||
v1 = _mm_loadu_si128(i2 + 1);
|
||||
sad = _mm_sad_epu8(v0, v1);
|
||||
acc = _mm_adds_epu16(acc, sad);
|
||||
v0 = _mm_loadu_si128(i1 + 2);
|
||||
v1 = _mm_loadu_si128(i2 + 2);
|
||||
sad = _mm_sad_epu8(v0, v1);
|
||||
acc = _mm_adds_epu16(acc, sad);
|
||||
v0 = _mm_loadu_si128(i1 + 3);
|
||||
v1 = _mm_loadu_si128(i2 + 3);
|
||||
sad = _mm_sad_epu8(v0, v1);
|
||||
acc = _mm_adds_epu16(acc, sad);
|
||||
v0 = _mm_loadu_si128(i1 + 4);
|
||||
v1 = _mm_loadu_si128(i2 + 4);
|
||||
sad = _mm_sad_epu8(v0, v1);
|
||||
acc = _mm_adds_epu16(acc, sad);
|
||||
v0 = _mm_loadu_si128(i1 + 5);
|
||||
v1 = _mm_loadu_si128(i2 + 5);
|
||||
sad = _mm_sad_epu8(v0, v1);
|
||||
acc = _mm_adds_epu16(acc, sad);
|
||||
v0 = _mm_loadu_si128(i1 + 6);
|
||||
v1 = _mm_loadu_si128(i2 + 6);
|
||||
sad = _mm_sad_epu8(v0, v1);
|
||||
acc = _mm_adds_epu16(acc, sad);
|
||||
v0 = _mm_loadu_si128(i1 + 7);
|
||||
v1 = _mm_loadu_si128(i2 + 7);
|
||||
sad = _mm_sad_epu8(v0, v1);
|
||||
acc = _mm_adds_epu16(acc, sad);
|
||||
|
||||
// This essential means sad = acc >> 64. We only care about the lower 16
|
||||
// bits.
|
||||
sad = _mm_shuffle_epi32(acc, 0xEE);
|
||||
sad = _mm_adds_epu16(sad, acc);
|
||||
int diff = _mm_cvtsi128_si32(sad);
|
||||
if (diff)
|
||||
return true;
|
||||
image1 += stride;
|
||||
image2 += stride;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
// This header file is used only differ_block.h. It defines the SSE2 rountines
|
||||
// for finding block difference.
|
||||
|
||||
#ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_DIFFER_BLOCK_SSE2_H_
|
||||
#define WEBRTC_MODULES_DESKTOP_CAPTURE_DIFFER_BLOCK_SSE2_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Find block difference of dimension 16x16.
|
||||
extern bool BlockDifference_SSE2_W16(const uint8_t* image1,
|
||||
const uint8_t* image2,
|
||||
int stride);
|
||||
|
||||
// Find block difference of dimension 32x32.
|
||||
extern bool BlockDifference_SSE2_W32(const uint8_t* image1,
|
||||
const uint8_t* image2,
|
||||
int stride);
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_DIFFER_BLOCK_SSE2_H_
|
||||
102
webrtc/modules/desktop_capture/differ_vector_sse2.cc
Normal file
102
webrtc/modules/desktop_capture/differ_vector_sse2.cc
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/modules/desktop_capture/differ_vector_sse2.h"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
#else
|
||||
#include <mmintrin.h>
|
||||
#include <emmintrin.h>
|
||||
#endif
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
extern bool VectorDifference_SSE2_W16(const uint8_t* image1,
|
||||
const uint8_t* image2) {
|
||||
__m128i acc = _mm_setzero_si128();
|
||||
__m128i v0;
|
||||
__m128i v1;
|
||||
__m128i sad;
|
||||
const __m128i* i1 = reinterpret_cast<const __m128i*>(image1);
|
||||
const __m128i* i2 = reinterpret_cast<const __m128i*>(image2);
|
||||
v0 = _mm_loadu_si128(i1);
|
||||
v1 = _mm_loadu_si128(i2);
|
||||
sad = _mm_sad_epu8(v0, v1);
|
||||
acc = _mm_adds_epu16(acc, sad);
|
||||
v0 = _mm_loadu_si128(i1 + 1);
|
||||
v1 = _mm_loadu_si128(i2 + 1);
|
||||
sad = _mm_sad_epu8(v0, v1);
|
||||
acc = _mm_adds_epu16(acc, sad);
|
||||
v0 = _mm_loadu_si128(i1 + 2);
|
||||
v1 = _mm_loadu_si128(i2 + 2);
|
||||
sad = _mm_sad_epu8(v0, v1);
|
||||
acc = _mm_adds_epu16(acc, sad);
|
||||
v0 = _mm_loadu_si128(i1 + 3);
|
||||
v1 = _mm_loadu_si128(i2 + 3);
|
||||
sad = _mm_sad_epu8(v0, v1);
|
||||
acc = _mm_adds_epu16(acc, sad);
|
||||
|
||||
// This essential means sad = acc >> 64. We only care about the lower 16
|
||||
// bits.
|
||||
sad = _mm_shuffle_epi32(acc, 0xEE);
|
||||
sad = _mm_adds_epu16(sad, acc);
|
||||
return _mm_cvtsi128_si32(sad) != 0;
|
||||
}
|
||||
|
||||
extern bool VectorDifference_SSE2_W32(const uint8_t* image1,
|
||||
const uint8_t* image2) {
|
||||
__m128i acc = _mm_setzero_si128();
|
||||
__m128i v0;
|
||||
__m128i v1;
|
||||
__m128i sad;
|
||||
const __m128i* i1 = reinterpret_cast<const __m128i*>(image1);
|
||||
const __m128i* i2 = reinterpret_cast<const __m128i*>(image2);
|
||||
v0 = _mm_loadu_si128(i1);
|
||||
v1 = _mm_loadu_si128(i2);
|
||||
sad = _mm_sad_epu8(v0, v1);
|
||||
acc = _mm_adds_epu16(acc, sad);
|
||||
v0 = _mm_loadu_si128(i1 + 1);
|
||||
v1 = _mm_loadu_si128(i2 + 1);
|
||||
sad = _mm_sad_epu8(v0, v1);
|
||||
acc = _mm_adds_epu16(acc, sad);
|
||||
v0 = _mm_loadu_si128(i1 + 2);
|
||||
v1 = _mm_loadu_si128(i2 + 2);
|
||||
sad = _mm_sad_epu8(v0, v1);
|
||||
acc = _mm_adds_epu16(acc, sad);
|
||||
v0 = _mm_loadu_si128(i1 + 3);
|
||||
v1 = _mm_loadu_si128(i2 + 3);
|
||||
sad = _mm_sad_epu8(v0, v1);
|
||||
acc = _mm_adds_epu16(acc, sad);
|
||||
v0 = _mm_loadu_si128(i1 + 4);
|
||||
v1 = _mm_loadu_si128(i2 + 4);
|
||||
sad = _mm_sad_epu8(v0, v1);
|
||||
acc = _mm_adds_epu16(acc, sad);
|
||||
v0 = _mm_loadu_si128(i1 + 5);
|
||||
v1 = _mm_loadu_si128(i2 + 5);
|
||||
sad = _mm_sad_epu8(v0, v1);
|
||||
acc = _mm_adds_epu16(acc, sad);
|
||||
v0 = _mm_loadu_si128(i1 + 6);
|
||||
v1 = _mm_loadu_si128(i2 + 6);
|
||||
sad = _mm_sad_epu8(v0, v1);
|
||||
acc = _mm_adds_epu16(acc, sad);
|
||||
v0 = _mm_loadu_si128(i1 + 7);
|
||||
v1 = _mm_loadu_si128(i2 + 7);
|
||||
sad = _mm_sad_epu8(v0, v1);
|
||||
acc = _mm_adds_epu16(acc, sad);
|
||||
|
||||
// This essential means sad = acc >> 64. We only care about the lower 16
|
||||
// bits.
|
||||
sad = _mm_shuffle_epi32(acc, 0xEE);
|
||||
sad = _mm_adds_epu16(sad, acc);
|
||||
return _mm_cvtsi128_si32(sad) != 0;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
31
webrtc/modules/desktop_capture/differ_vector_sse2.h
Normal file
31
webrtc/modules/desktop_capture/differ_vector_sse2.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
// This header file is used only differ_block.h. It defines the SSE2 rountines
|
||||
// for finding vector difference.
|
||||
|
||||
#ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_DIFFER_VECTOR_SSE2_H_
|
||||
#define WEBRTC_MODULES_DESKTOP_CAPTURE_DIFFER_VECTOR_SSE2_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Find vector difference of dimension 16.
|
||||
extern bool VectorDifference_SSE2_W16(const uint8_t* image1,
|
||||
const uint8_t* image2);
|
||||
|
||||
// Find vector difference of dimension 32.
|
||||
extern bool VectorDifference_SSE2_W32(const uint8_t* image1,
|
||||
const uint8_t* image2);
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_DIFFER_VECTOR_SSE2_H_
|
||||
95
webrtc/modules/desktop_capture/fake_desktop_capturer.h
Normal file
95
webrtc/modules/desktop_capture/fake_desktop_capturer.h
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_FAKE_DESKTOP_CAPTURER_H_
|
||||
#define WEBRTC_MODULES_DESKTOP_CAPTURE_FAKE_DESKTOP_CAPTURER_H_
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "webrtc/modules/desktop_capture/desktop_capturer.h"
|
||||
#include "webrtc/modules/desktop_capture/desktop_frame_generator.h"
|
||||
#include "webrtc/modules/desktop_capture/shared_desktop_frame.h"
|
||||
#include "webrtc/modules/desktop_capture/shared_memory.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// A fake implementation of DesktopCapturer or its derived interfaces to
|
||||
// generate DesktopFrame for testing purpose.
|
||||
//
|
||||
// Consumers can provide a FrameGenerator instance to generate instances of
|
||||
// DesktopFrame to return for each Capture() function call.
|
||||
// If no FrameGenerator provided, FakeDesktopCapturer will always return a
|
||||
// nullptr DesktopFrame.
|
||||
//
|
||||
// Double buffering is guaranteed by the FrameGenerator. FrameGenerator
|
||||
// implements in desktop_frame_generator.h guarantee double buffering, they
|
||||
// creates a new instance of DesktopFrame each time.
|
||||
//
|
||||
// T must be DesktopCapturer or its derived interfaces.
|
||||
//
|
||||
// TODO(zijiehe): Remove template T once we merge ScreenCapturer and
|
||||
// WindowCapturer.
|
||||
template <typename T>
|
||||
class FakeDesktopCapturer : public T {
|
||||
public:
|
||||
FakeDesktopCapturer()
|
||||
: callback_(nullptr),
|
||||
result_(DesktopCapturer::Result::SUCCESS),
|
||||
generator_(nullptr) {}
|
||||
|
||||
~FakeDesktopCapturer() override {}
|
||||
|
||||
// Decides the result which will be returned in next Capture() callback.
|
||||
void set_result(DesktopCapturer::Result result) { result_ = result; }
|
||||
|
||||
// Uses the |generator| provided as DesktopFrameGenerator, FakeDesktopCapturer
|
||||
// does
|
||||
// not take the ownership of |generator|.
|
||||
void set_frame_generator(DesktopFrameGenerator* generator) {
|
||||
generator_ = generator;
|
||||
}
|
||||
|
||||
// DesktopCapturer interface
|
||||
void Start(DesktopCapturer::Callback* callback) override {
|
||||
callback_ = callback;
|
||||
}
|
||||
|
||||
void Capture(const DesktopRegion& region) override {
|
||||
if (generator_) {
|
||||
std::unique_ptr<DesktopFrame> frame(
|
||||
generator_->GetNextFrame(shared_memory_factory_.get()));
|
||||
if (frame) {
|
||||
callback_->OnCaptureResult(result_, std::move(frame));
|
||||
} else {
|
||||
callback_->OnCaptureResult(DesktopCapturer::Result::ERROR_TEMPORARY,
|
||||
nullptr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
callback_->OnCaptureResult(DesktopCapturer::Result::ERROR_PERMANENT,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
void SetSharedMemoryFactory(
|
||||
std::unique_ptr<SharedMemoryFactory> shared_memory_factory) override {
|
||||
shared_memory_factory_ = std::move(shared_memory_factory);
|
||||
}
|
||||
|
||||
private:
|
||||
DesktopCapturer::Callback* callback_;
|
||||
std::unique_ptr<SharedMemoryFactory> shared_memory_factory_;
|
||||
DesktopCapturer::Result result_;
|
||||
DesktopFrameGenerator* generator_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_FAKE_DESKTOP_CAPTURER_H_
|
||||
34
webrtc/modules/desktop_capture/fake_screen_capturer.cc
Normal file
34
webrtc/modules/desktop_capture/fake_screen_capturer.cc
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/modules/desktop_capture/fake_screen_capturer.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
FakeScreenCapturer::FakeScreenCapturer()
|
||||
: FakeDesktopCapturer(),
|
||||
// A random number for the fake screen.
|
||||
id_(1378277498) {}
|
||||
FakeScreenCapturer::~FakeScreenCapturer() {}
|
||||
|
||||
bool FakeScreenCapturer::GetScreenList(ScreenList* list) {
|
||||
list->push_back(Screen{id_});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FakeScreenCapturer::SelectScreen(ScreenId id) {
|
||||
return id == kFullDesktopScreenId || id == id_;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
35
webrtc/modules/desktop_capture/fake_screen_capturer.h
Normal file
35
webrtc/modules/desktop_capture/fake_screen_capturer.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_FAKE_SCREEN_CAPTURER_H_
|
||||
#define WEBRTC_MODULES_DESKTOP_CAPTURE_FAKE_SCREEN_CAPTURER_H_
|
||||
|
||||
#include "webrtc/modules/desktop_capture/fake_desktop_capturer.h"
|
||||
#include "webrtc/modules/desktop_capture/screen_capturer.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class FakeScreenCapturer : public FakeDesktopCapturer<ScreenCapturer> {
|
||||
public:
|
||||
FakeScreenCapturer();
|
||||
~FakeScreenCapturer() override;
|
||||
|
||||
// ScreenCapturer interface.
|
||||
bool GetScreenList(ScreenList* list) override;
|
||||
bool SelectScreen(ScreenId id) override;
|
||||
|
||||
private:
|
||||
// A random ScreenId.
|
||||
const ScreenId id_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_FAKE_SCREEN_CAPTURER_H_
|
||||
214
webrtc/modules/desktop_capture/screen_capturer_differ_wrapper.cc
Normal file
214
webrtc/modules/desktop_capture/screen_capturer_differ_wrapper.cc
Normal file
@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/modules/desktop_capture/screen_capturer_differ_wrapper.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/base/timeutils.h"
|
||||
#include "webrtc/modules/desktop_capture/desktop_geometry.h"
|
||||
#include "webrtc/modules/desktop_capture/differ_block.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
// Returns true if (0, 0) - (|width|, |height|) vector in |old_buffer| and
|
||||
// |new_buffer| are equal. |width| should be less than 32
|
||||
// (defined by kBlockSize), otherwise BlockDifference() should be used.
|
||||
bool PartialBlockDifference(const uint8_t* old_buffer,
|
||||
const uint8_t* new_buffer,
|
||||
int width,
|
||||
int height,
|
||||
int stride) {
|
||||
RTC_DCHECK_LT(width, kBlockSize);
|
||||
const int width_bytes = width * DesktopFrame::kBytesPerPixel;
|
||||
for (int i = 0; i < height; i++) {
|
||||
if (memcmp(old_buffer, new_buffer, width_bytes) != 0) {
|
||||
return true;
|
||||
}
|
||||
old_buffer += stride;
|
||||
new_buffer += stride;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compares columns in the range of [|left|, |right|), in a row in the
|
||||
// range of [|top|, |top| + |height|), starts from |old_buffer| and
|
||||
// |new_buffer|, and outputs updated regions into |output|. |stride| is the
|
||||
// DesktopFrame::stride().
|
||||
void CompareRow(const uint8_t* old_buffer,
|
||||
const uint8_t* new_buffer,
|
||||
const int left,
|
||||
const int right,
|
||||
const int top,
|
||||
const int bottom,
|
||||
const int stride,
|
||||
DesktopRegion* const output) {
|
||||
const int block_x_offset = kBlockSize * DesktopFrame::kBytesPerPixel;
|
||||
const int width = right - left;
|
||||
const int height = bottom - top;
|
||||
const int block_count = (width - 1) / kBlockSize;
|
||||
const int last_block_width = width - block_count * kBlockSize;
|
||||
RTC_DCHECK(last_block_width <= kBlockSize && last_block_width > 0);
|
||||
|
||||
// The first block-column in a continuous dirty area in current block-row.
|
||||
int first_dirty_x_block = -1;
|
||||
|
||||
// We always need to add dirty area into |output| in the last block, so handle
|
||||
// it separatedly.
|
||||
for (int x = 0; x < block_count; x++) {
|
||||
if (BlockDifference(old_buffer, new_buffer, height, stride)) {
|
||||
if (first_dirty_x_block == -1) {
|
||||
// This is the first dirty block in a continuous dirty area.
|
||||
first_dirty_x_block = x;
|
||||
}
|
||||
} else if (first_dirty_x_block != -1) {
|
||||
// The block on the left is the last dirty block in a continuous
|
||||
// dirty area.
|
||||
output->AddRect(DesktopRect::MakeLTRB(
|
||||
first_dirty_x_block * kBlockSize + left, top,
|
||||
x * kBlockSize + left, bottom));
|
||||
first_dirty_x_block = -1;
|
||||
}
|
||||
old_buffer += block_x_offset;
|
||||
new_buffer += block_x_offset;
|
||||
}
|
||||
|
||||
bool last_block_diff;
|
||||
if (last_block_width < kBlockSize) {
|
||||
// The last one is a partial vector.
|
||||
last_block_diff = PartialBlockDifference(
|
||||
old_buffer, new_buffer, last_block_width, height, stride);
|
||||
} else {
|
||||
last_block_diff =
|
||||
BlockDifference(old_buffer, new_buffer, height, stride);
|
||||
}
|
||||
if (last_block_diff) {
|
||||
if (first_dirty_x_block == -1) {
|
||||
first_dirty_x_block = block_count;
|
||||
}
|
||||
output->AddRect(
|
||||
DesktopRect::MakeLTRB(first_dirty_x_block * kBlockSize + left,
|
||||
top, right, bottom));
|
||||
} else if (first_dirty_x_block != -1) {
|
||||
output->AddRect(DesktopRect::MakeLTRB(
|
||||
first_dirty_x_block * kBlockSize + left, top,
|
||||
block_count * kBlockSize + left, bottom));
|
||||
}
|
||||
}
|
||||
|
||||
// Compares |rect| area in |old_frame| and |new_frame|, and outputs dirty
|
||||
// regions into |output|.
|
||||
void CompareFrames(const DesktopFrame& old_frame,
|
||||
const DesktopFrame& new_frame,
|
||||
DesktopRect rect,
|
||||
DesktopRegion* const output) {
|
||||
RTC_DCHECK(old_frame.size().equals(new_frame.size()));
|
||||
RTC_DCHECK_EQ(old_frame.stride(), new_frame.stride());
|
||||
rect.IntersectWith(DesktopRect::MakeSize(old_frame.size()));
|
||||
|
||||
const int y_block_count = (rect.height() - 1) / kBlockSize;
|
||||
const int last_y_block_height = rect.height() - y_block_count * kBlockSize;
|
||||
// Offset from the start of one block-row to the next.
|
||||
const int block_y_stride = old_frame.stride() * kBlockSize;
|
||||
const uint8_t* prev_block_row_start =
|
||||
old_frame.GetFrameDataAtPos(rect.top_left());
|
||||
const uint8_t* curr_block_row_start =
|
||||
new_frame.GetFrameDataAtPos(rect.top_left());
|
||||
|
||||
int top = rect.top();
|
||||
// The last row may have a different height, so we handle it separately.
|
||||
for (int y = 0; y < y_block_count; y++) {
|
||||
CompareRow(prev_block_row_start, curr_block_row_start, rect.left(),
|
||||
rect.right(), top, top + kBlockSize,
|
||||
old_frame.stride(), output);
|
||||
top += kBlockSize;
|
||||
prev_block_row_start += block_y_stride;
|
||||
curr_block_row_start += block_y_stride;
|
||||
}
|
||||
CompareRow(prev_block_row_start, curr_block_row_start, rect.left(),
|
||||
rect.right(), top, top + last_y_block_height,
|
||||
old_frame.stride(), output);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ScreenCapturerDifferWrapper::ScreenCapturerDifferWrapper(
|
||||
std::unique_ptr<ScreenCapturer> base_capturer)
|
||||
: base_capturer_(std::move(base_capturer)) {
|
||||
RTC_DCHECK(base_capturer_);
|
||||
}
|
||||
|
||||
ScreenCapturerDifferWrapper::~ScreenCapturerDifferWrapper() {}
|
||||
|
||||
void ScreenCapturerDifferWrapper::Start(DesktopCapturer::Callback* callback) {
|
||||
callback_ = callback;
|
||||
base_capturer_->Start(this);
|
||||
}
|
||||
|
||||
void ScreenCapturerDifferWrapper::SetSharedMemoryFactory(
|
||||
std::unique_ptr<SharedMemoryFactory> shared_memory_factory) {
|
||||
base_capturer_->SetSharedMemoryFactory(std::move(shared_memory_factory));
|
||||
}
|
||||
|
||||
void ScreenCapturerDifferWrapper::Capture(const DesktopRegion& region) {
|
||||
base_capturer_->Capture(region);
|
||||
}
|
||||
|
||||
bool ScreenCapturerDifferWrapper::GetScreenList(ScreenList* screens) {
|
||||
return base_capturer_->GetScreenList(screens);
|
||||
}
|
||||
|
||||
bool ScreenCapturerDifferWrapper::SelectScreen(ScreenId id) {
|
||||
return base_capturer_->SelectScreen(id);
|
||||
}
|
||||
|
||||
void ScreenCapturerDifferWrapper::OnCaptureResult(
|
||||
Result result,
|
||||
std::unique_ptr<DesktopFrame> input_frame) {
|
||||
int64_t start_time_nanos = rtc::TimeNanos();
|
||||
if (!input_frame) {
|
||||
callback_->OnCaptureResult(result, nullptr);
|
||||
return;
|
||||
}
|
||||
RTC_DCHECK(result == Result::SUCCESS);
|
||||
|
||||
std::unique_ptr<SharedDesktopFrame> frame =
|
||||
SharedDesktopFrame::Wrap(std::move(input_frame));
|
||||
if (last_frame_ &&
|
||||
(last_frame_->size().width() != frame->size().width() ||
|
||||
last_frame_->size().height() != frame->size().height() ||
|
||||
last_frame_->stride() != frame->stride())) {
|
||||
last_frame_.reset();
|
||||
}
|
||||
|
||||
if (last_frame_) {
|
||||
DesktopRegion hints;
|
||||
hints.Swap(frame->GetUnderlyingFrame()->mutable_updated_region());
|
||||
for (DesktopRegion::Iterator it(hints); !it.IsAtEnd(); it.Advance()) {
|
||||
CompareFrames(*last_frame_, *frame, it.rect(),
|
||||
frame->mutable_updated_region());
|
||||
}
|
||||
} else {
|
||||
frame->mutable_updated_region()->SetRect(
|
||||
DesktopRect::MakeSize(frame->size()));
|
||||
}
|
||||
last_frame_ = frame->Share();
|
||||
|
||||
frame->set_capture_time_ms(frame->GetUnderlyingFrame()->capture_time_ms() +
|
||||
(rtc::TimeNanos() - start_time_nanos) /
|
||||
rtc::kNumNanosecsPerMillisec);
|
||||
callback_->OnCaptureResult(result, std::move(frame));
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_SCREEN_CAPTURER_DIFFER_WRAPPER_H_
|
||||
#define WEBRTC_MODULES_DESKTOP_CAPTURE_SCREEN_CAPTURER_DIFFER_WRAPPER_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "webrtc/modules/desktop_capture/screen_capturer.h"
|
||||
#include "webrtc/modules/desktop_capture/shared_desktop_frame.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// ScreenCapturer wrapper that calculates updated_region() by comparing frames
|
||||
// content. This class always expects the underlying ScreenCapturer
|
||||
// implementation returns a superset of updated regions in DestkopFrame. If a
|
||||
// ScreenCapturer implementation does not know the updated region, it should
|
||||
// set updated_region() to full frame.
|
||||
//
|
||||
// This class marks entire frame as updated if the frame size or frame stride
|
||||
// has been changed.
|
||||
class ScreenCapturerDifferWrapper : public ScreenCapturer,
|
||||
public DesktopCapturer::Callback {
|
||||
public:
|
||||
// Creates a ScreenCapturerDifferWrapper with a ScreenCapturer implementation,
|
||||
// and takes its ownership.
|
||||
explicit ScreenCapturerDifferWrapper(
|
||||
std::unique_ptr<ScreenCapturer> base_capturer);
|
||||
~ScreenCapturerDifferWrapper() override;
|
||||
|
||||
// ScreenCapturer interface.
|
||||
void Start(DesktopCapturer::Callback* callback) override;
|
||||
void SetSharedMemoryFactory(
|
||||
std::unique_ptr<SharedMemoryFactory> shared_memory_factory) override;
|
||||
void Capture(const DesktopRegion& region) override;
|
||||
bool GetScreenList(ScreenList* screens) override;
|
||||
bool SelectScreen(ScreenId id) override;
|
||||
|
||||
private:
|
||||
// DesktopCapturer::Callback interface.
|
||||
void OnCaptureResult(Result result,
|
||||
std::unique_ptr<DesktopFrame> frame) override;
|
||||
|
||||
const std::unique_ptr<ScreenCapturer> base_capturer_;
|
||||
DesktopCapturer::Callback* callback_;
|
||||
std::unique_ptr<SharedDesktopFrame> last_frame_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_SCREEN_CAPTURER_DIFFER_WRAPPER_H_
|
||||
@ -0,0 +1,291 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/modules/desktop_capture/screen_capturer_differ_wrapper.h"
|
||||
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "webrtc/base/random.h"
|
||||
#include "webrtc/base/timeutils.h"
|
||||
#include "webrtc/modules/desktop_capture/desktop_geometry.h"
|
||||
#include "webrtc/modules/desktop_capture/desktop_region.h"
|
||||
#include "webrtc/modules/desktop_capture/differ_block.h"
|
||||
#include "webrtc/modules/desktop_capture/fake_screen_capturer.h"
|
||||
#include "webrtc/modules/desktop_capture/screen_capturer_mock_objects.h"
|
||||
#include "webrtc/system_wrappers/include/cpu_features_wrapper.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
// Compares and asserts |frame|.updated_region() equals to |rects|. This
|
||||
// function does not care about the order of the |rects| and it does not expect
|
||||
// DesktopRegion to return an exact area for each rectangle in |rects|.
|
||||
template <template <typename, typename...> class T = std::initializer_list,
|
||||
typename... Rect>
|
||||
void AssertUpdatedRegionIs(const DesktopFrame& frame,
|
||||
const T<DesktopRect, Rect...>& rects) {
|
||||
DesktopRegion region;
|
||||
for (const auto& rect : rects) {
|
||||
region.AddRect(rect);
|
||||
}
|
||||
ASSERT_TRUE(frame.updated_region().Equals(region));
|
||||
}
|
||||
|
||||
// Compares and asserts |frame|.updated_region() covers all rectangles in
|
||||
// |rects|, but does not cover areas other than a kBlockSize expansion. This
|
||||
// function does not care about the order of the |rects|, and it does not expect
|
||||
// DesktopRegion to return an exact area of each rectangle in |rects|.
|
||||
template <template <typename, typename...> class T = std::initializer_list,
|
||||
typename... Rect>
|
||||
void AssertUpdatedRegionCovers(const DesktopFrame& frame,
|
||||
const T<DesktopRect, Rect...>& rects) {
|
||||
DesktopRegion region;
|
||||
for (const auto& rect : rects) {
|
||||
region.AddRect(rect);
|
||||
}
|
||||
|
||||
// Intersect of |rects| and |frame|.updated_region() should be |rects|. i.e.
|
||||
// |frame|.updated_region() should be a superset of |rects|.
|
||||
DesktopRegion intersect(region);
|
||||
intersect.IntersectWith(frame.updated_region());
|
||||
ASSERT_TRUE(region.Equals(intersect));
|
||||
|
||||
// Difference between |rects| and |frame|.updated_region() should not cover
|
||||
// areas which have larger than twice of kBlockSize width and height.
|
||||
//
|
||||
// Explanation of the 'twice' of kBlockSize (indeed kBlockSize * 2 - 2) is
|
||||
// following,
|
||||
// (Each block in the following grid is a 8 x 8 pixels area. X means the real
|
||||
// updated area, m means the updated area marked by
|
||||
// ScreenCapturerDifferWrapper.)
|
||||
// +---+---+---+---+---+---+---+---+
|
||||
// | X | m | m | m | m | m | m | m |
|
||||
// +---+---+---+---+---+---+---+---+
|
||||
// | m | m | m | m | m | m | m | m |
|
||||
// +---+---+---+---+---+---+---+---+
|
||||
// | m | m | m | m | m | m | m | m |
|
||||
// +---+---+---+---+---+---+---+---+
|
||||
// | m | m | m | m | m | m | m | X |
|
||||
// +---+---+---+---+---+---+---+---+
|
||||
// The top left [0, 0] - [8, 8] and right bottom [56, 24] - [64, 32] blocks of
|
||||
// this area are updated. But since ScreenCapturerDifferWrapper compares
|
||||
// 32 x 32 blocks by default, this entire area is marked as updated. So the
|
||||
// [8, 8] - [56, 32] is expected to be covered in the difference.
|
||||
//
|
||||
// But if [0, 0] - [8, 8] and [64, 24] - [72, 32] blocks are updated,
|
||||
// +---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
// | X | m | m | m | | | | | m | m | m | m |
|
||||
// +---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
// | m | m | m | m | | | | | m | m | m | m |
|
||||
// +---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
// | m | m | m | m | | | | | m | m | m | m |
|
||||
// +---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
// | m | m | m | m | | | | | X | m | m | m |
|
||||
// +---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
// the [8, 8] - [64, 32] is not expected to be covered in the difference. As
|
||||
// ScreenCapturerDifferWrapper should only mark [0, 0] - [32, 32] and
|
||||
// [64, 0] - [96, 32] as updated.
|
||||
DesktopRegion differ(frame.updated_region());
|
||||
differ.Subtract(region);
|
||||
for (DesktopRegion::Iterator it(differ); !it.IsAtEnd(); it.Advance()) {
|
||||
ASSERT_TRUE(it.rect().width() <= kBlockSize * 2 - 2 ||
|
||||
it.rect().height() <= kBlockSize * 2 - 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Executes a ScreenCapturerDifferWrapper::Capture() and compares its output
|
||||
// DesktopFrame::updated_region() with |updated_region| if |check_result| is
|
||||
// true. If |exactly_match| is true, AssertUpdatedRegionIs() will be used,
|
||||
// otherwise AssertUpdatedRegionCovers() will be used.
|
||||
template <template <typename, typename...> class T = std::initializer_list,
|
||||
typename... Rect>
|
||||
void ExecuteDifferWrapperCase(BlackWhiteDesktopFramePainter* frame_painter,
|
||||
ScreenCapturerDifferWrapper* capturer,
|
||||
MockScreenCapturerCallback* callback,
|
||||
const T<DesktopRect, Rect...>& updated_region,
|
||||
bool check_result,
|
||||
bool exactly_match) {
|
||||
EXPECT_CALL(*callback,
|
||||
OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS, testing::_))
|
||||
.Times(1)
|
||||
.WillOnce(testing::Invoke([&updated_region, check_result, exactly_match](
|
||||
DesktopCapturer::Result result,
|
||||
std::unique_ptr<DesktopFrame>* frame) {
|
||||
ASSERT_EQ(result, DesktopCapturer::Result::SUCCESS);
|
||||
if (check_result) {
|
||||
if (exactly_match) {
|
||||
AssertUpdatedRegionIs(**frame, updated_region);
|
||||
} else {
|
||||
AssertUpdatedRegionCovers(**frame, updated_region);
|
||||
}
|
||||
}
|
||||
}));
|
||||
for (const auto& rect : updated_region) {
|
||||
frame_painter->updated_region()->AddRect(rect);
|
||||
}
|
||||
capturer->Capture(DesktopRegion());
|
||||
}
|
||||
|
||||
// Executes a ScreenCapturerDifferWrapper::Capture(), if updated_region() is not
|
||||
// set, this function will reset ScreenCapturerDifferWrapper internal
|
||||
// DesktopFrame into white.
|
||||
void ExecuteCapturer(ScreenCapturerDifferWrapper* capturer,
|
||||
MockScreenCapturerCallback* callback) {
|
||||
EXPECT_CALL(*callback,
|
||||
OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS, testing::_))
|
||||
.Times(1);
|
||||
capturer->Capture(DesktopRegion());
|
||||
}
|
||||
|
||||
void ExecuteDifferWrapperTest(bool with_hints,
|
||||
bool enlarge_updated_region,
|
||||
bool random_updated_region,
|
||||
bool check_result) {
|
||||
const bool updated_region_should_exactly_match =
|
||||
with_hints && !enlarge_updated_region && !random_updated_region;
|
||||
BlackWhiteDesktopFramePainter frame_painter;
|
||||
PainterDesktopFrameGenerator frame_generator;
|
||||
frame_generator.set_desktop_frame_painter(&frame_painter);
|
||||
std::unique_ptr<FakeScreenCapturer> fake(new FakeScreenCapturer());
|
||||
fake->set_frame_generator(&frame_generator);
|
||||
ScreenCapturerDifferWrapper capturer(std::move(fake));
|
||||
MockScreenCapturerCallback callback;
|
||||
frame_generator.set_provide_updated_region_hints(with_hints);
|
||||
frame_generator.set_enlarge_updated_region(enlarge_updated_region);
|
||||
frame_generator.set_add_random_updated_region(random_updated_region);
|
||||
|
||||
capturer.Start(&callback);
|
||||
|
||||
EXPECT_CALL(callback,
|
||||
OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS, testing::_))
|
||||
.Times(1)
|
||||
.WillOnce(testing::Invoke([](DesktopCapturer::Result result,
|
||||
std::unique_ptr<DesktopFrame>* frame) {
|
||||
ASSERT_EQ(result, DesktopCapturer::Result::SUCCESS);
|
||||
AssertUpdatedRegionIs(**frame,
|
||||
{DesktopRect::MakeSize((*frame)->size())});
|
||||
}));
|
||||
capturer.Capture(DesktopRegion());
|
||||
|
||||
ExecuteDifferWrapperCase(&frame_painter, &capturer, &callback,
|
||||
{DesktopRect::MakeLTRB(100, 100, 200, 200),
|
||||
DesktopRect::MakeLTRB(300, 300, 400, 400)},
|
||||
check_result, updated_region_should_exactly_match);
|
||||
ExecuteCapturer(&capturer, &callback);
|
||||
|
||||
ExecuteDifferWrapperCase(
|
||||
&frame_painter, &capturer, &callback,
|
||||
{DesktopRect::MakeLTRB(0, 0, 40, 40),
|
||||
DesktopRect::MakeLTRB(0, frame_generator.size()->height() - 40, 40,
|
||||
frame_generator.size()->height()),
|
||||
DesktopRect::MakeLTRB(frame_generator.size()->width() - 40, 0,
|
||||
frame_generator.size()->width(), 40),
|
||||
DesktopRect::MakeLTRB(frame_generator.size()->width() - 40,
|
||||
frame_generator.size()->height() - 40,
|
||||
frame_generator.size()->width(),
|
||||
frame_generator.size()->height())},
|
||||
check_result, updated_region_should_exactly_match);
|
||||
|
||||
Random random(rtc::TimeMillis());
|
||||
// Fuzzing tests.
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
if (enlarge_updated_region) {
|
||||
frame_generator.set_enlarge_range(random.Rand(1, 50));
|
||||
}
|
||||
frame_generator.size()->set(random.Rand(500, 2000), random.Rand(500, 2000));
|
||||
ExecuteCapturer(&capturer, &callback);
|
||||
std::vector<DesktopRect> updated_region;
|
||||
for (int j = random.Rand(50); j >= 0; j--) {
|
||||
// At least a 1 x 1 updated region.
|
||||
const int left = random.Rand(0, frame_generator.size()->width() - 2);
|
||||
const int top = random.Rand(0, frame_generator.size()->height() - 2);
|
||||
const int right = random.Rand(left + 1, frame_generator.size()->width());
|
||||
const int bottom = random.Rand(top + 1, frame_generator.size()->height());
|
||||
updated_region.push_back(DesktopRect::MakeLTRB(left, top, right, bottom));
|
||||
}
|
||||
ExecuteDifferWrapperCase(&frame_painter, &capturer, &callback,
|
||||
updated_region, check_result,
|
||||
updated_region_should_exactly_match);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(ScreenCapturerDifferWrapperTest, CaptureWithoutHints) {
|
||||
ExecuteDifferWrapperTest(false, false, false, true);
|
||||
}
|
||||
|
||||
TEST(ScreenCapturerDifferWrapperTest, CaptureWithHints) {
|
||||
ExecuteDifferWrapperTest(true, false, false, true);
|
||||
}
|
||||
|
||||
TEST(ScreenCapturerDifferWrapperTest, CaptureWithEnlargedHints) {
|
||||
ExecuteDifferWrapperTest(true, true, false, true);
|
||||
}
|
||||
|
||||
TEST(ScreenCapturerDifferWrapperTest, CaptureWithRandomHints) {
|
||||
ExecuteDifferWrapperTest(true, false, true, true);
|
||||
}
|
||||
|
||||
TEST(ScreenCapturerDifferWrapperTest, CaptureWithEnlargedAndRandomHints) {
|
||||
ExecuteDifferWrapperTest(true, true, true, true);
|
||||
}
|
||||
|
||||
// When hints are provided, ScreenCapturerDifferWrapper has a slightly better
|
||||
// performance in current configuration, but not so significant. Following is
|
||||
// one run result.
|
||||
// [ RUN ] DISABLED_CaptureWithoutHintsPerf
|
||||
// [ OK ] DISABLED_CaptureWithoutHintsPerf (7118 ms)
|
||||
// [ RUN ] DISABLED_CaptureWithHintsPerf
|
||||
// [ OK ] DISABLED_CaptureWithHintsPerf (5580 ms)
|
||||
// [ RUN ] DISABLED_CaptureWithEnlargedHintsPerf
|
||||
// [ OK ] DISABLED_CaptureWithEnlargedHintsPerf (5974 ms)
|
||||
// [ RUN ] DISABLED_CaptureWithRandomHintsPerf
|
||||
// [ OK ] DISABLED_CaptureWithRandomHintsPerf (6184 ms)
|
||||
// [ RUN ] DISABLED_CaptureWithEnlargedAndRandomHintsPerf
|
||||
// [ OK ] DISABLED_CaptureWithEnlargedAndRandomHintsPerf (6347 ms)
|
||||
TEST(ScreenCapturerDifferWrapperTest, DISABLED_CaptureWithoutHintsPerf) {
|
||||
int64_t started = rtc::TimeMillis();
|
||||
ExecuteDifferWrapperTest(false, false, false, false);
|
||||
ASSERT_LE(rtc::TimeMillis() - started, 15000);
|
||||
}
|
||||
|
||||
TEST(ScreenCapturerDifferWrapperTest, DISABLED_CaptureWithHintsPerf) {
|
||||
int64_t started = rtc::TimeMillis();
|
||||
ExecuteDifferWrapperTest(true, false, false, false);
|
||||
ASSERT_LE(rtc::TimeMillis() - started, 15000);
|
||||
}
|
||||
|
||||
TEST(ScreenCapturerDifferWrapperTest, DISABLED_CaptureWithEnlargedHintsPerf) {
|
||||
int64_t started = rtc::TimeMillis();
|
||||
ExecuteDifferWrapperTest(true, true, false, false);
|
||||
ASSERT_LE(rtc::TimeMillis() - started, 15000);
|
||||
}
|
||||
|
||||
TEST(ScreenCapturerDifferWrapperTest, DISABLED_CaptureWithRandomHintsPerf) {
|
||||
int64_t started = rtc::TimeMillis();
|
||||
ExecuteDifferWrapperTest(true, false, true, false);
|
||||
ASSERT_LE(rtc::TimeMillis() - started, 15000);
|
||||
}
|
||||
|
||||
TEST(ScreenCapturerDifferWrapperTest,
|
||||
DISABLED_CaptureWithEnlargedAndRandomHintsPerf) {
|
||||
int64_t started = rtc::TimeMillis();
|
||||
ExecuteDifferWrapperTest(true, true, true, false);
|
||||
ASSERT_LE(rtc::TimeMillis() - started, 15000);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
@ -433,8 +433,14 @@
|
||||
'sources': [
|
||||
'desktop_capture/desktop_and_cursor_composer_unittest.cc',
|
||||
'desktop_capture/mouse_cursor_monitor_unittest.cc',
|
||||
'desktop_capture/screen_capturer_differ_wrapper_unittest.cc',
|
||||
'desktop_capture/screen_capturer_helper_unittest.cc',
|
||||
'desktop_capture/screen_capturer_mac_unittest.cc',
|
||||
'desktop_capture/fake_desktop_capturer.h',
|
||||
'desktop_capture/fake_screen_capturer.cc',
|
||||
'desktop_capture/fake_screen_capturer.h',
|
||||
'desktop_capture/desktop_frame_generator.cc',
|
||||
'desktop_capture/desktop_frame_generator.h',
|
||||
'desktop_capture/screen_capturer_mock_objects.h',
|
||||
'desktop_capture/screen_capturer_unittest.cc',
|
||||
'desktop_capture/screen_drawer.h',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user