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