| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 #include "webrtc/modules/desktop_capture/screen_capturer.h" | 11 #include "webrtc/modules/desktop_capture/screen_capturer.h" |
| 12 | 12 |
| 13 #include <stddef.h> | 13 #include <stddef.h> |
| 14 | 14 |
| 15 #include <memory> | 15 #include <memory> |
| 16 #include <set> | 16 #include <set> |
| 17 | 17 |
| 18 #include <ApplicationServices/ApplicationServices.h> | 18 #include <ApplicationServices/ApplicationServices.h> |
| 19 #include <Cocoa/Cocoa.h> | 19 #include <Cocoa/Cocoa.h> |
| 20 #include <dlfcn.h> | 20 #include <dlfcn.h> |
| 21 #include <IOKit/pwr_mgt/IOPMLib.h> | 21 #include <IOKit/pwr_mgt/IOPMLib.h> |
| 22 #include <OpenGL/CGLMacro.h> | 22 #include <OpenGL/CGLMacro.h> |
| 23 #include <OpenGL/OpenGL.h> | 23 #include <OpenGL/OpenGL.h> |
| 24 | 24 |
| 25 #include "webrtc/base/checks.h" |
| 25 #include "webrtc/base/macutils.h" | 26 #include "webrtc/base/macutils.h" |
| 26 #include "webrtc/modules/desktop_capture/desktop_capture_options.h" | 27 #include "webrtc/modules/desktop_capture/desktop_capture_options.h" |
| 27 #include "webrtc/modules/desktop_capture/desktop_frame.h" | 28 #include "webrtc/modules/desktop_capture/desktop_frame.h" |
| 28 #include "webrtc/modules/desktop_capture/desktop_geometry.h" | 29 #include "webrtc/modules/desktop_capture/desktop_geometry.h" |
| 29 #include "webrtc/modules/desktop_capture/desktop_region.h" | 30 #include "webrtc/modules/desktop_capture/desktop_region.h" |
| 30 #include "webrtc/modules/desktop_capture/mac/desktop_configuration.h" | 31 #include "webrtc/modules/desktop_capture/mac/desktop_configuration.h" |
| 31 #include "webrtc/modules/desktop_capture/mac/desktop_configuration_monitor.h" | 32 #include "webrtc/modules/desktop_capture/mac/desktop_configuration_monitor.h" |
| 32 #include "webrtc/modules/desktop_capture/mac/scoped_pixel_buffer_object.h" | 33 #include "webrtc/modules/desktop_capture/mac/scoped_pixel_buffer_object.h" |
| 33 #include "webrtc/modules/desktop_capture/screen_capture_frame_queue.h" | 34 #include "webrtc/modules/desktop_capture/screen_capture_queue.h" |
| 34 #include "webrtc/modules/desktop_capture/screen_capturer_helper.h" | 35 #include "webrtc/modules/desktop_capture/screen_capturer_helper.h" |
| 36 #include "webrtc/modules/desktop_capture/shared_desktop_frame.h" |
| 35 #include "webrtc/system_wrappers/include/logging.h" | 37 #include "webrtc/system_wrappers/include/logging.h" |
| 36 #include "webrtc/system_wrappers/include/tick_util.h" | 38 #include "webrtc/system_wrappers/include/tick_util.h" |
| 37 | 39 |
| 38 namespace webrtc { | 40 namespace webrtc { |
| 39 | 41 |
| 40 namespace { | 42 namespace { |
| 41 | 43 |
| 42 // Definitions used to dynamic-link to deprecated OS 10.6 functions. | 44 // Definitions used to dynamic-link to deprecated OS 10.6 functions. |
| 43 const char* kApplicationServicesLibraryName = | 45 const char* kApplicationServicesLibraryName = |
| 44 "/System/Library/Frameworks/ApplicationServices.framework/" | 46 "/System/Library/Frameworks/ApplicationServices.framework/" |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 219 const CGRect *rect_array); | 221 const CGRect *rect_array); |
| 220 static void ScreenRefreshCallback(CGRectCount count, | 222 static void ScreenRefreshCallback(CGRectCount count, |
| 221 const CGRect *rect_array, | 223 const CGRect *rect_array, |
| 222 void *user_parameter); | 224 void *user_parameter); |
| 223 static void ScreenUpdateMoveCallback(CGScreenUpdateMoveDelta delta, | 225 static void ScreenUpdateMoveCallback(CGScreenUpdateMoveDelta delta, |
| 224 size_t count, | 226 size_t count, |
| 225 const CGRect *rect_array, | 227 const CGRect *rect_array, |
| 226 void *user_parameter); | 228 void *user_parameter); |
| 227 void ReleaseBuffers(); | 229 void ReleaseBuffers(); |
| 228 | 230 |
| 229 DesktopFrame* CreateFrame(); | 231 std::unique_ptr<DesktopFrame> CreateFrame(); |
| 230 | 232 |
| 231 Callback* callback_; | 233 Callback* callback_; |
| 232 | 234 |
| 233 CGLContextObj cgl_context_; | 235 CGLContextObj cgl_context_; |
| 234 ScopedPixelBufferObject pixel_buffer_object_; | 236 ScopedPixelBufferObject pixel_buffer_object_; |
| 235 | 237 |
| 236 // Queue of the frames buffers. | 238 // Queue of the frames buffers. |
| 237 ScreenCaptureFrameQueue queue_; | 239 ScreenCaptureQueue<SharedDesktopFrame> queue_; |
| 238 | 240 |
| 239 // Current display configuration. | 241 // Current display configuration. |
| 240 MacDesktopConfiguration desktop_config_; | 242 MacDesktopConfiguration desktop_config_; |
| 241 | 243 |
| 242 // Currently selected display, or 0 if the full desktop is selected. On OS X | 244 // Currently selected display, or 0 if the full desktop is selected. On OS X |
| 243 // 10.6 and before, this is always 0. | 245 // 10.6 and before, this is always 0. |
| 244 CGDirectDisplayID current_display_; | 246 CGDirectDisplayID current_display_; |
| 245 | 247 |
| 246 // The physical pixel bounds of the current screen. | 248 // The physical pixel bounds of the current screen. |
| 247 DesktopRect screen_pixel_bounds_; | 249 DesktopRect screen_pixel_bounds_; |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 376 // (as used by Apple Remote Desktop). | 378 // (as used by Apple Remote Desktop). |
| 377 IOPMAssertionCreateWithName(CFSTR("UserIsActive"), | 379 IOPMAssertionCreateWithName(CFSTR("UserIsActive"), |
| 378 kIOPMAssertionLevelOn, | 380 kIOPMAssertionLevelOn, |
| 379 CFSTR("Chrome Remote Desktop connection active"), | 381 CFSTR("Chrome Remote Desktop connection active"), |
| 380 &power_assertion_id_user_); | 382 &power_assertion_id_user_); |
| 381 } | 383 } |
| 382 | 384 |
| 383 void ScreenCapturerMac::Capture(const DesktopRegion& region_to_capture) { | 385 void ScreenCapturerMac::Capture(const DesktopRegion& region_to_capture) { |
| 384 TickTime capture_start_time = TickTime::Now(); | 386 TickTime capture_start_time = TickTime::Now(); |
| 385 | 387 |
| 386 queue_.MoveToNextFrame(); | 388 queue_.MoveToNext(); |
| 389 RTC_DCHECK(!queue_.current() || !queue_.current()->IsShared()); |
| 387 | 390 |
| 388 desktop_config_monitor_->Lock(); | 391 desktop_config_monitor_->Lock(); |
| 389 MacDesktopConfiguration new_config = | 392 MacDesktopConfiguration new_config = |
| 390 desktop_config_monitor_->desktop_configuration(); | 393 desktop_config_monitor_->desktop_configuration(); |
| 391 if (!desktop_config_.Equals(new_config)) { | 394 if (!desktop_config_.Equals(new_config)) { |
| 392 desktop_config_ = new_config; | 395 desktop_config_ = new_config; |
| 393 // If the display configuraiton has changed then refresh capturer data | 396 // If the display configuraiton has changed then refresh capturer data |
| 394 // structures. Occasionally, the refresh and move handlers are lost when | 397 // structures. Occasionally, the refresh and move handlers are lost when |
| 395 // the screen mode changes, so re-register them here. | 398 // the screen mode changes, so re-register them here. |
| 396 UnregisterRefreshAndMoveHandlers(); | 399 UnregisterRefreshAndMoveHandlers(); |
| 397 RegisterRefreshAndMoveHandlers(); | 400 RegisterRefreshAndMoveHandlers(); |
| 398 ScreenConfigurationChanged(); | 401 ScreenConfigurationChanged(); |
| 399 } | 402 } |
| 400 | 403 |
| 401 DesktopRegion region; | 404 DesktopRegion region; |
| 402 helper_.TakeInvalidRegion(®ion); | 405 helper_.TakeInvalidRegion(®ion); |
| 403 | 406 |
| 404 // If the current buffer is from an older generation then allocate a new one. | 407 // If the current buffer is from an older generation then allocate a new one. |
| 405 // Note that we can't reallocate other buffers at this point, since the caller | 408 // Note that we can't reallocate other buffers at this point, since the caller |
| 406 // may still be reading from them. | 409 // may still be reading from them. |
| 407 if (!queue_.current_frame()) | 410 if (!queue_.current()) |
| 408 queue_.ReplaceCurrentFrame(CreateFrame()); | 411 queue_.ReplaceCurrent(SharedDesktopFrame::Wrap(CreateFrame())); |
| 409 | 412 |
| 410 DesktopFrame* current_frame = queue_.current_frame(); | 413 DesktopFrame* current_frame = queue_.current(); |
| 411 | 414 |
| 412 bool flip = false; // GL capturers need flipping. | 415 bool flip = false; // GL capturers need flipping. |
| 413 if (rtc::GetOSVersionName() >= rtc::kMacOSLion) { | 416 if (rtc::GetOSVersionName() >= rtc::kMacOSLion) { |
| 414 // Lion requires us to use their new APIs for doing screen capture. These | 417 // Lion requires us to use their new APIs for doing screen capture. These |
| 415 // APIS currently crash on 10.6.8 if there is no monitor attached. | 418 // APIS currently crash on 10.6.8 if there is no monitor attached. |
| 416 if (!CgBlitPostLion(*current_frame, region)) { | 419 if (!CgBlitPostLion(*current_frame, region)) { |
| 417 desktop_config_monitor_->Unlock(); | 420 desktop_config_monitor_->Unlock(); |
| 418 callback_->OnCaptureCompleted(NULL); | 421 callback_->OnCaptureCompleted(NULL); |
| 419 return; | 422 return; |
| 420 } | 423 } |
| 421 } else if (cgl_context_) { | 424 } else if (cgl_context_) { |
| 422 flip = true; | 425 flip = true; |
| 423 if (pixel_buffer_object_.get() != 0) { | 426 if (pixel_buffer_object_.get() != 0) { |
| 424 GlBlitFast(*current_frame, region); | 427 GlBlitFast(*current_frame, region); |
| 425 } else { | 428 } else { |
| 426 // See comment in ScopedPixelBufferObject::Init about why the slow | 429 // See comment in ScopedPixelBufferObject::Init about why the slow |
| 427 // path is always used on 10.5. | 430 // path is always used on 10.5. |
| 428 GlBlitSlow(*current_frame); | 431 GlBlitSlow(*current_frame); |
| 429 } | 432 } |
| 430 } else { | 433 } else { |
| 431 CgBlitPreLion(*current_frame, region); | 434 CgBlitPreLion(*current_frame, region); |
| 432 } | 435 } |
| 433 | 436 |
| 434 DesktopFrame* new_frame = queue_.current_frame()->Share(); | 437 DesktopFrame* new_frame = queue_.current()->Share(); |
| 435 *new_frame->mutable_updated_region() = region; | 438 *new_frame->mutable_updated_region() = region; |
| 436 | 439 |
| 437 if (flip) | 440 if (flip) |
| 438 new_frame = new InvertedDesktopFrame(new_frame); | 441 new_frame = new InvertedDesktopFrame(new_frame); |
| 439 | 442 |
| 440 helper_.set_size_most_recent(new_frame->size()); | 443 helper_.set_size_most_recent(new_frame->size()); |
| 441 | 444 |
| 442 // Signal that we are done capturing data from the display framebuffer, | 445 // Signal that we are done capturing data from the display framebuffer, |
| 443 // and accessing display structures. | 446 // and accessing display structures. |
| 444 desktop_config_monitor_->Unlock(); | 447 desktop_config_monitor_->Unlock(); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 490 } | 493 } |
| 491 | 494 |
| 492 ScreenConfigurationChanged(); | 495 ScreenConfigurationChanged(); |
| 493 return true; | 496 return true; |
| 494 } | 497 } |
| 495 | 498 |
| 496 void ScreenCapturerMac::GlBlitFast(const DesktopFrame& frame, | 499 void ScreenCapturerMac::GlBlitFast(const DesktopFrame& frame, |
| 497 const DesktopRegion& region) { | 500 const DesktopRegion& region) { |
| 498 // Clip to the size of our current screen. | 501 // Clip to the size of our current screen. |
| 499 DesktopRect clip_rect = DesktopRect::MakeSize(frame.size()); | 502 DesktopRect clip_rect = DesktopRect::MakeSize(frame.size()); |
| 500 if (queue_.previous_frame()) { | 503 if (queue_.previous()) { |
| 501 // We are doing double buffer for the capture data so we just need to copy | 504 // We are doing double buffer for the capture data so we just need to copy |
| 502 // the invalid region from the previous capture in the current buffer. | 505 // the invalid region from the previous capture in the current buffer. |
| 503 // TODO(hclam): We can reduce the amount of copying here by subtracting | 506 // TODO(hclam): We can reduce the amount of copying here by subtracting |
| 504 // |capturer_helper_|s region from |last_invalid_region_|. | 507 // |capturer_helper_|s region from |last_invalid_region_|. |
| 505 // http://crbug.com/92354 | 508 // http://crbug.com/92354 |
| 506 | 509 |
| 507 // Since the image obtained from OpenGL is upside-down, need to do some | 510 // Since the image obtained from OpenGL is upside-down, need to do some |
| 508 // magic here to copy the correct rectangle. | 511 // magic here to copy the correct rectangle. |
| 509 const int y_offset = (frame.size().height() - 1) * frame.stride(); | 512 const int y_offset = (frame.size().height() - 1) * frame.stride(); |
| 510 for (DesktopRegion::Iterator i(last_invalid_region_); | 513 for (DesktopRegion::Iterator i(last_invalid_region_); |
| 511 !i.IsAtEnd(); i.Advance()) { | 514 !i.IsAtEnd(); i.Advance()) { |
| 512 DesktopRect copy_rect = i.rect(); | 515 DesktopRect copy_rect = i.rect(); |
| 513 copy_rect.IntersectWith(clip_rect); | 516 copy_rect.IntersectWith(clip_rect); |
| 514 if (!copy_rect.is_empty()) { | 517 if (!copy_rect.is_empty()) { |
| 515 CopyRect(queue_.previous_frame()->data() + y_offset, | 518 CopyRect(queue_.previous()->data() + y_offset, |
| 516 -frame.stride(), | 519 -frame.stride(), |
| 517 frame.data() + y_offset, | 520 frame.data() + y_offset, |
| 518 -frame.stride(), | 521 -frame.stride(), |
| 519 DesktopFrame::kBytesPerPixel, | 522 DesktopFrame::kBytesPerPixel, |
| 520 copy_rect); | 523 copy_rect); |
| 521 } | 524 } |
| 522 } | 525 } |
| 523 } | 526 } |
| 524 last_invalid_region_ = region; | 527 last_invalid_region_ = region; |
| 525 | 528 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 574 glReadPixels(0, 0, frame.size().width(), frame.size().height(), | 577 glReadPixels(0, 0, frame.size().width(), frame.size().height(), |
| 575 GL_BGRA, GL_UNSIGNED_BYTE, frame.data()); | 578 GL_BGRA, GL_UNSIGNED_BYTE, frame.data()); |
| 576 glPopClientAttrib(); | 579 glPopClientAttrib(); |
| 577 } | 580 } |
| 578 | 581 |
| 579 void ScreenCapturerMac::CgBlitPreLion(const DesktopFrame& frame, | 582 void ScreenCapturerMac::CgBlitPreLion(const DesktopFrame& frame, |
| 580 const DesktopRegion& region) { | 583 const DesktopRegion& region) { |
| 581 // Copy the entire contents of the previous capture buffer, to capture over. | 584 // Copy the entire contents of the previous capture buffer, to capture over. |
| 582 // TODO(wez): Get rid of this as per crbug.com/145064, or implement | 585 // TODO(wez): Get rid of this as per crbug.com/145064, or implement |
| 583 // crbug.com/92354. | 586 // crbug.com/92354. |
| 584 if (queue_.previous_frame()) { | 587 if (queue_.previous()) { |
| 585 memcpy(frame.data(), | 588 memcpy(frame.data(), |
| 586 queue_.previous_frame()->data(), | 589 queue_.previous()->data(), |
| 587 frame.stride() * frame.size().height()); | 590 frame.stride() * frame.size().height()); |
| 588 } | 591 } |
| 589 | 592 |
| 590 for (size_t i = 0; i < desktop_config_.displays.size(); ++i) { | 593 for (size_t i = 0; i < desktop_config_.displays.size(); ++i) { |
| 591 const MacDisplayConfiguration& display_config = desktop_config_.displays[i]; | 594 const MacDisplayConfiguration& display_config = desktop_config_.displays[i]; |
| 592 | 595 |
| 593 // Use deprecated APIs to determine the display buffer layout. | 596 // Use deprecated APIs to determine the display buffer layout. |
| 594 assert(cg_display_base_address_ && cg_display_bytes_per_row_ && | 597 assert(cg_display_base_address_ && cg_display_bytes_per_row_ && |
| 595 cg_display_bits_per_pixel_); | 598 cg_display_bits_per_pixel_); |
| 596 uint8_t* display_base_address = reinterpret_cast<uint8_t*>( | 599 uint8_t* display_base_address = reinterpret_cast<uint8_t*>( |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 629 i.rect()); | 632 i.rect()); |
| 630 } | 633 } |
| 631 } | 634 } |
| 632 } | 635 } |
| 633 | 636 |
| 634 bool ScreenCapturerMac::CgBlitPostLion(const DesktopFrame& frame, | 637 bool ScreenCapturerMac::CgBlitPostLion(const DesktopFrame& frame, |
| 635 const DesktopRegion& region) { | 638 const DesktopRegion& region) { |
| 636 // Copy the entire contents of the previous capture buffer, to capture over. | 639 // Copy the entire contents of the previous capture buffer, to capture over. |
| 637 // TODO(wez): Get rid of this as per crbug.com/145064, or implement | 640 // TODO(wez): Get rid of this as per crbug.com/145064, or implement |
| 638 // crbug.com/92354. | 641 // crbug.com/92354. |
| 639 if (queue_.previous_frame()) { | 642 if (queue_.previous()) { |
| 640 memcpy(frame.data(), | 643 memcpy(frame.data(), |
| 641 queue_.previous_frame()->data(), | 644 queue_.previous()->data(), |
| 642 frame.stride() * frame.size().height()); | 645 frame.stride() * frame.size().height()); |
| 643 } | 646 } |
| 644 | 647 |
| 645 MacDisplayConfigurations displays_to_capture; | 648 MacDisplayConfigurations displays_to_capture; |
| 646 if (current_display_) { | 649 if (current_display_) { |
| 647 // Capturing a single screen. Note that the screen id may change when | 650 // Capturing a single screen. Note that the screen id may change when |
| 648 // screens are added or removed. | 651 // screens are added or removed. |
| 649 const MacDisplayConfiguration* config = | 652 const MacDisplayConfiguration* config = |
| 650 desktop_config_.FindDisplayConfigurationById(current_display_); | 653 desktop_config_.FindDisplayConfigurationById(current_display_); |
| 651 if (config) { | 654 if (config) { |
| (...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 957 void ScreenCapturerMac::ScreenUpdateMoveCallback( | 960 void ScreenCapturerMac::ScreenUpdateMoveCallback( |
| 958 CGScreenUpdateMoveDelta delta, | 961 CGScreenUpdateMoveDelta delta, |
| 959 size_t count, | 962 size_t count, |
| 960 const CGRect* rect_array, | 963 const CGRect* rect_array, |
| 961 void* user_parameter) { | 964 void* user_parameter) { |
| 962 ScreenCapturerMac* capturer = | 965 ScreenCapturerMac* capturer = |
| 963 reinterpret_cast<ScreenCapturerMac*>(user_parameter); | 966 reinterpret_cast<ScreenCapturerMac*>(user_parameter); |
| 964 capturer->ScreenUpdateMove(delta, count, rect_array); | 967 capturer->ScreenUpdateMove(delta, count, rect_array); |
| 965 } | 968 } |
| 966 | 969 |
| 967 DesktopFrame* ScreenCapturerMac::CreateFrame() { | 970 std::unique_ptr<DesktopFrame> ScreenCapturerMac::CreateFrame() { |
| 968 std::unique_ptr<DesktopFrame> frame( | 971 std::unique_ptr<DesktopFrame> frame( |
| 969 new BasicDesktopFrame(screen_pixel_bounds_.size())); | 972 new BasicDesktopFrame(screen_pixel_bounds_.size())); |
| 970 | 973 |
| 971 frame->set_dpi(DesktopVector(kStandardDPI * dip_to_pixel_scale_, | 974 frame->set_dpi(DesktopVector(kStandardDPI * dip_to_pixel_scale_, |
| 972 kStandardDPI * dip_to_pixel_scale_)); | 975 kStandardDPI * dip_to_pixel_scale_)); |
| 973 return frame.release(); | 976 return frame; |
| 974 } | 977 } |
| 975 | 978 |
| 976 } // namespace | 979 } // namespace |
| 977 | 980 |
| 978 // static | 981 // static |
| 979 ScreenCapturer* ScreenCapturer::Create(const DesktopCaptureOptions& options) { | 982 ScreenCapturer* ScreenCapturer::Create(const DesktopCaptureOptions& options) { |
| 980 if (!options.configuration_monitor()) | 983 if (!options.configuration_monitor()) |
| 981 return NULL; | 984 return NULL; |
| 982 | 985 |
| 983 std::unique_ptr<ScreenCapturerMac> capturer( | 986 std::unique_ptr<ScreenCapturerMac> capturer( |
| 984 new ScreenCapturerMac(options.configuration_monitor())); | 987 new ScreenCapturerMac(options.configuration_monitor())); |
| 985 if (!capturer->Init()) | 988 if (!capturer->Init()) |
| 986 capturer.reset(); | 989 capturer.reset(); |
| 987 return capturer.release(); | 990 return capturer.release(); |
| 988 } | 991 } |
| 989 | 992 |
| 990 } // namespace webrtc | 993 } // namespace webrtc |
| OLD | NEW |