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)
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   libyuv::CopyPlane(frame.data(), frame.stride(), result->data(),
161                     result->stride(), frame.size().width() * kBytesPerPixel,
162                     frame.size().height());
163   result->CopyFrameInfoFrom(frame);
164   return result;
165 }
166 
167 // static
Create(DesktopSize size,SharedMemoryFactory * shared_memory_factory)168 std::unique_ptr<DesktopFrame> SharedMemoryDesktopFrame::Create(
169     DesktopSize size,
170     SharedMemoryFactory* shared_memory_factory) {
171   RTC_DCHECK(shared_memory_factory);
172 
173   size_t buffer_size = size.height() * size.width() * kBytesPerPixel;
174   std::unique_ptr<SharedMemory> shared_memory =
175       shared_memory_factory->CreateSharedMemory(buffer_size);
176   if (!shared_memory)
177     return nullptr;
178 
179   return std::make_unique<SharedMemoryDesktopFrame>(
180       size, size.width() * kBytesPerPixel, std::move(shared_memory));
181 }
182 
SharedMemoryDesktopFrame(DesktopSize size,int stride,SharedMemory * shared_memory)183 SharedMemoryDesktopFrame::SharedMemoryDesktopFrame(DesktopSize size,
184                                                    int stride,
185                                                    SharedMemory* shared_memory)
186     : DesktopFrame(size,
187                    stride,
188                    reinterpret_cast<uint8_t*>(shared_memory->data()),
189                    shared_memory) {}
190 
SharedMemoryDesktopFrame(DesktopSize size,int stride,std::unique_ptr<SharedMemory> shared_memory)191 SharedMemoryDesktopFrame::SharedMemoryDesktopFrame(
192     DesktopSize size,
193     int stride,
194     std::unique_ptr<SharedMemory> shared_memory)
195     : SharedMemoryDesktopFrame(size, stride, shared_memory.release()) {}
196 
~SharedMemoryDesktopFrame()197 SharedMemoryDesktopFrame::~SharedMemoryDesktopFrame() {
198   delete shared_memory_;
199 }
200 
201 }  // namespace webrtc
202