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