blob: fb13fe273880727dd102710dd626a772c4183c51 [file] [log] [blame]
/*
* 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> DesktopFrameCGImage::CreateForDisplay(
CGDirectDisplayID display_id) {
// Create an image containing a snapshot of the display.
rtc::ScopedCFTypeRef<CGImageRef> cg_image(CGDisplayCreateImage(display_id));
if (!cg_image) {
return nullptr;
}
return DesktopFrameCGImage::CreateFromCGImage(cg_image);
}
// static
std::unique_ptr<DesktopFrameCGImage> DesktopFrameCGImage::CreateForWindow(CGWindowID window_id) {
rtc::ScopedCFTypeRef<CGImageRef> cg_image(
CGWindowListCreateImage(CGRectNull,
kCGWindowListOptionIncludingWindow,
window_id,
kCGWindowImageBoundsIgnoreFraming));
if (!cg_image) {
return nullptr;
}
return DesktopFrameCGImage::CreateFromCGImage(cg_image);
}
// static
std::unique_ptr<DesktopFrameCGImage> DesktopFrameCGImage::CreateFromCGImage(
rtc::ScopedCFTypeRef<CGImageRef> cg_image) {
// 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<CFDataRef> 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<uint8_t*>(CFDataGetBytePtr(cg_data.get()));
RTC_DCHECK(data);
DesktopSize size(CGImageGetWidth(cg_image.get()), CGImageGetHeight(cg_image.get()));
int stride = CGImageGetBytesPerRow(cg_image.get());
std::unique_ptr<DesktopFrameCGImage> frame(
new DesktopFrameCGImage(size, stride, data, cg_image, cg_data));
CGColorSpaceRef cg_color_space = CGImageGetColorSpace(cg_image.get());
if (cg_color_space) {
rtc::ScopedCFTypeRef<CFDataRef> cf_icc_profile(CGColorSpaceCopyICCProfile(cg_color_space));
if (cf_icc_profile) {
const uint8_t* data_as_byte =
reinterpret_cast<const uint8_t*>(CFDataGetBytePtr(cf_icc_profile.get()));
const size_t data_size = CFDataGetLength(cf_icc_profile.get());
if (data_as_byte && data_size > 0) {
frame->set_icc_profile(std::vector<uint8_t>(data_as_byte, data_as_byte + data_size));
}
}
}
return frame;
}
DesktopFrameCGImage::DesktopFrameCGImage(DesktopSize size,
int stride,
uint8_t* data,
rtc::ScopedCFTypeRef<CGImageRef> cg_image,
rtc::ScopedCFTypeRef<CFDataRef> 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