diff --git a/webrtc/modules/BUILD.gn b/webrtc/modules/BUILD.gn index d4e4244df4..cf3e469727 100644 --- a/webrtc/modules/BUILD.gn +++ b/webrtc/modules/BUILD.gn @@ -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", diff --git a/webrtc/modules/desktop_capture/BUILD.gn b/webrtc/modules/desktop_capture/BUILD.gn index 7c2ab6cdc7..8887ba99c3 100644 --- a/webrtc/modules/desktop_capture/BUILD.gn +++ b/webrtc/modules/desktop_capture/BUILD.gn @@ -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) { diff --git a/webrtc/modules/desktop_capture/desktop_capture.gypi b/webrtc/modules/desktop_capture/desktop_capture.gypi index 872e705b52..521ef2794c 100644 --- a/webrtc/modules/desktop_capture/desktop_capture.gypi +++ b/webrtc/modules/desktop_capture/desktop_capture.gypi @@ -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', { diff --git a/webrtc/modules/desktop_capture/desktop_frame_generator.cc b/webrtc/modules/desktop_capture/desktop_frame_generator.cc new file mode 100644 index 0000000000..ae5c9492cb --- /dev/null +++ b/webrtc/modules/desktop_capture/desktop_frame_generator.cc @@ -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 +#include + +#include + +#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(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 PainterDesktopFrameGenerator::GetNextFrame( + SharedMemoryFactory* factory) { + if (!return_frame_) { + return nullptr; + } + + std::unique_ptr frame = std::unique_ptr( + 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 diff --git a/webrtc/modules/desktop_capture/desktop_frame_generator.h b/webrtc/modules/desktop_capture/desktop_frame_generator.h new file mode 100644 index 0000000000..2b767dcb4d --- /dev/null +++ b/webrtc/modules/desktop_capture/desktop_frame_generator.h @@ -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 + +#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 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 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_ diff --git a/webrtc/modules/desktop_capture/desktop_geometry.cc b/webrtc/modules/desktop_capture/desktop_geometry.cc index 1ff7c683c7..2af8cf826e 100644 --- a/webrtc/modules/desktop_capture/desktop_geometry.cc +++ b/webrtc/modules/desktop_capture/desktop_geometry.cc @@ -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 diff --git a/webrtc/modules/desktop_capture/desktop_geometry.h b/webrtc/modules/desktop_capture/desktop_geometry.h index 047eeec3d9..8e9b9183a8 100644 --- a/webrtc/modules/desktop_capture/desktop_geometry.h +++ b/webrtc/modules/desktop_capture/desktop_geometry.h @@ -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) { diff --git a/webrtc/modules/desktop_capture/differ_block.cc b/webrtc/modules/desktop_capture/differ_block.cc index d4cbda3601..cf2299f815 100644 --- a/webrtc/modules/desktop_capture/differ_block.cc +++ b/webrtc/modules/desktop_capture/differ_block.cc @@ -13,49 +13,59 @@ #include #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 diff --git a/webrtc/modules/desktop_capture/differ_block.h b/webrtc/modules/desktop_capture/differ_block.h index e1d487d68b..97fe3bc544 100644 --- a/webrtc/modules/desktop_capture/differ_block.h +++ b/webrtc/modules/desktop_capture/differ_block.h @@ -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, diff --git a/webrtc/modules/desktop_capture/differ_block_sse2.cc b/webrtc/modules/desktop_capture/differ_block_sse2.cc deleted file mode 100644 index 8d35df2226..0000000000 --- a/webrtc/modules/desktop_capture/differ_block_sse2.cc +++ /dev/null @@ -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 -#else -#include -#include -#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(image1); - const __m128i* i2 = reinterpret_cast(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(image1); - const __m128i* i2 = reinterpret_cast(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 diff --git a/webrtc/modules/desktop_capture/differ_block_sse2.h b/webrtc/modules/desktop_capture/differ_block_sse2.h deleted file mode 100644 index 90426dafab..0000000000 --- a/webrtc/modules/desktop_capture/differ_block_sse2.h +++ /dev/null @@ -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 - -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_ diff --git a/webrtc/modules/desktop_capture/differ_vector_sse2.cc b/webrtc/modules/desktop_capture/differ_vector_sse2.cc new file mode 100644 index 0000000000..ce6cc297c6 --- /dev/null +++ b/webrtc/modules/desktop_capture/differ_vector_sse2.cc @@ -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 +#else +#include +#include +#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(image1); + const __m128i* i2 = reinterpret_cast(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(image1); + const __m128i* i2 = reinterpret_cast(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 diff --git a/webrtc/modules/desktop_capture/differ_vector_sse2.h b/webrtc/modules/desktop_capture/differ_vector_sse2.h new file mode 100644 index 0000000000..353c6b9b00 --- /dev/null +++ b/webrtc/modules/desktop_capture/differ_vector_sse2.h @@ -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 + +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_ diff --git a/webrtc/modules/desktop_capture/fake_desktop_capturer.h b/webrtc/modules/desktop_capture/fake_desktop_capturer.h new file mode 100644 index 0000000000..db53809ec5 --- /dev/null +++ b/webrtc/modules/desktop_capture/fake_desktop_capturer.h @@ -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 +#include + +#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 +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 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 shared_memory_factory) override { + shared_memory_factory_ = std::move(shared_memory_factory); + } + + private: + DesktopCapturer::Callback* callback_; + std::unique_ptr shared_memory_factory_; + DesktopCapturer::Result result_; + DesktopFrameGenerator* generator_; +}; + +} // namespace webrtc + +#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_FAKE_DESKTOP_CAPTURER_H_ diff --git a/webrtc/modules/desktop_capture/fake_screen_capturer.cc b/webrtc/modules/desktop_capture/fake_screen_capturer.cc new file mode 100644 index 0000000000..192992fcff --- /dev/null +++ b/webrtc/modules/desktop_capture/fake_screen_capturer.cc @@ -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 + +#include + +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 diff --git a/webrtc/modules/desktop_capture/fake_screen_capturer.h b/webrtc/modules/desktop_capture/fake_screen_capturer.h new file mode 100644 index 0000000000..3b7c6fc25f --- /dev/null +++ b/webrtc/modules/desktop_capture/fake_screen_capturer.h @@ -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 { + 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_ diff --git a/webrtc/modules/desktop_capture/screen_capturer_differ_wrapper.cc b/webrtc/modules/desktop_capture/screen_capturer_differ_wrapper.cc new file mode 100644 index 0000000000..dc76b67353 --- /dev/null +++ b/webrtc/modules/desktop_capture/screen_capturer_differ_wrapper.cc @@ -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 +#include + +#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 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 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 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 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 diff --git a/webrtc/modules/desktop_capture/screen_capturer_differ_wrapper.h b/webrtc/modules/desktop_capture/screen_capturer_differ_wrapper.h new file mode 100644 index 0000000000..c7a20b3d07 --- /dev/null +++ b/webrtc/modules/desktop_capture/screen_capturer_differ_wrapper.h @@ -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 + +#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 base_capturer); + ~ScreenCapturerDifferWrapper() override; + + // ScreenCapturer interface. + void Start(DesktopCapturer::Callback* callback) override; + void SetSharedMemoryFactory( + std::unique_ptr 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 frame) override; + + const std::unique_ptr base_capturer_; + DesktopCapturer::Callback* callback_; + std::unique_ptr last_frame_; +}; + +} // namespace webrtc + +#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_SCREEN_CAPTURER_DIFFER_WRAPPER_H_ diff --git a/webrtc/modules/desktop_capture/screen_capturer_differ_wrapper_unittest.cc b/webrtc/modules/desktop_capture/screen_capturer_differ_wrapper_unittest.cc new file mode 100644 index 0000000000..e667553b14 --- /dev/null +++ b/webrtc/modules/desktop_capture/screen_capturer_differ_wrapper_unittest.cc @@ -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 +#include +#include +#include + +#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