xref: /aosp_15_r20/external/webrtc/modules/desktop_capture/mac/desktop_frame_cgimage.mm (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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_cgimage.h"
12
13#include <AvailabilityMacros.h>
14
15#include "rtc_base/checks.h"
16#include "rtc_base/logging.h"
17
18namespace webrtc {
19
20// static
21std::unique_ptr<DesktopFrameCGImage> DesktopFrameCGImage::CreateForDisplay(
22    CGDirectDisplayID display_id) {
23  // Create an image containing a snapshot of the display.
24  rtc::ScopedCFTypeRef<CGImageRef> cg_image(CGDisplayCreateImage(display_id));
25  if (!cg_image) {
26    return nullptr;
27  }
28
29  return DesktopFrameCGImage::CreateFromCGImage(cg_image);
30}
31
32// static
33std::unique_ptr<DesktopFrameCGImage> DesktopFrameCGImage::CreateForWindow(CGWindowID window_id) {
34  rtc::ScopedCFTypeRef<CGImageRef> cg_image(
35      CGWindowListCreateImage(CGRectNull,
36                              kCGWindowListOptionIncludingWindow,
37                              window_id,
38                              kCGWindowImageBoundsIgnoreFraming));
39  if (!cg_image) {
40    return nullptr;
41  }
42
43  return DesktopFrameCGImage::CreateFromCGImage(cg_image);
44}
45
46// static
47std::unique_ptr<DesktopFrameCGImage> DesktopFrameCGImage::CreateFromCGImage(
48    rtc::ScopedCFTypeRef<CGImageRef> cg_image) {
49  // Verify that the image has 32-bit depth.
50  int bits_per_pixel = CGImageGetBitsPerPixel(cg_image.get());
51  if (bits_per_pixel / 8 != DesktopFrame::kBytesPerPixel) {
52    RTC_LOG(LS_ERROR) << "CGDisplayCreateImage() returned imaged with " << bits_per_pixel
53                      << " bits per pixel. Only 32-bit depth is supported.";
54    return nullptr;
55  }
56
57  // Request access to the raw pixel data via the image's DataProvider.
58  CGDataProviderRef cg_provider = CGImageGetDataProvider(cg_image.get());
59  RTC_DCHECK(cg_provider);
60
61  // CGDataProviderCopyData returns a new data object containing a copy of the provider’s
62  // data.
63  rtc::ScopedCFTypeRef<CFDataRef> cg_data(CGDataProviderCopyData(cg_provider));
64  RTC_DCHECK(cg_data);
65
66  // CFDataGetBytePtr returns a read-only pointer to the bytes of a CFData object.
67  uint8_t* data = const_cast<uint8_t*>(CFDataGetBytePtr(cg_data.get()));
68  RTC_DCHECK(data);
69
70  DesktopSize size(CGImageGetWidth(cg_image.get()), CGImageGetHeight(cg_image.get()));
71  int stride = CGImageGetBytesPerRow(cg_image.get());
72
73  std::unique_ptr<DesktopFrameCGImage> frame(
74      new DesktopFrameCGImage(size, stride, data, cg_image, cg_data));
75
76  CGColorSpaceRef cg_color_space = CGImageGetColorSpace(cg_image.get());
77  if (cg_color_space) {
78#if !defined(MAC_OS_X_VERSION_10_13) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_13
79    rtc::ScopedCFTypeRef<CFDataRef> cf_icc_profile(CGColorSpaceCopyICCProfile(cg_color_space));
80#else
81    rtc::ScopedCFTypeRef<CFDataRef> cf_icc_profile(CGColorSpaceCopyICCData(cg_color_space));
82#endif
83    if (cf_icc_profile) {
84      const uint8_t* data_as_byte =
85          reinterpret_cast<const uint8_t*>(CFDataGetBytePtr(cf_icc_profile.get()));
86      const size_t data_size = CFDataGetLength(cf_icc_profile.get());
87      if (data_as_byte && data_size > 0) {
88        frame->set_icc_profile(std::vector<uint8_t>(data_as_byte, data_as_byte + data_size));
89      }
90    }
91  }
92
93  return frame;
94}
95
96DesktopFrameCGImage::DesktopFrameCGImage(DesktopSize size,
97                                         int stride,
98                                         uint8_t* data,
99                                         rtc::ScopedCFTypeRef<CGImageRef> cg_image,
100                                         rtc::ScopedCFTypeRef<CFDataRef> cg_data)
101    : DesktopFrame(size, stride, data, nullptr), cg_image_(cg_image), cg_data_(cg_data) {
102  RTC_DCHECK(cg_image_);
103  RTC_DCHECK(cg_data_);
104}
105
106DesktopFrameCGImage::~DesktopFrameCGImage() = default;
107
108}  // namespace webrtc
109