desktop_frame_iosurface.mm (3984B)
1 /* 2 * Copyright (c) 2018 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/mac/desktop_frame_iosurface.h" 12 13 #include "rtc_base/checks.h" 14 #include "rtc_base/logging.h" 15 #include "rtc_base/numerics/safe_conversions.h" 16 17 namespace webrtc { 18 19 // static 20 std::unique_ptr<DesktopFrameIOSurface> DesktopFrameIOSurface::Wrap( 21 webrtc::ScopedCFTypeRef<IOSurfaceRef> io_surface, CGRect rect) { 22 if (!io_surface) { 23 return nullptr; 24 } 25 26 IOSurfaceIncrementUseCount(io_surface.get()); 27 IOReturn status = 28 IOSurfaceLock(io_surface.get(), kIOSurfaceLockReadOnly, nullptr); 29 if (status != kIOReturnSuccess) { 30 RTC_LOG(LS_ERROR) << "Failed to lock the IOSurface with status " << status; 31 IOSurfaceDecrementUseCount(io_surface.get()); 32 return nullptr; 33 } 34 35 // Verify that the image has 32-bit depth. 36 int bytes_per_pixel = IOSurfaceGetBytesPerElement(io_surface.get()); 37 if (bytes_per_pixel != DesktopFrame::kBytesPerPixel) { 38 RTC_LOG(LS_ERROR) << "CGDisplayStream handler returned IOSurface with " 39 << (8 * bytes_per_pixel) 40 << " bits per pixel. Only 32-bit depth is supported."; 41 IOSurfaceUnlock(io_surface.get(), kIOSurfaceLockReadOnly, nullptr); 42 IOSurfaceDecrementUseCount(io_surface.get()); 43 return nullptr; 44 } 45 46 const size_t surface_width = IOSurfaceGetWidth(io_surface.get()); 47 const size_t surface_height = IOSurfaceGetHeight(io_surface.get()); 48 const int32_t stride = 49 checked_cast<int32_t>(IOSurfaceGetBytesPerRow(io_surface.get())); 50 uint8_t* const data = 51 static_cast<uint8_t*>(IOSurfaceGetBaseAddress(io_surface.get())); 52 int32_t width = checked_cast<int32_t>(surface_width); 53 int32_t height = checked_cast<int32_t>(surface_height); 54 ptrdiff_t offset = 0; 55 ptrdiff_t offset_columns = 0; 56 ptrdiff_t offset_rows = 0; 57 if (rect.size.width > 0 && rect.size.height > 0) { 58 width = checked_cast<int32_t>(std::floor(rect.size.width)); 59 height = checked_cast<int32_t>(std::floor(rect.size.height)); 60 offset_columns = checked_cast<ptrdiff_t>(std::ceil(rect.origin.x)); 61 offset_rows = checked_cast<ptrdiff_t>(std::ceil(rect.origin.y)); 62 offset = stride * offset_rows + bytes_per_pixel * offset_columns; 63 } 64 65 RTC_LOG(LS_VERBOSE) << "DesktopFrameIOSurface wrapping IOSurface with size " 66 << surface_width << "x" << surface_height 67 << ". Cropping to (" << offset_columns << "," 68 << offset_rows << "; " << width << "x" << height 69 << "). Stride=" << stride / bytes_per_pixel 70 << ", buffer-offset-px=" << offset / bytes_per_pixel 71 << ", buffer-offset-bytes=" << offset; 72 73 RTC_CHECK_GE(surface_width, offset_columns + width); 74 RTC_CHECK_GE(surface_height, offset_rows + height); 75 RTC_CHECK_GE(offset, 0); 76 RTC_CHECK_LE(offset + ((height - 1) * stride) + (width * bytes_per_pixel) - 1, 77 IOSurfaceGetAllocSize(io_surface.get())); 78 79 return std::unique_ptr<DesktopFrameIOSurface>(new DesktopFrameIOSurface( 80 io_surface, data + offset, width, height, stride)); 81 } 82 83 DesktopFrameIOSurface::DesktopFrameIOSurface( 84 webrtc::ScopedCFTypeRef<IOSurfaceRef> io_surface, 85 uint8_t* data, 86 int32_t width, 87 int32_t height, 88 int32_t stride) 89 : DesktopFrame(DesktopSize(width, height), stride, data, nullptr), 90 io_surface_(io_surface) { 91 RTC_DCHECK(io_surface_); 92 } 93 94 DesktopFrameIOSurface::~DesktopFrameIOSurface() { 95 IOSurfaceUnlock(io_surface_.get(), kIOSurfaceLockReadOnly, nullptr); 96 IOSurfaceDecrementUseCount(io_surface_.get()); 97 } 98 99 } // namespace webrtc