desktop_frame.cc (9143B)
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 <algorithm> 14 #include <cmath> 15 #include <cstdint> 16 #include <cstring> 17 #include <memory> 18 #include <utility> 19 20 #include "modules/desktop_capture/desktop_capture_types.h" 21 #include "modules/desktop_capture/desktop_geometry.h" 22 #include "modules/desktop_capture/shared_memory.h" 23 #include "rtc_base/checks.h" 24 #include "third_party/libyuv/include/libyuv/planar_functions.h" 25 26 namespace webrtc { 27 28 DesktopFrame::DesktopFrame(DesktopSize size, 29 int stride, 30 FourCC pixel_format, 31 uint8_t* data, 32 SharedMemory* shared_memory) 33 : data_(data), 34 shared_memory_(shared_memory), 35 size_(size), 36 stride_(stride), 37 pixel_format_(pixel_format), 38 capture_time_ms_(0), 39 capturer_id_(DesktopCapturerId::kUnknown) { 40 RTC_DCHECK(size_.width() >= 0); 41 RTC_DCHECK(size_.height() >= 0); 42 } 43 44 DesktopFrame::DesktopFrame(DesktopSize size, 45 int stride, 46 uint8_t* data, 47 SharedMemory* shared_memory) 48 : DesktopFrame(size, stride, FOURCC_ARGB, data, shared_memory) {} 49 50 DesktopFrame::~DesktopFrame() = default; 51 52 void DesktopFrame::CopyPixelsFrom(const uint8_t* src_buffer, 53 int src_stride, 54 const DesktopRect& dest_rect) { 55 RTC_CHECK(DesktopRect::MakeSize(size()).ContainsRect(dest_rect)); 56 57 uint8_t* dest = GetFrameDataAtPos(dest_rect.top_left()); 58 libyuv::CopyPlane(src_buffer, src_stride, dest, stride(), 59 DesktopFrame::kBytesPerPixel * dest_rect.width(), 60 dest_rect.height()); 61 } 62 63 void DesktopFrame::CopyPixelsFrom(const DesktopFrame& src_frame, 64 const DesktopVector& src_pos, 65 const DesktopRect& dest_rect) { 66 RTC_CHECK(DesktopRect::MakeSize(src_frame.size()) 67 .ContainsRect( 68 DesktopRect::MakeOriginSize(src_pos, dest_rect.size()))); 69 RTC_CHECK_EQ(pixel_format(), src_frame.pixel_format()); 70 71 CopyPixelsFrom(src_frame.GetFrameDataAtPos(src_pos), src_frame.stride(), 72 dest_rect); 73 } 74 75 bool DesktopFrame::CopyIntersectingPixelsFrom(const DesktopFrame& src_frame, 76 double horizontal_scale, 77 double vertical_scale) { 78 const DesktopVector& origin = top_left(); 79 const DesktopVector& src_frame_origin = src_frame.top_left(); 80 81 DesktopVector src_frame_offset = src_frame_origin.subtract(origin); 82 83 // Determine the intersection, first adjusting its origin to account for any 84 // DPI scaling. 85 DesktopRect intersection_rect = src_frame.rect(); 86 if (horizontal_scale != 1.0 || vertical_scale != 1.0) { 87 DesktopVector origin_adjustment( 88 static_cast<int>( 89 std::round((horizontal_scale - 1.0) * src_frame_offset.x())), 90 static_cast<int>( 91 std::round((vertical_scale - 1.0) * src_frame_offset.y()))); 92 93 intersection_rect.Translate(origin_adjustment); 94 95 src_frame_offset = src_frame_offset.add(origin_adjustment); 96 } 97 98 intersection_rect.IntersectWith(rect()); 99 if (intersection_rect.is_empty()) { 100 return false; 101 } 102 103 // Translate the intersection rect to be relative to the outer rect. 104 intersection_rect.Translate(-origin.x(), -origin.y()); 105 106 // Determine source position for the copy (offsets of outer frame from 107 // source origin, if positive). 108 int32_t src_pos_x = std::max(0, -src_frame_offset.x()); 109 int32_t src_pos_y = std::max(0, -src_frame_offset.y()); 110 111 CopyPixelsFrom(src_frame, DesktopVector(src_pos_x, src_pos_y), 112 intersection_rect); 113 return true; 114 } 115 116 DesktopRect DesktopFrame::rect() const { 117 const float scale = scale_factor(); 118 // Only scale the size. 119 return DesktopRect::MakeXYWH(top_left().x(), top_left().y(), 120 size().width() / scale, size().height() / scale); 121 } 122 123 float DesktopFrame::scale_factor() const { 124 float scale = 1.0f; 125 126 #if defined(WEBRTC_MAC) || defined(CHROMEOS) 127 // At least on Windows the logical and physical pixel are the same 128 // See http://crbug.com/948362. 129 if (!dpi().is_zero() && dpi().x() == dpi().y()) 130 scale = dpi().x() / kStandardDPI; 131 #endif 132 133 return scale; 134 } 135 136 uint8_t* DesktopFrame::GetFrameDataAtPos(const DesktopVector& pos) const { 137 return data() + stride() * pos.y() + DesktopFrame::kBytesPerPixel * pos.x(); 138 } 139 140 void DesktopFrame::CopyFrameInfoFrom(const DesktopFrame& other) { 141 set_dpi(other.dpi()); 142 set_capture_time_ms(other.capture_time_ms()); 143 set_capturer_id(other.capturer_id()); 144 *mutable_updated_region() = other.updated_region(); 145 set_top_left(other.top_left()); 146 set_icc_profile(other.icc_profile()); 147 set_may_contain_cursor(other.may_contain_cursor()); 148 set_device_scale_factor(other.device_scale_factor()); 149 } 150 151 void DesktopFrame::MoveFrameInfoFrom(DesktopFrame* other) { 152 set_dpi(other->dpi()); 153 set_capture_time_ms(other->capture_time_ms()); 154 set_capturer_id(other->capturer_id()); 155 mutable_updated_region()->Swap(other->mutable_updated_region()); 156 set_top_left(other->top_left()); 157 set_icc_profile(other->icc_profile()); 158 set_may_contain_cursor(other->may_contain_cursor()); 159 set_device_scale_factor(other->device_scale_factor()); 160 } 161 162 bool DesktopFrame::FrameDataIsBlack() const { 163 if (size().is_empty()) 164 return false; 165 166 uint32_t* pixel = reinterpret_cast<uint32_t*>(data()); 167 for (int i = 0; i < size().width() * size().height(); ++i) { 168 if (*pixel++) 169 return false; 170 } 171 return true; 172 } 173 174 void DesktopFrame::SetFrameDataToBlack() { 175 const uint8_t kBlackPixelValue = 0x00; 176 memset(data(), kBlackPixelValue, stride() * size().height()); 177 } 178 179 BasicDesktopFrame::BasicDesktopFrame(DesktopSize size) 180 : BasicDesktopFrame(size, FOURCC_ARGB) {} 181 182 BasicDesktopFrame::BasicDesktopFrame(DesktopSize size, FourCC pixel_format) 183 : DesktopFrame(size, 184 kBytesPerPixel * size.width(), 185 pixel_format, 186 new uint8_t[kBytesPerPixel * size.width() * size.height()](), 187 nullptr) {} 188 189 BasicDesktopFrame::~BasicDesktopFrame() { 190 delete[] data_; 191 } 192 193 // static 194 DesktopFrame* BasicDesktopFrame::CopyOf(const DesktopFrame& frame) { 195 DesktopFrame* result = 196 new BasicDesktopFrame(frame.size(), frame.pixel_format()); 197 // TODO(crbug.com/1330019): Temporary workaround for a known libyuv crash when 198 // the height or width is 0. Remove this once this change has been merged. 199 if (frame.size().width() && frame.size().height()) { 200 libyuv::CopyPlane(frame.data(), frame.stride(), result->data(), 201 result->stride(), frame.size().width() * kBytesPerPixel, 202 frame.size().height()); 203 } 204 result->CopyFrameInfoFrom(frame); 205 return result; 206 } 207 208 // static 209 std::unique_ptr<DesktopFrame> SharedMemoryDesktopFrame::Create( 210 DesktopSize size, 211 FourCC pixel_format, 212 SharedMemoryFactory* shared_memory_factory) { 213 RTC_DCHECK(shared_memory_factory); 214 215 size_t buffer_size = size.height() * size.width() * kBytesPerPixel; 216 std::unique_ptr<SharedMemory> shared_memory = 217 shared_memory_factory->CreateSharedMemory(buffer_size); 218 if (!shared_memory) 219 return nullptr; 220 221 return std::make_unique<SharedMemoryDesktopFrame>( 222 size, size.width() * kBytesPerPixel, pixel_format, 223 std::move(shared_memory)); 224 } 225 226 SharedMemoryDesktopFrame::SharedMemoryDesktopFrame( 227 DesktopSize size, 228 int stride, 229 std::unique_ptr<SharedMemory> shared_memory) 230 : SharedMemoryDesktopFrame(size, 231 stride, 232 FOURCC_ARGB, 233 std::move(shared_memory)) {} 234 235 SharedMemoryDesktopFrame::SharedMemoryDesktopFrame(DesktopSize size, 236 int stride, 237 FourCC pixel_format, 238 SharedMemory* shared_memory) 239 : DesktopFrame(size, 240 stride, 241 pixel_format, 242 reinterpret_cast<uint8_t*>(shared_memory->data()), 243 shared_memory) {} 244 245 SharedMemoryDesktopFrame::SharedMemoryDesktopFrame( 246 DesktopSize size, 247 int stride, 248 FourCC pixel_format, 249 std::unique_ptr<SharedMemory> shared_memory) 250 : SharedMemoryDesktopFrame(size, 251 stride, 252 pixel_format, 253 shared_memory.release()) {} 254 255 SharedMemoryDesktopFrame::~SharedMemoryDesktopFrame() { 256 delete shared_memory_; 257 } 258 259 } // namespace webrtc