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