diff --git a/modules/desktop_capture/BUILD.gn b/modules/desktop_capture/BUILD.gn index 6f116daa9f..5a4383b2f9 100644 --- a/modules/desktop_capture/BUILD.gn +++ b/modules/desktop_capture/BUILD.gn @@ -175,6 +175,8 @@ if (is_mac) { visibility = [ ":desktop_capture" ] sources = [ "mac/desktop_configuration.mm", + "mac/desktop_frame_cgimage.h", + "mac/desktop_frame_cgimage.mm", "mac/screen_capturer_mac.h", "mac/screen_capturer_mac.mm", "mouse_cursor_monitor_mac.mm", diff --git a/modules/desktop_capture/DEPS b/modules/desktop_capture/DEPS index 3b8a639f5e..61bf938fb6 100644 --- a/modules/desktop_capture/DEPS +++ b/modules/desktop_capture/DEPS @@ -4,6 +4,9 @@ include_rules = [ ] specific_include_rules = { + "desktop_frame_cgimage\.h": [ + "+sdk/objc", + ], "screen_capturer_mac\.mm": [ "+sdk/objc", ], diff --git a/modules/desktop_capture/mac/desktop_frame_cgimage.h b/modules/desktop_capture/mac/desktop_frame_cgimage.h new file mode 100644 index 0000000000..1adc8b02cf --- /dev/null +++ b/modules/desktop_capture/mac/desktop_frame_cgimage.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef MODULES_DESKTOP_CAPTURE_MAC_DESKTOP_FRAME_CGIMAGE_H_ +#define MODULES_DESKTOP_CAPTURE_MAC_DESKTOP_FRAME_CGIMAGE_H_ + +#include + +#include + +#include "modules/desktop_capture/desktop_frame.h" +#include "sdk/objc/Framework/Classes/Common/scoped_cftyperef.h" + +namespace webrtc { + +class DesktopFrameCGImage final : public DesktopFrame { + public: + // Create an image containing a snapshot of the display at the time this is + // being called. + static std::unique_ptr CreateForDisplay( + CGDirectDisplayID display_id); + + ~DesktopFrameCGImage() override; + + private: + // This constructor expects |cg_image| to hold a non-null CGImageRef. + DesktopFrameCGImage(DesktopSize size, + int stride, + uint8_t* data, + rtc::ScopedCFTypeRef cg_image, + rtc::ScopedCFTypeRef cg_data); + + const rtc::ScopedCFTypeRef cg_image_; + const rtc::ScopedCFTypeRef cg_data_; + + RTC_DISALLOW_COPY_AND_ASSIGN(DesktopFrameCGImage); +}; + +} // namespace webrtc + +#endif // MODULES_DESKTOP_CAPTURE_MAC_DESKTOP_FRAME_CGIMAGE_H_ diff --git a/modules/desktop_capture/mac/desktop_frame_cgimage.mm b/modules/desktop_capture/mac/desktop_frame_cgimage.mm new file mode 100644 index 0000000000..23afaaa138 --- /dev/null +++ b/modules/desktop_capture/mac/desktop_frame_cgimage.mm @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "modules/desktop_capture/mac/desktop_frame_cgimage.h" + +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" + +namespace webrtc { + +// static +std::unique_ptr DesktopFrameCGImage::CreateForDisplay( + CGDirectDisplayID display_id) { + // Create an image containing a snapshot of the display. + rtc::ScopedCFTypeRef cg_image(CGDisplayCreateImage(display_id)); + if (!cg_image) { + return nullptr; + } + + // Verify that the image has 32-bit depth. + int bits_per_pixel = CGImageGetBitsPerPixel(cg_image.get()); + if (bits_per_pixel / 8 != DesktopFrame::kBytesPerPixel) { + RTC_LOG(LS_ERROR) << "CGDisplayCreateImage() returned imaged with " << bits_per_pixel + << " bits per pixel. Only 32-bit depth is supported."; + return nullptr; + } + + // Request access to the raw pixel data via the image's DataProvider. + CGDataProviderRef cg_provider = CGImageGetDataProvider(cg_image.get()); + RTC_DCHECK(cg_provider); + + // CGDataProviderCopyData returns a new data object containing a copy of the provider’s + // data. + rtc::ScopedCFTypeRef cg_data(CGDataProviderCopyData(cg_provider)); + RTC_DCHECK(cg_data); + + // CFDataGetBytePtr returns a read-only pointer to the bytes of a CFData object. + uint8_t* data = const_cast(CFDataGetBytePtr(cg_data.get())); + RTC_DCHECK(data); + + DesktopSize size(CGImageGetWidth(cg_image.get()), CGImageGetHeight(cg_image.get())); + int stride = CGImageGetBytesPerRow(cg_image.get()); + + return std::unique_ptr( + new DesktopFrameCGImage(size, stride, data, cg_image, cg_data)); +} + +DesktopFrameCGImage::DesktopFrameCGImage(DesktopSize size, + int stride, + uint8_t* data, + rtc::ScopedCFTypeRef cg_image, + rtc::ScopedCFTypeRef cg_data) + : DesktopFrame(size, stride, data, nullptr), cg_image_(cg_image), cg_data_(cg_data) { + RTC_DCHECK(cg_image_); + RTC_DCHECK(cg_data_); +} + +DesktopFrameCGImage::~DesktopFrameCGImage() = default; + +} // namespace webrtc diff --git a/modules/desktop_capture/mac/screen_capturer_mac.mm b/modules/desktop_capture/mac/screen_capturer_mac.mm index ca3cc1ed85..df18777226 100644 --- a/modules/desktop_capture/mac/screen_capturer_mac.mm +++ b/modules/desktop_capture/mac/screen_capturer_mac.mm @@ -12,6 +12,7 @@ #include "modules/desktop_capture/mac/screen_capturer_mac.h" +#include "modules/desktop_capture/mac/desktop_frame_cgimage.h" #include "rtc_base/checks.h" #include "rtc_base/constructormagic.h" #include "rtc_base/logging.h" @@ -405,32 +406,19 @@ bool ScreenCapturerMac::CgBlit(const DesktopFrame& frame, const DesktopRegion& r } } - // Create an image containing a snapshot of the display. - rtc::ScopedCFTypeRef image(CGDisplayCreateImage(display_config.id)); - if (!image) { + std::unique_ptr frame_source = + DesktopFrameCGImage::CreateForDisplay(display_config.id); + if (!frame_source) { continue; } - // Verify that the image has 32-bit depth. - int bits_per_pixel = CGImageGetBitsPerPixel(image.get()); - if (bits_per_pixel / 8 != DesktopFrame::kBytesPerPixel) { - RTC_LOG(LS_ERROR) << "CGDisplayCreateImage() returned imaged with " << bits_per_pixel - << " bits per pixel. Only 32-bit depth is supported."; - return false; - } + const uint8_t* display_base_address = frame_source->data(); + int src_bytes_per_row = frame_source->stride(); + RTC_DCHECK(display_base_address); - // Request access to the raw pixel data via the image's DataProvider. - CGDataProviderRef provider = CGImageGetDataProvider(image.get()); - rtc::ScopedCFTypeRef data(CGDataProviderCopyData(provider)); - RTC_DCHECK(data); - - const uint8_t* display_base_address = CFDataGetBytePtr(data.get()); - int src_bytes_per_row = CGImageGetBytesPerRow(image.get()); - - // |image| size may be different from display_bounds in case the screen was + // |frame_source| size may be different from display_bounds in case the screen was // resized recently. - copy_region.IntersectWith( - DesktopRect::MakeWH(CGImageGetWidth(image.get()), CGImageGetHeight(image.get()))); + copy_region.IntersectWith(frame_source->rect()); // Copy the dirty region from the display buffer into our desktop buffer. uint8_t* out_ptr = frame.GetFrameDataAtPos(display_bounds.top_left());