diff options
Diffstat (limited to 'remoting')
-rw-r--r-- | remoting/host/capturer_mac.cc | 95 |
1 files changed, 84 insertions, 11 deletions
diff --git a/remoting/host/capturer_mac.cc b/remoting/host/capturer_mac.cc index 49e9319..5e7b217 100644 --- a/remoting/host/capturer_mac.cc +++ b/remoting/host/capturer_mac.cc @@ -5,23 +5,36 @@ #include "remoting/host/capturer.h" #include <ApplicationServices/ApplicationServices.h> +#include <dlfcn.h> #include <OpenGL/CGLMacro.h> #include <OpenGL/OpenGL.h> - #include <stddef.h> #include "base/logging.h" #include "base/mac/mac_util.h" +#include "base/mac/scoped_cftyperef.h" #include "base/memory/scoped_ptr.h" #include "base/synchronization/waitable_event.h" #include "remoting/base/util.h" #include "remoting/host/capturer_helper.h" #include "skia/ext/skia_utils_mac.h" + namespace remoting { namespace { +#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5) +// Possibly remove CapturerMac::CgBlitPreLion as well depending on performance +// of CapturerMac::CgBlitPostLion on 10.6. +#error No longer need to import CGDisplayCreateImage. +#else +// Declared here because CGDisplayCreateImage does not exist in the 10.5 SDK, +// which we are currently compiling against, and it is required on 10.7 to do +// screen capture. +typedef CGImageRef (*CGDisplayCreateImageFunc)(CGDirectDisplayID displayID); +#endif + // The amount of time allowed for displays to reconfigure. const int64 kDisplayReconfigurationTimeoutInSeconds = 10; @@ -147,7 +160,8 @@ class CapturerMac : public Capturer { private: void GlBlitFast(const VideoFrameBuffer& buffer, const SkRegion& region); void GlBlitSlow(const VideoFrameBuffer& buffer); - void CgBlit(const VideoFrameBuffer& buffer, const SkRegion& region); + void CgBlitPreLion(const VideoFrameBuffer& buffer, const SkRegion& region); + void CgBlitPostLion(const VideoFrameBuffer& buffer, const SkRegion& region); void CaptureRegion(const SkRegion& region, CaptureCompletedCallback* callback); @@ -195,6 +209,9 @@ class CapturerMac : public Capturer { // structures. Specifically cgl_context_ and pixel_buffer_object_. base::WaitableEvent display_configuration_capture_event_; + // Will be non-null on lion. + CGDisplayCreateImageFunc display_create_image_func_; + DISALLOW_COPY_AND_ASSIGN(CapturerMac); }; @@ -203,7 +220,8 @@ CapturerMac::CapturerMac() current_buffer_(0), last_buffer_(NULL), pixel_format_(media::VideoFrame::RGB32), - display_configuration_capture_event_(false, true) { + display_configuration_capture_event_(false, true), + display_create_image_func_(NULL) { } CapturerMac::~CapturerMac() { @@ -236,6 +254,15 @@ bool CapturerMac::Init() { return false; } + if (base::mac::IsOSLionOrLater()) { + display_create_image_func_ = + reinterpret_cast<CGDisplayCreateImageFunc>( + dlsym(RTLD_NEXT, "CGDisplayCreateImage")); + if (!display_create_image_func_) { + LOG(ERROR) << "Unable to load CGDisplayCreateImage on Lion"; + return false; + } + } ScreenConfigurationChanged(); return true; } @@ -269,6 +296,11 @@ void CapturerMac::ScreenConfigurationChanged() { return; } + if (display_create_image_func_ != NULL) { + // No need for any OpenGL support on Lion + return; + } + CGLPixelFormatAttribute attributes[] = { kCGLPFAFullScreen, kCGLPFADisplayMask, @@ -323,8 +355,12 @@ void CapturerMac::CaptureInvalidRegion(CaptureCompletedCallback* callback) { VideoFrameBuffer& current_buffer = buffers_[current_buffer_]; current_buffer.Update(); - bool flip = true; // GL capturers need flipping. - if (cgl_context_) { + bool flip = false; // GL capturers need flipping. + if (display_create_image_func_ != NULL) { + // Lion requires us to use their new APIs for doing screen capture. + CgBlitPostLion(current_buffer, region); + } else if (cgl_context_) { + flip = true; if (pixel_buffer_object_.get() != 0) { GlBlitFast(current_buffer, region); } else { @@ -333,8 +369,7 @@ void CapturerMac::CaptureInvalidRegion(CaptureCompletedCallback* callback) { GlBlitSlow(current_buffer); } } else { - CgBlit(current_buffer, region); - flip = false; + CgBlitPreLion(current_buffer, region); } DataPlanes planes; @@ -439,8 +474,8 @@ void CapturerMac::GlBlitSlow(const VideoFrameBuffer& buffer) { glPopClientAttrib(); } -void CapturerMac::CgBlit(const VideoFrameBuffer& buffer, - const SkRegion& region) { +void CapturerMac::CgBlitPreLion(const VideoFrameBuffer& buffer, + const SkRegion& region) { const int buffer_height = buffer.size().height(); const int buffer_width = buffer.size().width(); @@ -448,8 +483,7 @@ void CapturerMac::CgBlit(const VideoFrameBuffer& buffer, SkIRect clip_rect = SkIRect::MakeWH(buffer_width, buffer_height); if (last_buffer_) - memcpy(buffer.ptr(), last_buffer_, - buffer.bytes_per_row() * buffer_height); + memcpy(buffer.ptr(), last_buffer_, buffer.bytes_per_row() * buffer_height); last_buffer_ = buffer.ptr(); CGDirectDisplayID main_display = CGMainDisplayID(); uint8* display_base_address = @@ -472,6 +506,45 @@ void CapturerMac::CgBlit(const VideoFrameBuffer& buffer, } } +void CapturerMac::CgBlitPostLion(const VideoFrameBuffer& buffer, + const SkRegion& region) { + const int buffer_height = buffer.size().height(); + const int buffer_width = buffer.size().width(); + + // Clip to the size of our current screen. + SkIRect clip_rect = SkIRect::MakeWH(buffer_width, buffer_height); + + if (last_buffer_) + memcpy(buffer.ptr(), last_buffer_, buffer.bytes_per_row() * buffer_height); + last_buffer_ = buffer.ptr(); + CGDirectDisplayID display = CGMainDisplayID(); + base::mac::ScopedCFTypeRef<CGImageRef> image( + display_create_image_func_(display)); + if (image.get() == NULL) + return; + CGDataProviderRef provider = CGImageGetDataProvider(image); + base::mac::ScopedCFTypeRef<CFDataRef> data(CGDataProviderCopyData(provider)); + if (data.get() == NULL) + return; + const uint8* display_base_address = CFDataGetBytePtr(data); + int src_bytes_per_row = CGImageGetBytesPerRow(image); + int src_bytes_per_pixel = CGImageGetBitsPerPixel(image) / 8; + // TODO(hclam): We can reduce the amount of copying here by subtracting + // |capturer_helper_|s region from |last_invalid_region_|. + // http://crbug.com/92354 + for(SkRegion::Iterator i(region); !i.done(); i.next()) { + SkIRect copy_rect = i.rect(); + if (copy_rect.intersect(clip_rect)) { + CopyRect(display_base_address, + src_bytes_per_row, + buffer.ptr(), + buffer.bytes_per_row(), + src_bytes_per_pixel, + copy_rect); + } + } +} + const SkISize& CapturerMac::size_most_recent() const { return helper_.size_most_recent(); } |