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