Avoid a frame copy in WindowCapturerMac

By wraping the cg_data instead of copying it. We had the infrastructure
for it since the work around iosurface, we were just not using it.

Also having a centralized DesktopFrameCGImage::CreateFromCGImage helper
will be useful to parse the ICC Profile at only one place.

Bug: chromium:945468
Change-Id: I69f179064fd9045d992a7baea35820c38e24dacc
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/133640
Commit-Queue: Julien Isorce <julien.isorce@chromium.org>
Reviewed-by: Jamie Walch <jamiewalch@chromium.org>
Cr-Commit-Position: refs/heads/master@{#27696}
diff --git a/modules/desktop_capture/mac/desktop_frame_cgimage.h b/modules/desktop_capture/mac/desktop_frame_cgimage.h
index bf8be1b..8e00666 100644
--- a/modules/desktop_capture/mac/desktop_frame_cgimage.h
+++ b/modules/desktop_capture/mac/desktop_frame_cgimage.h
@@ -27,9 +27,18 @@
   static std::unique_ptr<DesktopFrameCGImage> 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<DesktopFrameCGImage> CreateForWindow(
+      CGWindowID window_id);
+
   ~DesktopFrameCGImage() override;
 
  private:
+  static std::unique_ptr<DesktopFrameCGImage> CreateFromCGImage(
+      rtc::ScopedCFTypeRef<CGImageRef> 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 23afaaa..784b04f 100644
--- a/modules/desktop_capture/mac/desktop_frame_cgimage.mm
+++ b/modules/desktop_capture/mac/desktop_frame_cgimage.mm
@@ -24,6 +24,26 @@
     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) {
diff --git a/modules/desktop_capture/window_capturer_mac.mm b/modules/desktop_capture/window_capturer_mac.mm
index 979b3b8..fae3f98 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 @@
       on_screen_window = full_screen_window;
   }
 
-  CGImageRef window_image = CGWindowListCreateImage(
-      CGRectNull, kCGWindowListOptionIncludingWindow,
-      on_screen_window, kCGWindowImageBoundsIgnoreFraming);
-
-  if (!window_image) {
+  std::unique_ptr<DesktopFrame> 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<DesktopFrame> 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());