1 /*
2 * Copyright (c) 2013 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.h"
12
13 #include <string.h>
14
15 #include <cmath>
16 #include <memory>
17 #include <utility>
18
19 #include "modules/desktop_capture/desktop_capture_types.h"
20 #include "modules/desktop_capture/desktop_geometry.h"
21 #include "rtc_base/checks.h"
22
23 namespace webrtc {
24
DesktopFrame(DesktopSize size,int stride,uint8_t * data,SharedMemory * shared_memory)25 DesktopFrame::DesktopFrame(DesktopSize size,
26 int stride,
27 uint8_t* data,
28 SharedMemory* shared_memory)
29 : data_(data),
30 shared_memory_(shared_memory),
31 size_(size),
32 stride_(stride),
33 capture_time_ms_(0),
34 capturer_id_(DesktopCapturerId::kUnknown) {
35 RTC_DCHECK(size_.width() >= 0);
36 RTC_DCHECK(size_.height() >= 0);
37 }
38
39 DesktopFrame::~DesktopFrame() = default;
40
CopyPixelsFrom(const uint8_t * src_buffer,int src_stride,const DesktopRect & dest_rect)41 void DesktopFrame::CopyPixelsFrom(const uint8_t* src_buffer,
42 int src_stride,
43 const DesktopRect& dest_rect) {
44 RTC_CHECK(DesktopRect::MakeSize(size()).ContainsRect(dest_rect));
45
46 uint8_t* dest = GetFrameDataAtPos(dest_rect.top_left());
47 for (int y = 0; y < dest_rect.height(); ++y) {
48 memcpy(dest, src_buffer, DesktopFrame::kBytesPerPixel * dest_rect.width());
49 src_buffer += src_stride;
50 dest += stride();
51 }
52 }
53
CopyPixelsFrom(const DesktopFrame & src_frame,const DesktopVector & src_pos,const DesktopRect & dest_rect)54 void DesktopFrame::CopyPixelsFrom(const DesktopFrame& src_frame,
55 const DesktopVector& src_pos,
56 const DesktopRect& dest_rect) {
57 RTC_CHECK(DesktopRect::MakeSize(src_frame.size())
58 .ContainsRect(
59 DesktopRect::MakeOriginSize(src_pos, dest_rect.size())));
60
61 CopyPixelsFrom(src_frame.GetFrameDataAtPos(src_pos), src_frame.stride(),
62 dest_rect);
63 }
64
CopyIntersectingPixelsFrom(const DesktopFrame & src_frame,double horizontal_scale,double vertical_scale)65 bool DesktopFrame::CopyIntersectingPixelsFrom(const DesktopFrame& src_frame,
66 double horizontal_scale,
67 double vertical_scale) {
68 const DesktopVector& origin = top_left();
69 const DesktopVector& src_frame_origin = src_frame.top_left();
70
71 DesktopVector src_frame_offset = src_frame_origin.subtract(origin);
72
73 // Determine the intersection, first adjusting its origin to account for any
74 // DPI scaling.
75 DesktopRect intersection_rect = src_frame.rect();
76 if (horizontal_scale != 1.0 || vertical_scale != 1.0) {
77 DesktopVector origin_adjustment(
78 static_cast<int>(
79 std::round((horizontal_scale - 1.0) * src_frame_offset.x())),
80 static_cast<int>(
81 std::round((vertical_scale - 1.0) * src_frame_offset.y())));
82
83 intersection_rect.Translate(origin_adjustment);
84
85 src_frame_offset = src_frame_offset.add(origin_adjustment);
86 }
87
88 intersection_rect.IntersectWith(rect());
89 if (intersection_rect.is_empty()) {
90 return false;
91 }
92
93 // Translate the intersection rect to be relative to the outer rect.
94 intersection_rect.Translate(-origin.x(), -origin.y());
95
96 // Determine source position for the copy (offsets of outer frame from
97 // source origin, if positive).
98 int32_t src_pos_x = std::max(0, -src_frame_offset.x());
99 int32_t src_pos_y = std::max(0, -src_frame_offset.y());
100
101 CopyPixelsFrom(src_frame, DesktopVector(src_pos_x, src_pos_y),
102 intersection_rect);
103 return true;
104 }
105
rect() const106 DesktopRect DesktopFrame::rect() const {
107 const float scale = scale_factor();
108 // Only scale the size.
109 return DesktopRect::MakeXYWH(top_left().x(), top_left().y(),
110 size().width() / scale, size().height() / scale);
111 }
112
scale_factor() const113 float DesktopFrame::scale_factor() const {
114 float scale = 1.0f;
115
116 #if defined(WEBRTC_MAC)
117 // At least on Windows the logical and physical pixel are the same
118 // See http://crbug.com/948362.
119 if (!dpi().is_zero() && dpi().x() == dpi().y())
120 scale = dpi().x() / kStandardDPI;
121 #endif
122
123 return scale;
124 }
125
GetFrameDataAtPos(const DesktopVector & pos) const126 uint8_t* DesktopFrame::GetFrameDataAtPos(const DesktopVector& pos) const {
127 return data() + stride() * pos.y() + DesktopFrame::kBytesPerPixel * pos.x();
128 }
129
CopyFrameInfoFrom(const DesktopFrame & other)130 void DesktopFrame::CopyFrameInfoFrom(const DesktopFrame& other) {
131 set_dpi(other.dpi());
132 set_capture_time_ms(other.capture_time_ms());
133 set_capturer_id(other.capturer_id());
134 *mutable_updated_region() = other.updated_region();
135 set_top_left(other.top_left());
136 set_icc_profile(other.icc_profile());
137 }
138
MoveFrameInfoFrom(DesktopFrame * other)139 void DesktopFrame::MoveFrameInfoFrom(DesktopFrame* other) {
140 set_dpi(other->dpi());
141 set_capture_time_ms(other->capture_time_ms());
142 set_capturer_id(other->capturer_id());
143 mutable_updated_region()->Swap(other->mutable_updated_region());
144 set_top_left(other->top_left());
145 set_icc_profile(other->icc_profile());
146 }
147
BasicDesktopFrame(DesktopSize size)148 BasicDesktopFrame::BasicDesktopFrame(DesktopSize size)
149 : DesktopFrame(size,
150 kBytesPerPixel * size.width(),
151 new uint8_t[kBytesPerPixel * size.width() * size.height()](),
152 nullptr) {}
153
~BasicDesktopFrame()154 BasicDesktopFrame::~BasicDesktopFrame() {
155 delete[] data_;
156 }
157
158 // static
CopyOf(const DesktopFrame & frame)159 DesktopFrame* BasicDesktopFrame::CopyOf(const DesktopFrame& frame) {
160 DesktopFrame* result = new BasicDesktopFrame(frame.size());
161 for (int y = 0; y < frame.size().height(); ++y) {
162 memcpy(result->data() + y * result->stride(),
163 frame.data() + y * frame.stride(),
164 frame.size().width() * kBytesPerPixel);
165 }
166 result->CopyFrameInfoFrom(frame);
167 return result;
168 }
169
170 // static
Create(DesktopSize size,SharedMemoryFactory * shared_memory_factory)171 std::unique_ptr<DesktopFrame> SharedMemoryDesktopFrame::Create(
172 DesktopSize size,
173 SharedMemoryFactory* shared_memory_factory) {
174 RTC_DCHECK(shared_memory_factory);
175
176 size_t buffer_size = size.height() * size.width() * kBytesPerPixel;
177 std::unique_ptr<SharedMemory> shared_memory =
178 shared_memory_factory->CreateSharedMemory(buffer_size);
179 if (!shared_memory)
180 return nullptr;
181
182 return std::make_unique<SharedMemoryDesktopFrame>(
183 size, size.width() * kBytesPerPixel, std::move(shared_memory));
184 }
185
SharedMemoryDesktopFrame(DesktopSize size,int stride,SharedMemory * shared_memory)186 SharedMemoryDesktopFrame::SharedMemoryDesktopFrame(DesktopSize size,
187 int stride,
188 SharedMemory* shared_memory)
189 : DesktopFrame(size,
190 stride,
191 reinterpret_cast<uint8_t*>(shared_memory->data()),
192 shared_memory) {}
193
SharedMemoryDesktopFrame(DesktopSize size,int stride,std::unique_ptr<SharedMemory> shared_memory)194 SharedMemoryDesktopFrame::SharedMemoryDesktopFrame(
195 DesktopSize size,
196 int stride,
197 std::unique_ptr<SharedMemory> shared_memory)
198 : SharedMemoryDesktopFrame(size, stride, shared_memory.release()) {}
199
~SharedMemoryDesktopFrame()200 SharedMemoryDesktopFrame::~SharedMemoryDesktopFrame() {
201 delete shared_memory_;
202 }
203
204 } // namespace webrtc
205