OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. |
| 3 * |
| 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ |
| 10 |
| 11 #include "webrtc/modules/desktop_capture/screen_capturer_mock_objects.h" |
| 12 |
| 13 #include <stdint.h> |
| 14 #include <string.h> |
| 15 |
| 16 #include <utility> |
| 17 |
| 18 #include "webrtc/base/random.h" |
| 19 #include "webrtc/base/timeutils.h" |
| 20 #include "webrtc/modules/desktop_capture/shared_desktop_frame.h" |
| 21 |
| 22 namespace webrtc { |
| 23 |
| 24 namespace { |
| 25 |
| 26 // Creates a DesktopFrame according to the input |factory|, and paints it to |
| 27 // white. |
| 28 std::unique_ptr<DesktopFrame> CreateDesktopFrame(DesktopSize size, |
| 29 SharedMemoryFactory* factory) { |
| 30 std::unique_ptr<DesktopFrame> frame( |
| 31 factory ? SharedMemoryDesktopFrame::Create(size, factory).release() |
| 32 : new BasicDesktopFrame(size)); |
| 33 memset(frame->data(), 0, frame->stride() * frame->size().height()); |
| 34 return SharedDesktopFrame::Wrap(std::move(frame)); |
| 35 } |
| 36 |
| 37 // Paints pixels in |rect| of |frame| to |color|. |
| 38 void PaintRect(DesktopFrame* frame, DesktopRect rect, uint32_t color) { |
| 39 static_assert(DesktopFrame::kBytesPerPixel == sizeof(uint32_t), |
| 40 "kBytesPerPixel should be 4."); |
| 41 ASSERT_TRUE(frame->size().width() >= rect.width() && |
| 42 frame->size().height() >= rect.height()); |
| 43 int row = rect.top() * frame->stride(); |
| 44 for (int i = 0; i < rect.height(); i++) { |
| 45 int column = rect.left() * DesktopFrame::kBytesPerPixel; |
| 46 for (int j = 0; j < rect.width(); j++) { |
| 47 memcpy(&frame->data()[row + column], &color, sizeof(color)); |
| 48 column += DesktopFrame::kBytesPerPixel; |
| 49 } |
| 50 row += frame->stride(); |
| 51 } |
| 52 } |
| 53 |
| 54 // Paints pixels in |region| of |frame| to |color|. |
| 55 void PaintRegion(DesktopFrame* frame, |
| 56 const DesktopRegion& region, |
| 57 uint32_t color) { |
| 58 for (DesktopRegion::Iterator it(region); !it.IsAtEnd(); it.Advance()) { |
| 59 PaintRect(frame, it.rect(), color); |
| 60 } |
| 61 } |
| 62 |
| 63 // Sets dirty region of |frame| to |dirty_region|. If |enlarge_dirty_region| is |
| 64 // true, this function will randomly enlarge each DesktopRect in |dirty_region|. |
| 65 // But the enlarged DesktopRegion won't excceed the frame->size(). |
| 66 void SetDirtyRegion(DesktopFrame* frame, |
| 67 const DesktopRegion& dirty_region, |
| 68 bool enlarge_dirty_region, |
| 69 int enlarge_range, |
| 70 bool random_dirty_region) { |
| 71 RTC_DCHECK(enlarge_range > 0); |
| 72 const DesktopRect screen_rect = DesktopRect::MakeSize(frame->size()); |
| 73 Random random(rtc::TimeMicros()); |
| 74 frame->mutable_updated_region()->Clear(); |
| 75 for (DesktopRegion::Iterator it(dirty_region); !it.IsAtEnd(); it.Advance()) { |
| 76 DesktopRect rect = it.rect(); |
| 77 if (enlarge_dirty_region) { |
| 78 rect = DesktopRect::MakeLTRB(rect.left() - random.Rand(enlarge_range), |
| 79 rect.top() - random.Rand(enlarge_range), |
| 80 rect.right() + random.Rand(enlarge_range), |
| 81 rect.bottom() + random.Rand(enlarge_range)); |
| 82 rect.IntersectWith(screen_rect); |
| 83 } |
| 84 frame->mutable_updated_region()->AddRect(rect); |
| 85 } |
| 86 |
| 87 if (random_dirty_region) { |
| 88 for (int i = random.Rand(10); i >= 0; i--) { |
| 89 // At least a 1 x 1 dirty region. |
| 90 const int left = random.Rand(0, frame->size().width() - 2); |
| 91 const int top = random.Rand(0, frame->size().height() - 2); |
| 92 const int right = random.Rand(left + 1, frame->size().width()); |
| 93 const int bottom = random.Rand(top + 1, frame->size().height()); |
| 94 frame->mutable_updated_region()->AddRect( |
| 95 DesktopRect::MakeLTRB(left, top, right, bottom)); |
| 96 } |
| 97 } |
| 98 } |
| 99 |
| 100 } // namespace |
| 101 |
| 102 MockScreenCapturer::MockScreenCapturer() |
| 103 : callback_(nullptr), |
| 104 size_(1024, 768), |
| 105 result_(Result::SUCCESS), |
| 106 return_frame_(true), |
| 107 provide_dirty_region_hints_(false), |
| 108 enlarge_dirty_region_(false), |
| 109 enlarge_range_(20) { |
| 110 ON_CALL(*this, Start(testing::_)) |
| 111 .WillByDefault(testing::Invoke( |
| 112 [this](Callback* callback) { callback_ = callback; })); |
| 113 |
| 114 ON_CALL(*this, Capture(testing::_)) |
| 115 .WillByDefault(testing::Invoke([this](const DesktopRegion& region) { |
| 116 // A typical ScreenCapturer won't use the |region| parameter. |
| 117 ASSERT_TRUE(callback_); |
| 118 if (return_frame_) { |
| 119 std::unique_ptr<DesktopFrame> frame = |
| 120 CreateDesktopFrame(size_, shared_memory_factory_.get()); |
| 121 PaintRegion(frame.get(), dirty_region_, UINT32_MAX); |
| 122 if (provide_dirty_region_hints_) { |
| 123 SetDirtyRegion(frame.get(), dirty_region_, enlarge_dirty_region_, |
| 124 enlarge_range_, random_dirty_region_); |
| 125 } |
| 126 dirty_region_.Clear(); |
| 127 callback_->OnCaptureResult(result_, std::move(frame)); |
| 128 } else { |
| 129 callback_->OnCaptureResult(result_, std::unique_ptr<DesktopFrame>()); |
| 130 } |
| 131 })); |
| 132 |
| 133 ON_CALL(*this, GetScreenList(testing::_)) |
| 134 .WillByDefault(testing::Return(true)); |
| 135 |
| 136 ON_CALL(*this, SelectScreen(testing::_)) |
| 137 .WillByDefault(testing::Invoke( |
| 138 [](ScreenId id) { return id == kFullDesktopScreenId; })); |
| 139 } |
| 140 |
| 141 MockScreenCapturer::~MockScreenCapturer() = default; |
| 142 |
| 143 void MockScreenCapturer::SetSharedMemoryFactory( |
| 144 std::unique_ptr<SharedMemoryFactory> shared_memory_factory) { |
| 145 shared_memory_factory_ = std::move(shared_memory_factory); |
| 146 } |
| 147 |
| 148 } // namespace webrtc |
OLD | NEW |