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 |