Chromium Code Reviews| 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 "ApplicationServices.framework/ApplicationServices"; | |
| 36 typedef void* (*CGDisplayBaseAddressFunc)(CGDirectDisplayID); | |
| 37 typedef size_t (*CGDisplayBytesPerRowFunc)(CGDirectDisplayID); | |
| 38 typedef size_t (*CGDisplayBitsPerPixelFunc)(CGDirectDisplayID); | |
| 39 const char* kOpenGlLibraryName = "OpenGL.framework/OpenGL"; | |
| 40 typedef CGLError (*CGLSetFullScreenFunc)(CGLContextObj); | |
| 41 | |
| 31 // skia/ext/skia_utils_mac.h only defines CGRectToSkRect(). | 42 // skia/ext/skia_utils_mac.h only defines CGRectToSkRect(). |
| 32 SkIRect CGRectToSkIRect(const CGRect& rect) { | 43 SkIRect CGRectToSkIRect(const CGRect& rect) { |
| 33 SkIRect sk_rect = { | 44 SkIRect sk_rect = { |
| 34 SkScalarRound(rect.origin.x), | 45 SkScalarRound(rect.origin.x), |
| 35 SkScalarRound(rect.origin.y), | 46 SkScalarRound(rect.origin.y), |
| 36 SkScalarRound(rect.origin.x + rect.size.width), | 47 SkScalarRound(rect.origin.x + rect.size.width), |
| 37 SkScalarRound(rect.origin.y + rect.size.height) | 48 SkScalarRound(rect.origin.y + rect.size.height) |
| 38 }; | 49 }; |
| 39 return sk_rect; | 50 return sk_rect; |
| 40 } | 51 } |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 175 // Acts as a critical section around our display configuration data | 186 // Acts as a critical section around our display configuration data |
| 176 // structures. Specifically cgl_context_ and pixel_buffer_object_. | 187 // structures. Specifically cgl_context_ and pixel_buffer_object_. |
| 177 base::WaitableEvent display_configuration_capture_event_; | 188 base::WaitableEvent display_configuration_capture_event_; |
| 178 | 189 |
| 179 // Power management assertion to prevent the screen from sleeping. | 190 // Power management assertion to prevent the screen from sleeping. |
| 180 IOPMAssertionID power_assertion_id_display_; | 191 IOPMAssertionID power_assertion_id_display_; |
| 181 | 192 |
| 182 // Power management assertion to indicate that the user is active. | 193 // Power management assertion to indicate that the user is active. |
| 183 IOPMAssertionID power_assertion_id_user_; | 194 IOPMAssertionID power_assertion_id_user_; |
| 184 | 195 |
| 196 // Dynamically link to deprecated APIs for Mac OS X 10.6 support. | |
| 197 base::ScopedNativeLibrary app_services_library_; | |
| 198 CGDisplayBaseAddressFunc cg_display_base_address_; | |
| 199 CGDisplayBytesPerRowFunc cg_display_bytes_per_row_; | |
| 200 CGDisplayBitsPerPixelFunc cg_display_bits_per_pixel_; | |
| 201 base::ScopedNativeLibrary opengl_library_; | |
| 202 CGLSetFullScreenFunc cgl_set_full_screen_; | |
| 203 | |
| 185 DISALLOW_COPY_AND_ASSIGN(VideoFrameCapturerMac); | 204 DISALLOW_COPY_AND_ASSIGN(VideoFrameCapturerMac); |
| 186 }; | 205 }; |
| 187 | 206 |
| 188 VideoFrameCapturerMac::VideoFrameCapturerMac() | 207 VideoFrameCapturerMac::VideoFrameCapturerMac() |
| 189 : cgl_context_(NULL), | 208 : cgl_context_(NULL), |
| 190 current_buffer_(0), | 209 current_buffer_(0), |
| 191 last_buffer_(NULL), | 210 last_buffer_(NULL), |
| 192 pixel_format_(media::VideoFrame::RGB32), | 211 pixel_format_(media::VideoFrame::RGB32), |
| 193 display_configuration_capture_event_(false, true), | 212 display_configuration_capture_event_(false, true), |
| 194 power_assertion_id_display_(kIOPMNullAssertionID), | 213 power_assertion_id_display_(kIOPMNullAssertionID), |
| 195 power_assertion_id_user_(kIOPMNullAssertionID) { | 214 power_assertion_id_user_(kIOPMNullAssertionID), |
| 215 cg_display_base_address_(NULL), | |
| 216 cg_display_bytes_per_row_(NULL), | |
| 217 cg_display_bits_per_pixel_(NULL), | |
| 218 cgl_set_full_screen_(NULL) | |
| 219 { | |
| 196 } | 220 } |
| 197 | 221 |
| 198 VideoFrameCapturerMac::~VideoFrameCapturerMac() { | 222 VideoFrameCapturerMac::~VideoFrameCapturerMac() { |
| 199 ReleaseBuffers(); | 223 ReleaseBuffers(); |
| 200 CGUnregisterScreenRefreshCallback( | 224 CGUnregisterScreenRefreshCallback( |
| 201 VideoFrameCapturerMac::ScreenRefreshCallback, this); | 225 VideoFrameCapturerMac::ScreenRefreshCallback, this); |
| 202 CGScreenUnregisterMoveCallback( | 226 CGScreenUnregisterMoveCallback( |
| 203 VideoFrameCapturerMac::ScreenUpdateMoveCallback, this); | 227 VideoFrameCapturerMac::ScreenUpdateMoveCallback, this); |
| 204 CGError err = CGDisplayRemoveReconfigurationCallback( | 228 CGError err = CGDisplayRemoveReconfigurationCallback( |
| 205 VideoFrameCapturerMac::DisplaysReconfiguredCallback, this); | 229 VideoFrameCapturerMac::DisplaysReconfiguredCallback, this); |
| (...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 506 GL_BGRA, GL_UNSIGNED_BYTE, buffer.ptr()); | 530 GL_BGRA, GL_UNSIGNED_BYTE, buffer.ptr()); |
| 507 glPopClientAttrib(); | 531 glPopClientAttrib(); |
| 508 } | 532 } |
| 509 | 533 |
| 510 void VideoFrameCapturerMac::CgBlitPreLion(const VideoFrameBuffer& buffer, | 534 void VideoFrameCapturerMac::CgBlitPreLion(const VideoFrameBuffer& buffer, |
| 511 const SkRegion& region) { | 535 const SkRegion& region) { |
| 512 const int buffer_height = buffer.size().height(); | 536 const int buffer_height = buffer.size().height(); |
| 513 | 537 |
| 514 // Copy the entire contents of the previous capture buffer, to capture over. | 538 // 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 | 539 // TODO(wez): Get rid of this as per crbug.com/145064, or implement |
| 516 // crbug.com/92354. | 540 // crbug.com/92354. |
|
Nico
2012/09/06 21:12:19
Can this comment be updated?
Wez
2012/09/06 21:59:07
The changes in this CL don't affect whether we nee
| |
| 517 if (last_buffer_) | 541 if (last_buffer_) |
| 518 memcpy(buffer.ptr(), last_buffer_, buffer.bytes_per_row() * buffer_height); | 542 memcpy(buffer.ptr(), last_buffer_, buffer.bytes_per_row() * buffer_height); |
| 519 last_buffer_ = buffer.ptr(); | 543 last_buffer_ = buffer.ptr(); |
| 520 | 544 |
| 521 for (unsigned int d = 0; d < display_ids_.size(); ++d) { | 545 for (unsigned int d = 0; d < display_ids_.size(); ++d) { |
| 522 #pragma clang diagnostic push | 546 // Use deprecated APIs to determine the display buffer layout. |
|
Nico
2012/09/06 21:12:19
// because the replacement APIs exist on 10.6, but
Wez
2012/09/06 21:59:07
This is the original capture code; we don't have a
| |
| 523 #pragma clang diagnostic ignored "-Wdeprecated-declarations" | 547 DCHECK(cg_display_base_address_ && cg_display_bytes_per_row_ && |
| 548 cg_display_bits_per_pixel_); | |
| 524 uint8* display_base_address = | 549 uint8* display_base_address = |
| 525 reinterpret_cast<uint8*>(CGDisplayBaseAddress(display_ids_[d])); | 550 reinterpret_cast<uint8*>((*cg_display_base_address_)(display_ids_[d])); |
| 526 CHECK(display_base_address); | 551 CHECK(display_base_address); |
| 527 int src_bytes_per_row = CGDisplayBytesPerRow(display_ids_[d]); | 552 int src_bytes_per_row = (*cg_display_bytes_per_row_)(display_ids_[d]); |
| 528 int src_bytes_per_pixel = CGDisplayBitsPerPixel(display_ids_[d]) / 8; | 553 int src_bytes_per_pixel = |
| 529 #pragma clang diagnostic pop | 554 (*cg_display_bits_per_pixel_)(display_ids_[d]) / 8; |
| 555 | |
| 530 // Determine the position of the display in the buffer. | 556 // Determine the position of the display in the buffer. |
| 531 SkIRect display_bounds = CGRectToSkIRect(CGDisplayBounds(display_ids_[d])); | 557 SkIRect display_bounds = CGRectToSkIRect(CGDisplayBounds(display_ids_[d])); |
| 532 display_bounds.offset(-desktop_bounds_.left(), -desktop_bounds_.top()); | 558 display_bounds.offset(-desktop_bounds_.left(), -desktop_bounds_.top()); |
| 533 | 559 |
| 534 // Determine which parts of the blit region, if any, lay within the monitor. | 560 // Determine which parts of the blit region, if any, lay within the monitor. |
| 535 SkRegion copy_region; | 561 SkRegion copy_region; |
| 536 if (!copy_region.op(region, display_bounds, SkRegion::kIntersect_Op)) | 562 if (!copy_region.op(region, display_bounds, SkRegion::kIntersect_Op)) |
| 537 continue; | 563 continue; |
| 538 | 564 |
| 539 // Translate the region to be copied into display-relative coordinates. | 565 // Translate the region to be copied into display-relative coordinates. |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 646 // Re-mark the entire desktop as dirty. | 672 // Re-mark the entire desktop as dirty. |
| 647 helper_.InvalidateScreen(SkISize::Make(desktop_bounds_.width(), | 673 helper_.InvalidateScreen(SkISize::Make(desktop_bounds_.width(), |
| 648 desktop_bounds_.height())); | 674 desktop_bounds_.height())); |
| 649 | 675 |
| 650 if (base::mac::IsOSLionOrLater()) { | 676 if (base::mac::IsOSLionOrLater()) { |
| 651 LOG(INFO) << "Using CgBlitPostLion."; | 677 LOG(INFO) << "Using CgBlitPostLion."; |
| 652 // No need for any OpenGL support on Lion | 678 // No need for any OpenGL support on Lion |
| 653 return; | 679 return; |
| 654 } | 680 } |
| 655 | 681 |
| 682 // Dynamically link to the deprecated pre-Lion capture APIs. | |
| 683 FilePath app_services_path(kApplicationServicesLibraryName); | |
| 684 app_services_library_.Reset(base::LoadNativeLibrary(app_services_path, NULL)); | |
|
Jamie
2012/09/06 21:41:50
Pass a string for error logging?
Wez
2012/09/07 00:17:51
Seems overkill in this case, but OK...
| |
| 685 FilePath opengl_path(kOpenGlLibraryName); | |
|
Nico
2012/09/06 21:12:19
http://code.google.com/searchframe#OAMlx_jo-ck/src
Wez
2012/09/06 21:59:07
Won't that break things if the locations of those
| |
| 686 opengl_library_.Reset(base::LoadNativeLibrary(opengl_path, NULL)); | |
| 687 CHECK(app_services_library_.is_valid() && opengl_library_.is_valid()); | |
| 688 | |
| 689 cg_display_base_address_ = reinterpret_cast<CGDisplayBaseAddressFunc>( | |
| 690 app_services_library_.GetFunctionPointer("CGDisplayBaseAddress")); | |
| 691 cg_display_bytes_per_row_ = reinterpret_cast<CGDisplayBytesPerRowFunc>( | |
| 692 app_services_library_.GetFunctionPointer("CGDisplayBytesPerRow")); | |
| 693 cg_display_bits_per_pixel_ = reinterpret_cast<CGDisplayBitsPerPixelFunc>( | |
| 694 app_services_library_.GetFunctionPointer("CGDisplayBitsPerPixel")); | |
| 695 cgl_set_full_screen_ = reinterpret_cast<CGLSetFullScreenFunc>( | |
| 696 opengl_library_.GetFunctionPointer("CGLSetFullScreen")); | |
| 697 CHECK(cg_display_base_address_ && cg_display_bytes_per_row_ && | |
| 698 cg_display_bits_per_pixel_ && cgl_set_full_screen_); | |
| 699 | |
| 656 if (display_ids_.size() > 1) { | 700 if (display_ids_.size() > 1) { |
| 657 LOG(INFO) << "Using CgBlitPreLion (Multi-monitor)."; | 701 LOG(INFO) << "Using CgBlitPreLion (Multi-monitor)."; |
| 658 return; | 702 return; |
| 659 } | 703 } |
| 660 | 704 |
| 661 CGDirectDisplayID mainDevice = CGMainDisplayID(); | 705 CGDirectDisplayID mainDevice = CGMainDisplayID(); |
| 662 if (!CGDisplayUsesOpenGLAcceleration(mainDevice)) { | 706 if (!CGDisplayUsesOpenGLAcceleration(mainDevice)) { |
| 663 LOG(INFO) << "Using CgBlitPreLion (OpenGL unavailable)."; | 707 LOG(INFO) << "Using CgBlitPreLion (OpenGL unavailable)."; |
| 664 return; | 708 return; |
| 665 } | 709 } |
| 666 | 710 |
| 667 LOG(INFO) << "Using GlBlit"; | 711 LOG(INFO) << "Using GlBlit"; |
| 668 | 712 |
| 669 CGLPixelFormatAttribute attributes[] = { | 713 CGLPixelFormatAttribute attributes[] = { |
| 670 kCGLPFAFullScreen, | 714 kCGLPFAFullScreen, |
| 671 kCGLPFADisplayMask, | 715 kCGLPFADisplayMask, |
| 672 (CGLPixelFormatAttribute)CGDisplayIDToOpenGLDisplayMask(mainDevice), | 716 (CGLPixelFormatAttribute)CGDisplayIDToOpenGLDisplayMask(mainDevice), |
| 673 (CGLPixelFormatAttribute)0 | 717 (CGLPixelFormatAttribute)0 |
| 674 }; | 718 }; |
| 675 CGLPixelFormatObj pixel_format = NULL; | 719 CGLPixelFormatObj pixel_format = NULL; |
| 676 GLint matching_pixel_format_count = 0; | 720 GLint matching_pixel_format_count = 0; |
| 677 CGLError err = CGLChoosePixelFormat(attributes, | 721 CGLError err = CGLChoosePixelFormat(attributes, |
| 678 &pixel_format, | 722 &pixel_format, |
| 679 &matching_pixel_format_count); | 723 &matching_pixel_format_count); |
| 680 DCHECK_EQ(err, kCGLNoError); | 724 DCHECK_EQ(err, kCGLNoError); |
| 681 err = CGLCreateContext(pixel_format, NULL, &cgl_context_); | 725 err = CGLCreateContext(pixel_format, NULL, &cgl_context_); |
| 682 DCHECK_EQ(err, kCGLNoError); | 726 DCHECK_EQ(err, kCGLNoError); |
| 683 CGLDestroyPixelFormat(pixel_format); | 727 CGLDestroyPixelFormat(pixel_format); |
| 684 #pragma clang diagnostic push | 728 (*cgl_set_full_screen_)(cgl_context_); |
|
Jamie
2012/09/06 21:41:50
I think it's worth preserving the TODO in some for
Wez
2012/09/07 00:17:51
We'll never use the new API, though; it's crashy o
| |
| 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_); | 729 CGLSetCurrentContext(cgl_context_); |
| 694 | 730 |
| 695 size_t buffer_size = desktop_bounds_.width() * desktop_bounds_.height() * | 731 size_t buffer_size = desktop_bounds_.width() * desktop_bounds_.height() * |
| 696 sizeof(uint32_t); | 732 sizeof(uint32_t); |
| 697 pixel_buffer_object_.Init(cgl_context_, buffer_size); | 733 pixel_buffer_object_.Init(cgl_context_, buffer_size); |
| 698 } | 734 } |
| 699 | 735 |
| 700 void VideoFrameCapturerMac::ScreenRefresh(CGRectCount count, | 736 void VideoFrameCapturerMac::ScreenRefresh(CGRectCount count, |
| 701 const CGRect* rect_array) { | 737 const CGRect* rect_array) { |
| 702 SkIRect skirect_array[count]; | 738 SkIRect skirect_array[count]; |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 776 VideoFrameCapturer* VideoFrameCapturer::Create() { | 812 VideoFrameCapturer* VideoFrameCapturer::Create() { |
| 777 VideoFrameCapturerMac* capturer = new VideoFrameCapturerMac(); | 813 VideoFrameCapturerMac* capturer = new VideoFrameCapturerMac(); |
| 778 if (!capturer->Init()) { | 814 if (!capturer->Init()) { |
| 779 delete capturer; | 815 delete capturer; |
| 780 capturer = NULL; | 816 capturer = NULL; |
| 781 } | 817 } |
| 782 return capturer; | 818 return capturer; |
| 783 } | 819 } |
| 784 | 820 |
| 785 } // namespace remoting | 821 } // namespace remoting |
| OLD | NEW |