desktop_frame_generator.cc (6693B)
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 "modules/desktop_capture/desktop_frame_generator.h" 12 13 #include <cstdint> 14 #include <cstring> 15 #include <memory> 16 17 #include "modules/desktop_capture/desktop_frame.h" 18 #include "modules/desktop_capture/desktop_geometry.h" 19 #include "modules/desktop_capture/desktop_region.h" 20 #include "modules/desktop_capture/rgba_color.h" 21 #include "modules/desktop_capture/shared_memory.h" 22 #include "rtc_base/checks.h" 23 #include "rtc_base/random.h" 24 #include "rtc_base/time_utils.h" 25 26 namespace webrtc { 27 28 namespace { 29 30 // Sets `updated_region` to `frame`. If `enlarge_updated_region` is 31 // true, this function will randomly enlarge each DesktopRect in 32 // `updated_region`. But the enlarged DesktopRegion won't excceed the 33 // frame->size(). If `add_random_updated_region` is true, several random 34 // rectangles will also be included in `frame`. 35 void SetUpdatedRegion(DesktopFrame* frame, 36 const DesktopRegion& updated_region, 37 bool enlarge_updated_region, 38 int enlarge_range, 39 bool add_random_updated_region) { 40 const DesktopRect screen_rect = DesktopRect::MakeSize(frame->size()); 41 Random random(TimeMicros()); 42 frame->mutable_updated_region()->Clear(); 43 for (DesktopRegion::Iterator it(updated_region); !it.IsAtEnd(); 44 it.Advance()) { 45 DesktopRect rect = it.rect(); 46 if (enlarge_updated_region && enlarge_range > 0) { 47 rect.Extend(random.Rand(enlarge_range), random.Rand(enlarge_range), 48 random.Rand(enlarge_range), random.Rand(enlarge_range)); 49 rect.IntersectWith(screen_rect); 50 } 51 frame->mutable_updated_region()->AddRect(rect); 52 } 53 54 if (add_random_updated_region) { 55 for (int i = random.Rand(10); i >= 0; i--) { 56 // At least a 1 x 1 updated region. 57 const int left = random.Rand(0, frame->size().width() - 2); 58 const int top = random.Rand(0, frame->size().height() - 2); 59 const int right = random.Rand(left + 1, frame->size().width()); 60 const int bottom = random.Rand(top + 1, frame->size().height()); 61 frame->mutable_updated_region()->AddRect( 62 DesktopRect::MakeLTRB(left, top, right, bottom)); 63 } 64 } 65 } 66 67 // Paints pixels in `rect` of `frame` to `color`. 68 void PaintRect(DesktopFrame* frame, DesktopRect rect, RgbaColor rgba_color) { 69 static_assert(DesktopFrame::kBytesPerPixel == sizeof(uint32_t), 70 "kBytesPerPixel should be 4."); 71 RTC_DCHECK_GE(frame->size().width(), rect.right()); 72 RTC_DCHECK_GE(frame->size().height(), rect.bottom()); 73 // TODO(bugs.webrtc.org/436974448): Support other pixel formats. 74 RTC_CHECK_EQ(FOURCC_ARGB, frame->pixel_format()); 75 uint32_t color = rgba_color.ToUInt32(); 76 uint8_t* row = frame->GetFrameDataAtPos(rect.top_left()); 77 for (int i = 0; i < rect.height(); i++) { 78 uint32_t* column = reinterpret_cast<uint32_t*>(row); 79 for (int j = 0; j < rect.width(); j++) { 80 column[j] = color; 81 } 82 row += frame->stride(); 83 } 84 } 85 86 // Paints pixels in `region` of `frame` to `color`. 87 void PaintRegion(DesktopFrame* frame, 88 DesktopRegion* region, 89 RgbaColor rgba_color) { 90 region->IntersectWith(DesktopRect::MakeSize(frame->size())); 91 for (DesktopRegion::Iterator it(*region); !it.IsAtEnd(); it.Advance()) { 92 PaintRect(frame, it.rect(), rgba_color); 93 } 94 } 95 96 } // namespace 97 98 DesktopFrameGenerator::DesktopFrameGenerator() {} 99 DesktopFrameGenerator::~DesktopFrameGenerator() {} 100 101 DesktopFramePainter::DesktopFramePainter() {} 102 DesktopFramePainter::~DesktopFramePainter() {} 103 104 PainterDesktopFrameGenerator::PainterDesktopFrameGenerator() 105 : size_(1024, 768), 106 return_frame_(true), 107 provide_updated_region_hints_(false), 108 enlarge_updated_region_(false), 109 enlarge_range_(20), 110 add_random_updated_region_(false), 111 painter_(nullptr) {} 112 PainterDesktopFrameGenerator::~PainterDesktopFrameGenerator() {} 113 114 std::unique_ptr<DesktopFrame> PainterDesktopFrameGenerator::GetNextFrame( 115 SharedMemoryFactory* factory) { 116 if (!return_frame_) { 117 return nullptr; 118 } 119 120 std::unique_ptr<DesktopFrame> frame = std::unique_ptr<DesktopFrame>( 121 factory ? SharedMemoryDesktopFrame::Create(size_, FOURCC_ARGB, factory) 122 .release() 123 : new BasicDesktopFrame(size_, FOURCC_ARGB)); 124 if (painter_) { 125 DesktopRegion updated_region; 126 if (!painter_->Paint(frame.get(), &updated_region)) { 127 return nullptr; 128 } 129 130 if (provide_updated_region_hints_) { 131 SetUpdatedRegion(frame.get(), updated_region, enlarge_updated_region_, 132 enlarge_range_, add_random_updated_region_); 133 } else { 134 frame->mutable_updated_region()->SetRect( 135 DesktopRect::MakeSize(frame->size())); 136 } 137 } 138 139 return frame; 140 } 141 142 DesktopSize* PainterDesktopFrameGenerator::size() { 143 return &size_; 144 } 145 146 void PainterDesktopFrameGenerator::set_return_frame(bool return_frame) { 147 return_frame_ = return_frame; 148 } 149 150 void PainterDesktopFrameGenerator::set_provide_updated_region_hints( 151 bool provide_updated_region_hints) { 152 provide_updated_region_hints_ = provide_updated_region_hints; 153 } 154 155 void PainterDesktopFrameGenerator::set_enlarge_updated_region( 156 bool enlarge_updated_region) { 157 enlarge_updated_region_ = enlarge_updated_region; 158 } 159 160 void PainterDesktopFrameGenerator::set_enlarge_range(int enlarge_range) { 161 enlarge_range_ = enlarge_range; 162 } 163 164 void PainterDesktopFrameGenerator::set_add_random_updated_region( 165 bool add_random_updated_region) { 166 add_random_updated_region_ = add_random_updated_region; 167 } 168 169 void PainterDesktopFrameGenerator::set_desktop_frame_painter( 170 DesktopFramePainter* painter) { 171 painter_ = painter; 172 } 173 174 BlackWhiteDesktopFramePainter::BlackWhiteDesktopFramePainter() {} 175 BlackWhiteDesktopFramePainter::~BlackWhiteDesktopFramePainter() {} 176 177 DesktopRegion* BlackWhiteDesktopFramePainter::updated_region() { 178 return &updated_region_; 179 } 180 181 bool BlackWhiteDesktopFramePainter::Paint(DesktopFrame* frame, 182 DesktopRegion* updated_region) { 183 RTC_DCHECK(updated_region->is_empty()); 184 memset(frame->data(), 0, frame->stride() * frame->size().height()); 185 PaintRegion(frame, &updated_region_, RgbaColor(0xFFFFFFFF)); 186 updated_region_.Swap(updated_region); 187 return true; 188 } 189 190 } // namespace webrtc