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}
This commit is contained in:
Julien Isorce 2019-04-18 21:26:55 -07:00 committed by Commit Bot
parent aec09a2d18
commit 5665572f47
3 changed files with 32 additions and 30 deletions

View File

@ -27,9 +27,18 @@ class DesktopFrameCGImage final : public DesktopFrame {
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,

View File

@ -24,6 +24,26 @@ std::unique_ptr<DesktopFrameCGImage> DesktopFrameCGImage::CreateForDisplay(
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) {

View File

@ -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<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());