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