| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "remoting/host/video_frame_capturer.h" | 5 #include "remoting/host/video_frame_capturer.h" |
| 6 | 6 |
| 7 #include <ApplicationServices/ApplicationServices.h> | 7 #include <ApplicationServices/ApplicationServices.h> |
| 8 #include <Cocoa/Cocoa.h> | 8 #include <Cocoa/Cocoa.h> |
| 9 #include <dlfcn.h> | 9 #include <dlfcn.h> |
| 10 #include <IOKit/pwr_mgt/IOPMLib.h> | 10 #include <IOKit/pwr_mgt/IOPMLib.h> |
| 11 #include <OpenGL/CGLMacro.h> | 11 #include <OpenGL/CGLMacro.h> |
| 12 #include <OpenGL/OpenGL.h> | 12 #include <OpenGL/OpenGL.h> |
| 13 #include <stddef.h> | 13 #include <stddef.h> |
| 14 | 14 |
| 15 #include "base/logging.h" | 15 #include "base/logging.h" |
| 16 #include "base/file_path.h" |
| 16 #include "base/mac/mac_util.h" | 17 #include "base/mac/mac_util.h" |
| 17 #include "base/mac/scoped_cftyperef.h" | 18 #include "base/mac/scoped_cftyperef.h" |
| 18 #include "base/memory/scoped_ptr.h" | 19 #include "base/memory/scoped_ptr.h" |
| 20 #include "base/scoped_native_library.h" |
| 19 #include "base/synchronization/waitable_event.h" | 21 #include "base/synchronization/waitable_event.h" |
| 20 #include "base/time.h" | 22 #include "base/time.h" |
| 21 #include "remoting/base/capture_data.h" | 23 #include "remoting/base/capture_data.h" |
| 22 #include "remoting/base/util.h" | 24 #include "remoting/base/util.h" |
| 23 #include "remoting/host/mac/scoped_pixel_buffer_object.h" | 25 #include "remoting/host/mac/scoped_pixel_buffer_object.h" |
| 24 #include "remoting/host/video_frame_capturer_helper.h" | 26 #include "remoting/host/video_frame_capturer_helper.h" |
| 25 #include "remoting/proto/control.pb.h" | 27 #include "remoting/proto/control.pb.h" |
| 26 | 28 |
| 27 namespace remoting { | 29 namespace remoting { |
| 28 | 30 |
| 29 namespace { | 31 namespace { |
| 30 | 32 |
| 33 // Definitions used to dynamic-link to deprecated OS 10.6 functions. |
| 34 const char* kApplicationServicesLibraryName = |
| 35 "/System/Library/Frameworks/ApplicationServices.framework/" |
| 36 "ApplicationServices"; |
| 37 typedef void* (*CGDisplayBaseAddressFunc)(CGDirectDisplayID); |
| 38 typedef size_t (*CGDisplayBytesPerRowFunc)(CGDirectDisplayID); |
| 39 typedef size_t (*CGDisplayBitsPerPixelFunc)(CGDirectDisplayID); |
| 40 const char* kOpenGlLibraryName = |
| 41 "/System/Library/Frameworks/OpenGL.framework/OpenGL"; |
| 42 typedef CGLError (*CGLSetFullScreenFunc)(CGLContextObj); |
| 43 |
| 31 // skia/ext/skia_utils_mac.h only defines CGRectToSkRect(). | 44 // skia/ext/skia_utils_mac.h only defines CGRectToSkRect(). |
| 32 SkIRect CGRectToSkIRect(const CGRect& rect) { | 45 SkIRect CGRectToSkIRect(const CGRect& rect) { |
| 33 SkIRect sk_rect = { | 46 SkIRect sk_rect = { |
| 34 SkScalarRound(rect.origin.x), | 47 SkScalarRound(rect.origin.x), |
| 35 SkScalarRound(rect.origin.y), | 48 SkScalarRound(rect.origin.y), |
| 36 SkScalarRound(rect.origin.x + rect.size.width), | 49 SkScalarRound(rect.origin.x + rect.size.width), |
| 37 SkScalarRound(rect.origin.y + rect.size.height) | 50 SkScalarRound(rect.origin.y + rect.size.height) |
| 38 }; | 51 }; |
| 39 return sk_rect; | 52 return sk_rect; |
| 40 } | 53 } |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 175 // Acts as a critical section around our display configuration data | 188 // Acts as a critical section around our display configuration data |
| 176 // structures. Specifically cgl_context_ and pixel_buffer_object_. | 189 // structures. Specifically cgl_context_ and pixel_buffer_object_. |
| 177 base::WaitableEvent display_configuration_capture_event_; | 190 base::WaitableEvent display_configuration_capture_event_; |
| 178 | 191 |
| 179 // Power management assertion to prevent the screen from sleeping. | 192 // Power management assertion to prevent the screen from sleeping. |
| 180 IOPMAssertionID power_assertion_id_display_; | 193 IOPMAssertionID power_assertion_id_display_; |
| 181 | 194 |
| 182 // Power management assertion to indicate that the user is active. | 195 // Power management assertion to indicate that the user is active. |
| 183 IOPMAssertionID power_assertion_id_user_; | 196 IOPMAssertionID power_assertion_id_user_; |
| 184 | 197 |
| 198 // Dynamically link to deprecated APIs for Mac OS X 10.6 support. |
| 199 base::ScopedNativeLibrary app_services_library_; |
| 200 CGDisplayBaseAddressFunc cg_display_base_address_; |
| 201 CGDisplayBytesPerRowFunc cg_display_bytes_per_row_; |
| 202 CGDisplayBitsPerPixelFunc cg_display_bits_per_pixel_; |
| 203 base::ScopedNativeLibrary opengl_library_; |
| 204 CGLSetFullScreenFunc cgl_set_full_screen_; |
| 205 |
| 185 DISALLOW_COPY_AND_ASSIGN(VideoFrameCapturerMac); | 206 DISALLOW_COPY_AND_ASSIGN(VideoFrameCapturerMac); |
| 186 }; | 207 }; |
| 187 | 208 |
| 188 VideoFrameCapturerMac::VideoFrameCapturerMac() | 209 VideoFrameCapturerMac::VideoFrameCapturerMac() |
| 189 : cgl_context_(NULL), | 210 : cgl_context_(NULL), |
| 190 current_buffer_(0), | 211 current_buffer_(0), |
| 191 last_buffer_(NULL), | 212 last_buffer_(NULL), |
| 192 pixel_format_(media::VideoFrame::RGB32), | 213 pixel_format_(media::VideoFrame::RGB32), |
| 193 display_configuration_capture_event_(false, true), | 214 display_configuration_capture_event_(false, true), |
| 194 power_assertion_id_display_(kIOPMNullAssertionID), | 215 power_assertion_id_display_(kIOPMNullAssertionID), |
| 195 power_assertion_id_user_(kIOPMNullAssertionID) { | 216 power_assertion_id_user_(kIOPMNullAssertionID), |
| 217 cg_display_base_address_(NULL), |
| 218 cg_display_bytes_per_row_(NULL), |
| 219 cg_display_bits_per_pixel_(NULL), |
| 220 cgl_set_full_screen_(NULL) |
| 221 { |
| 196 } | 222 } |
| 197 | 223 |
| 198 VideoFrameCapturerMac::~VideoFrameCapturerMac() { | 224 VideoFrameCapturerMac::~VideoFrameCapturerMac() { |
| 199 ReleaseBuffers(); | 225 ReleaseBuffers(); |
| 200 CGUnregisterScreenRefreshCallback( | 226 CGUnregisterScreenRefreshCallback( |
| 201 VideoFrameCapturerMac::ScreenRefreshCallback, this); | 227 VideoFrameCapturerMac::ScreenRefreshCallback, this); |
| 202 CGScreenUnregisterMoveCallback( | 228 CGScreenUnregisterMoveCallback( |
| 203 VideoFrameCapturerMac::ScreenUpdateMoveCallback, this); | 229 VideoFrameCapturerMac::ScreenUpdateMoveCallback, this); |
| 204 CGError err = CGDisplayRemoveReconfigurationCallback( | 230 CGError err = CGDisplayRemoveReconfigurationCallback( |
| 205 VideoFrameCapturerMac::DisplaysReconfiguredCallback, this); | 231 VideoFrameCapturerMac::DisplaysReconfiguredCallback, this); |
| (...skipping 306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 512 const int buffer_height = buffer.size().height(); | 538 const int buffer_height = buffer.size().height(); |
| 513 | 539 |
| 514 // Copy the entire contents of the previous capture buffer, to capture over. | 540 // Copy the entire contents of the previous capture buffer, to capture over. |
| 515 // TODO(wez): Get rid of this as per crbug.com/145064, or implement | 541 // TODO(wez): Get rid of this as per crbug.com/145064, or implement |
| 516 // crbug.com/92354. | 542 // crbug.com/92354. |
| 517 if (last_buffer_) | 543 if (last_buffer_) |
| 518 memcpy(buffer.ptr(), last_buffer_, buffer.bytes_per_row() * buffer_height); | 544 memcpy(buffer.ptr(), last_buffer_, buffer.bytes_per_row() * buffer_height); |
| 519 last_buffer_ = buffer.ptr(); | 545 last_buffer_ = buffer.ptr(); |
| 520 | 546 |
| 521 for (unsigned int d = 0; d < display_ids_.size(); ++d) { | 547 for (unsigned int d = 0; d < display_ids_.size(); ++d) { |
| 522 #pragma clang diagnostic push | 548 // Use deprecated APIs to determine the display buffer layout. |
| 523 #pragma clang diagnostic ignored "-Wdeprecated-declarations" | 549 DCHECK(cg_display_base_address_ && cg_display_bytes_per_row_ && |
| 550 cg_display_bits_per_pixel_); |
| 524 uint8* display_base_address = | 551 uint8* display_base_address = |
| 525 reinterpret_cast<uint8*>(CGDisplayBaseAddress(display_ids_[d])); | 552 reinterpret_cast<uint8*>((*cg_display_base_address_)(display_ids_[d])); |
| 526 CHECK(display_base_address); | 553 CHECK(display_base_address); |
| 527 int src_bytes_per_row = CGDisplayBytesPerRow(display_ids_[d]); | 554 int src_bytes_per_row = (*cg_display_bytes_per_row_)(display_ids_[d]); |
| 528 int src_bytes_per_pixel = CGDisplayBitsPerPixel(display_ids_[d]) / 8; | 555 int src_bytes_per_pixel = |
| 529 #pragma clang diagnostic pop | 556 (*cg_display_bits_per_pixel_)(display_ids_[d]) / 8; |
| 557 |
| 530 // Determine the position of the display in the buffer. | 558 // Determine the position of the display in the buffer. |
| 531 SkIRect display_bounds = CGRectToSkIRect(CGDisplayBounds(display_ids_[d])); | 559 SkIRect display_bounds = CGRectToSkIRect(CGDisplayBounds(display_ids_[d])); |
| 532 display_bounds.offset(-desktop_bounds_.left(), -desktop_bounds_.top()); | 560 display_bounds.offset(-desktop_bounds_.left(), -desktop_bounds_.top()); |
| 533 | 561 |
| 534 // Determine which parts of the blit region, if any, lay within the monitor. | 562 // Determine which parts of the blit region, if any, lay within the monitor. |
| 535 SkRegion copy_region; | 563 SkRegion copy_region; |
| 536 if (!copy_region.op(region, display_bounds, SkRegion::kIntersect_Op)) | 564 if (!copy_region.op(region, display_bounds, SkRegion::kIntersect_Op)) |
| 537 continue; | 565 continue; |
| 538 | 566 |
| 539 // Translate the region to be copied into display-relative coordinates. | 567 // Translate the region to be copied into display-relative coordinates. |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 640 desktop_bounds_ = SkIRect::MakeEmpty(); | 668 desktop_bounds_ = SkIRect::MakeEmpty(); |
| 641 for (unsigned int d = 0; d < display_count; ++d) { | 669 for (unsigned int d = 0; d < display_count; ++d) { |
| 642 CGRect display_bounds = CGDisplayBounds(display_ids_[d]); | 670 CGRect display_bounds = CGDisplayBounds(display_ids_[d]); |
| 643 desktop_bounds_.join(CGRectToSkIRect(display_bounds)); | 671 desktop_bounds_.join(CGRectToSkIRect(display_bounds)); |
| 644 } | 672 } |
| 645 | 673 |
| 646 // Re-mark the entire desktop as dirty. | 674 // Re-mark the entire desktop as dirty. |
| 647 helper_.InvalidateScreen(SkISize::Make(desktop_bounds_.width(), | 675 helper_.InvalidateScreen(SkISize::Make(desktop_bounds_.width(), |
| 648 desktop_bounds_.height())); | 676 desktop_bounds_.height())); |
| 649 | 677 |
| 678 // CgBlitPostLion uses CGDisplayCreateImage() to snapshot each display's |
| 679 // contents. Although the API exists in OS 10.6, it crashes the caller if |
| 680 // the machine has no monitor connected, so we fall back to depcreated APIs |
| 681 // when running on 10.6. |
| 650 if (base::mac::IsOSLionOrLater()) { | 682 if (base::mac::IsOSLionOrLater()) { |
| 651 LOG(INFO) << "Using CgBlitPostLion."; | 683 LOG(INFO) << "Using CgBlitPostLion."; |
| 652 // No need for any OpenGL support on Lion | 684 // No need for any OpenGL support on Lion |
| 653 return; | 685 return; |
| 654 } | 686 } |
| 655 | 687 |
| 688 // Dynamically link to the deprecated pre-Lion capture APIs. |
| 689 std::string app_services_library_error; |
| 690 FilePath app_services_path(kApplicationServicesLibraryName); |
| 691 app_services_library_.Reset( |
| 692 base::LoadNativeLibrary(app_services_path, &app_services_library_error)); |
| 693 CHECK(app_services_library_.is_valid()) << app_services_library_error; |
| 694 |
| 695 std::string opengl_library_error; |
| 696 FilePath opengl_path(kOpenGlLibraryName); |
| 697 opengl_library_.Reset( |
| 698 base::LoadNativeLibrary(opengl_path, &opengl_library_error)); |
| 699 CHECK(opengl_library_.is_valid()) << opengl_library_error; |
| 700 |
| 701 cg_display_base_address_ = reinterpret_cast<CGDisplayBaseAddressFunc>( |
| 702 app_services_library_.GetFunctionPointer("CGDisplayBaseAddress")); |
| 703 cg_display_bytes_per_row_ = reinterpret_cast<CGDisplayBytesPerRowFunc>( |
| 704 app_services_library_.GetFunctionPointer("CGDisplayBytesPerRow")); |
| 705 cg_display_bits_per_pixel_ = reinterpret_cast<CGDisplayBitsPerPixelFunc>( |
| 706 app_services_library_.GetFunctionPointer("CGDisplayBitsPerPixel")); |
| 707 cgl_set_full_screen_ = reinterpret_cast<CGLSetFullScreenFunc>( |
| 708 opengl_library_.GetFunctionPointer("CGLSetFullScreen")); |
| 709 CHECK(cg_display_base_address_ && cg_display_bytes_per_row_ && |
| 710 cg_display_bits_per_pixel_ && cgl_set_full_screen_); |
| 711 |
| 656 if (display_ids_.size() > 1) { | 712 if (display_ids_.size() > 1) { |
| 657 LOG(INFO) << "Using CgBlitPreLion (Multi-monitor)."; | 713 LOG(INFO) << "Using CgBlitPreLion (Multi-monitor)."; |
| 658 return; | 714 return; |
| 659 } | 715 } |
| 660 | 716 |
| 661 CGDirectDisplayID mainDevice = CGMainDisplayID(); | 717 CGDirectDisplayID mainDevice = CGMainDisplayID(); |
| 662 if (!CGDisplayUsesOpenGLAcceleration(mainDevice)) { | 718 if (!CGDisplayUsesOpenGLAcceleration(mainDevice)) { |
| 663 LOG(INFO) << "Using CgBlitPreLion (OpenGL unavailable)."; | 719 LOG(INFO) << "Using CgBlitPreLion (OpenGL unavailable)."; |
| 664 return; | 720 return; |
| 665 } | 721 } |
| 666 | 722 |
| 667 LOG(INFO) << "Using GlBlit"; | 723 LOG(INFO) << "Using GlBlit"; |
| 668 | 724 |
| 669 CGLPixelFormatAttribute attributes[] = { | 725 CGLPixelFormatAttribute attributes[] = { |
| 670 kCGLPFAFullScreen, | 726 kCGLPFAFullScreen, |
| 671 kCGLPFADisplayMask, | 727 kCGLPFADisplayMask, |
| 672 (CGLPixelFormatAttribute)CGDisplayIDToOpenGLDisplayMask(mainDevice), | 728 (CGLPixelFormatAttribute)CGDisplayIDToOpenGLDisplayMask(mainDevice), |
| 673 (CGLPixelFormatAttribute)0 | 729 (CGLPixelFormatAttribute)0 |
| 674 }; | 730 }; |
| 675 CGLPixelFormatObj pixel_format = NULL; | 731 CGLPixelFormatObj pixel_format = NULL; |
| 676 GLint matching_pixel_format_count = 0; | 732 GLint matching_pixel_format_count = 0; |
| 677 CGLError err = CGLChoosePixelFormat(attributes, | 733 CGLError err = CGLChoosePixelFormat(attributes, |
| 678 &pixel_format, | 734 &pixel_format, |
| 679 &matching_pixel_format_count); | 735 &matching_pixel_format_count); |
| 680 DCHECK_EQ(err, kCGLNoError); | 736 DCHECK_EQ(err, kCGLNoError); |
| 681 err = CGLCreateContext(pixel_format, NULL, &cgl_context_); | 737 err = CGLCreateContext(pixel_format, NULL, &cgl_context_); |
| 682 DCHECK_EQ(err, kCGLNoError); | 738 DCHECK_EQ(err, kCGLNoError); |
| 683 CGLDestroyPixelFormat(pixel_format); | 739 CGLDestroyPixelFormat(pixel_format); |
| 684 #pragma clang diagnostic push | 740 (*cgl_set_full_screen_)(cgl_context_); |
| 685 #pragma clang diagnostic ignored "-Wdeprecated-declarations" | |
| 686 // TODO(jamiewalch): The non-deprecated equivalent code is shown below, but | |
| 687 // it causes 10.6 Macs' displays to go black. Find out why. | |
| 688 // | |
| 689 // CGLSetFullScreenOnDisplay(cgl_context_, | |
| 690 // CGDisplayIDToOpenGLDisplayMask(mainDevice)); | |
| 691 CGLSetFullScreen(cgl_context_); | |
| 692 #pragma clang diagnostic pop | |
| 693 CGLSetCurrentContext(cgl_context_); | 741 CGLSetCurrentContext(cgl_context_); |
| 694 | 742 |
| 695 size_t buffer_size = desktop_bounds_.width() * desktop_bounds_.height() * | 743 size_t buffer_size = desktop_bounds_.width() * desktop_bounds_.height() * |
| 696 sizeof(uint32_t); | 744 sizeof(uint32_t); |
| 697 pixel_buffer_object_.Init(cgl_context_, buffer_size); | 745 pixel_buffer_object_.Init(cgl_context_, buffer_size); |
| 698 } | 746 } |
| 699 | 747 |
| 700 void VideoFrameCapturerMac::ScreenRefresh(CGRectCount count, | 748 void VideoFrameCapturerMac::ScreenRefresh(CGRectCount count, |
| 701 const CGRect* rect_array) { | 749 const CGRect* rect_array) { |
| 702 SkIRect skirect_array[count]; | 750 SkIRect skirect_array[count]; |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 776 VideoFrameCapturer* VideoFrameCapturer::Create() { | 824 VideoFrameCapturer* VideoFrameCapturer::Create() { |
| 777 VideoFrameCapturerMac* capturer = new VideoFrameCapturerMac(); | 825 VideoFrameCapturerMac* capturer = new VideoFrameCapturerMac(); |
| 778 if (!capturer->Init()) { | 826 if (!capturer->Init()) { |
| 779 delete capturer; | 827 delete capturer; |
| 780 capturer = NULL; | 828 capturer = NULL; |
| 781 } | 829 } |
| 782 return capturer; | 830 return capturer; |
| 783 } | 831 } |
| 784 | 832 |
| 785 } // namespace remoting | 833 } // namespace remoting |
| OLD | NEW |