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