diff --git a/modules/desktop_capture/mac/desktop_frame_cgimage.h b/modules/desktop_capture/mac/desktop_frame_cgimage.h index bf8be1b2fa..8e00666573 100644 --- a/modules/desktop_capture/mac/desktop_frame_cgimage.h +++ b/modules/desktop_capture/mac/desktop_frame_cgimage.h @@ -27,9 +27,18 @@ class DesktopFrameCGImage final : public DesktopFrame { static std::unique_ptr CreateForDisplay( CGDirectDisplayID display_id); + // Create an image containing a snaphot of the given window at the time this + // is being called. This also works when the window is overlapped or in + // another workspace. + static std::unique_ptr CreateForWindow( + CGWindowID window_id); + ~DesktopFrameCGImage() override; private: + static std::unique_ptr CreateFromCGImage( + rtc::ScopedCFTypeRef cg_image); + // This constructor expects |cg_image| to hold a non-null CGImageRef. DesktopFrameCGImage(DesktopSize size, int stride, diff --git a/modules/desktop_capture/mac/desktop_frame_cgimage.mm b/modules/desktop_capture/mac/desktop_frame_cgimage.mm index 23afaaa138..784b04f7b9 100644 --- a/modules/desktop_capture/mac/desktop_frame_cgimage.mm +++ b/modules/desktop_capture/mac/desktop_frame_cgimage.mm @@ -24,6 +24,26 @@ std::unique_ptr DesktopFrameCGImage::CreateForDisplay( return nullptr; } + return DesktopFrameCGImage::CreateFromCGImage(cg_image); +} + +// static +std::unique_ptr DesktopFrameCGImage::CreateForWindow(CGWindowID window_id) { + rtc::ScopedCFTypeRef cg_image( + CGWindowListCreateImage(CGRectNull, + kCGWindowListOptionIncludingWindow, + window_id, + kCGWindowImageBoundsIgnoreFraming)); + if (!cg_image) { + return nullptr; + } + + return DesktopFrameCGImage::CreateFromCGImage(cg_image); +} + +// static +std::unique_ptr DesktopFrameCGImage::CreateFromCGImage( + rtc::ScopedCFTypeRef 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) { diff --git a/modules/desktop_capture/window_capturer_mac.mm b/modules/desktop_capture/window_capturer_mac.mm index 979b3b87d2..fae3f9854b 100644 --- a/modules/desktop_capture/window_capturer_mac.mm +++ b/modules/desktop_capture/window_capturer_mac.mm @@ -21,6 +21,7 @@ #include "modules/desktop_capture/desktop_frame.h" #include "modules/desktop_capture/mac/desktop_configuration.h" #include "modules/desktop_capture/mac/desktop_configuration_monitor.h" +#include "modules/desktop_capture/mac/desktop_frame_cgimage.h" #include "modules/desktop_capture/mac/full_screen_chrome_window_detector.h" #include "modules/desktop_capture/mac/window_list_utils.h" #include "modules/desktop_capture/window_finder_mac.h" @@ -171,41 +172,13 @@ void WindowCapturerMac::CaptureFrame() { on_screen_window = full_screen_window; } - CGImageRef window_image = CGWindowListCreateImage( - CGRectNull, kCGWindowListOptionIncludingWindow, - on_screen_window, kCGWindowImageBoundsIgnoreFraming); - - if (!window_image) { + std::unique_ptr frame = DesktopFrameCGImage::CreateForWindow(on_screen_window); + if (!frame) { RTC_LOG(LS_WARNING) << "Temporarily failed to capture window."; callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr); return; } - int bits_per_pixel = CGImageGetBitsPerPixel(window_image); - if (bits_per_pixel != 32) { - RTC_LOG(LS_ERROR) << "Unsupported window image depth: " << bits_per_pixel; - CFRelease(window_image); - callback_->OnCaptureResult(Result::ERROR_PERMANENT, nullptr); - return; - } - - int width = CGImageGetWidth(window_image); - int height = CGImageGetHeight(window_image); - CGDataProviderRef provider = CGImageGetDataProvider(window_image); - CFDataRef cf_data = CGDataProviderCopyData(provider); - std::unique_ptr frame( - new BasicDesktopFrame(DesktopSize(width, height))); - - int src_stride = CGImageGetBytesPerRow(window_image); - const uint8_t* src_data = CFDataGetBytePtr(cf_data); - for (int y = 0; y < height; ++y) { - memcpy(frame->data() + frame->stride() * y, src_data + src_stride * y, - DesktopFrame::kBytesPerPixel * width); - } - - CFRelease(cf_data); - CFRelease(window_image); - frame->mutable_updated_region()->SetRect( DesktopRect::MakeSize(frame->size())); frame->set_top_left(GetWindowBounds(on_screen_window).top_left());