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 |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
161 rect.size.height += kBorderEffectSize * 2; | 161 rect.size.height += kBorderEffectSize * 2; |
162 // |rect| is in DIP, so convert to physical pixels. | 162 // |rect| is in DIP, so convert to physical pixels. |
163 return ScaleAndRoundCGRect(rect, dip_to_pixel_scale); | 163 return ScaleAndRoundCGRect(rect, dip_to_pixel_scale); |
164 } | 164 } |
165 | 165 |
166 // Create an image of the given region using the given |window_list|. | 166 // Create an image of the given region using the given |window_list|. |
167 // |pixel_bounds| should be in the primary display's coordinate in physical | 167 // |pixel_bounds| should be in the primary display's coordinate in physical |
168 // pixels. The caller should release the returned CGImageRef and CFDataRef. | 168 // pixels. The caller should release the returned CGImageRef and CFDataRef. |
169 CGImageRef CreateExcludedWindowRegionImage(const DesktopRect& pixel_bounds, | 169 CGImageRef CreateExcludedWindowRegionImage(const DesktopRect& pixel_bounds, |
170 float dip_to_pixel_scale, | 170 float dip_to_pixel_scale, |
171 CFArrayRef window_list, | 171 CFArrayRef window_list) { |
172 CFDataRef* data_ref) { | |
173 CGRect window_bounds; | 172 CGRect window_bounds; |
174 // The origin is in DIP while the size is in physical pixels. That's what | 173 // The origin is in DIP while the size is in physical pixels. That's what |
175 // CGWindowListCreateImageFromArray expects. | 174 // CGWindowListCreateImageFromArray expects. |
176 window_bounds.origin.x = pixel_bounds.left() / dip_to_pixel_scale; | 175 window_bounds.origin.x = pixel_bounds.left() / dip_to_pixel_scale; |
177 window_bounds.origin.y = pixel_bounds.top() / dip_to_pixel_scale; | 176 window_bounds.origin.y = pixel_bounds.top() / dip_to_pixel_scale; |
178 window_bounds.size.width = pixel_bounds.width(); | 177 window_bounds.size.width = pixel_bounds.width(); |
179 window_bounds.size.height = pixel_bounds.height(); | 178 window_bounds.size.height = pixel_bounds.height(); |
180 | 179 |
181 CGImageRef excluded_image = CGWindowListCreateImageFromArray( | 180 return CGWindowListCreateImageFromArray( |
182 window_bounds, window_list, kCGWindowImageDefault); | 181 window_bounds, window_list, kCGWindowImageDefault); |
183 | |
184 CGDataProviderRef provider = CGImageGetDataProvider(excluded_image); | |
185 *data_ref = CGDataProviderCopyData(provider); | |
186 assert(*data_ref); | |
187 return excluded_image; | |
188 } | 182 } |
189 | 183 |
190 // A class to perform video frame capturing for mac. | 184 // A class to perform video frame capturing for mac. |
191 class ScreenCapturerMac : public ScreenCapturer { | 185 class ScreenCapturerMac : public ScreenCapturer { |
192 public: | 186 public: |
193 explicit ScreenCapturerMac( | 187 explicit ScreenCapturerMac( |
194 rtc::scoped_refptr<DesktopConfigurationMonitor> desktop_config_monitor); | 188 rtc::scoped_refptr<DesktopConfigurationMonitor> desktop_config_monitor); |
195 virtual ~ScreenCapturerMac(); | 189 virtual ~ScreenCapturerMac(); |
196 | 190 |
197 bool Init(); | 191 bool Init(); |
(...skipping 489 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
687 DesktopRegion copy_region = region; | 681 DesktopRegion copy_region = region; |
688 copy_region.IntersectWith(display_bounds); | 682 copy_region.IntersectWith(display_bounds); |
689 if (copy_region.is_empty()) | 683 if (copy_region.is_empty()) |
690 continue; | 684 continue; |
691 | 685 |
692 // Translate the region to be copied into display-relative coordinates. | 686 // Translate the region to be copied into display-relative coordinates. |
693 copy_region.Translate(-display_bounds.left(), -display_bounds.top()); | 687 copy_region.Translate(-display_bounds.left(), -display_bounds.top()); |
694 | 688 |
695 DesktopRect excluded_window_bounds; | 689 DesktopRect excluded_window_bounds; |
696 CGImageRef excluded_image = NULL; | 690 CGImageRef excluded_image = NULL; |
697 CFDataRef excluded_window_region_data = NULL; | |
698 if (excluded_window_ && window_list) { | 691 if (excluded_window_ && window_list) { |
699 // Get the region of the excluded window relative the primary display. | 692 // Get the region of the excluded window relative the primary display. |
700 excluded_window_bounds = GetExcludedWindowPixelBounds( | 693 excluded_window_bounds = GetExcludedWindowPixelBounds( |
701 excluded_window_, display_config.dip_to_pixel_scale); | 694 excluded_window_, display_config.dip_to_pixel_scale); |
702 excluded_window_bounds.IntersectWith(display_config.pixel_bounds); | 695 excluded_window_bounds.IntersectWith(display_config.pixel_bounds); |
703 | 696 |
704 // Create the image under the excluded window first, because it's faster | 697 // Create the image under the excluded window first, because it's faster |
705 // than captuing the whole display. | 698 // than captuing the whole display. |
706 if (!excluded_window_bounds.is_empty()) { | 699 if (!excluded_window_bounds.is_empty()) { |
707 excluded_image = CreateExcludedWindowRegionImage( | 700 excluded_image = CreateExcludedWindowRegionImage( |
708 excluded_window_bounds, | 701 excluded_window_bounds, display_config.dip_to_pixel_scale, |
709 display_config.dip_to_pixel_scale, | 702 window_list); |
710 window_list, | |
711 &excluded_window_region_data); | |
712 } | 703 } |
713 } | 704 } |
714 | 705 |
715 // Create an image containing a snapshot of the display. | 706 // Create an image containing a snapshot of the display. |
716 CGImageRef image = CGDisplayCreateImage(display_config.id); | 707 CGImageRef image = CGDisplayCreateImage(display_config.id); |
717 if (image == NULL) | 708 if (image == NULL) { |
| 709 if (excluded_image) |
| 710 CFRelease(excluded_image); |
718 continue; | 711 continue; |
| 712 } |
| 713 |
| 714 // Verify that the image has 32-bit depth. |
| 715 int bits_per_pixel = CGImageGetBitsPerPixel(image); |
| 716 if (bits_per_pixel / 8 != DesktopFrame::kBytesPerPixel) { |
| 717 LOG(LS_ERROR) << "CGDisplayCreateImage() returned imaged with " |
| 718 << bits_per_pixel |
| 719 << " bits per pixel. Only 32-bit depth is supported."; |
| 720 CFRelease(image); |
| 721 if (excluded_image) |
| 722 CFRelease(excluded_image); |
| 723 return false; |
| 724 } |
719 | 725 |
720 // Request access to the raw pixel data via the image's DataProvider. | 726 // Request access to the raw pixel data via the image's DataProvider. |
721 CGDataProviderRef provider = CGImageGetDataProvider(image); | 727 CGDataProviderRef provider = CGImageGetDataProvider(image); |
722 CFDataRef data = CGDataProviderCopyData(provider); | 728 CFDataRef data = CGDataProviderCopyData(provider); |
723 assert(data); | 729 assert(data); |
724 | 730 |
725 const uint8_t* display_base_address = CFDataGetBytePtr(data); | 731 const uint8_t* display_base_address = CFDataGetBytePtr(data); |
726 int src_bytes_per_row = CGImageGetBytesPerRow(image); | 732 int src_bytes_per_row = CGImageGetBytesPerRow(image); |
727 int src_bytes_per_pixel = CGImageGetBitsPerPixel(image) / 8; | |
728 | 733 |
729 // Calculate where in the output buffer the display's origin is. | 734 // |image| size may be different from display_bounds in case the screen was |
730 uint8_t* out_ptr = frame.data() + | 735 // resized recently. |
731 (display_bounds.left() * src_bytes_per_pixel) + | 736 copy_region.IntersectWith( |
732 (display_bounds.top() * frame.stride()); | 737 DesktopRect::MakeWH(CGImageGetWidth(image), CGImageGetHeight(image))); |
733 | 738 |
734 // Copy the dirty region from the display buffer into our desktop buffer. | 739 // Copy the dirty region from the display buffer into our desktop buffer. |
| 740 uint8_t* out_ptr = frame.GetFrameDataAtPos(display_bounds.top_left()); |
735 for (DesktopRegion::Iterator i(copy_region); !i.IsAtEnd(); i.Advance()) { | 741 for (DesktopRegion::Iterator i(copy_region); !i.IsAtEnd(); i.Advance()) { |
736 CopyRect(display_base_address, | 742 CopyRect(display_base_address, src_bytes_per_row, out_ptr, frame.stride(), |
737 src_bytes_per_row, | 743 DesktopFrame::kBytesPerPixel, i.rect()); |
738 out_ptr, | |
739 frame.stride(), | |
740 src_bytes_per_pixel, | |
741 i.rect()); | |
742 } | 744 } |
743 | 745 |
744 // Copy the region of the excluded window to the frame. | 746 CFRelease(data); |
| 747 CFRelease(image); |
| 748 |
745 if (excluded_image) { | 749 if (excluded_image) { |
746 assert(excluded_window_region_data); | 750 CGDataProviderRef provider = CGImageGetDataProvider(excluded_image); |
747 display_base_address = CFDataGetBytePtr(excluded_window_region_data); | 751 CFDataRef excluded_image_data = CGDataProviderCopyData(provider); |
| 752 assert(excluded_image_data); |
| 753 display_base_address = CFDataGetBytePtr(excluded_image_data); |
748 src_bytes_per_row = CGImageGetBytesPerRow(excluded_image); | 754 src_bytes_per_row = CGImageGetBytesPerRow(excluded_image); |
749 | 755 |
750 // Translate the bounds relative to the desktop, because |frame| data | 756 // Translate the bounds relative to the desktop, because |frame| data |
751 // starts from the desktop top-left corner. | 757 // starts from the desktop top-left corner. |
752 DesktopRect window_bounds_relative_to_desktop(excluded_window_bounds); | 758 DesktopRect window_bounds_relative_to_desktop(excluded_window_bounds); |
753 window_bounds_relative_to_desktop.Translate( | 759 window_bounds_relative_to_desktop.Translate(-screen_pixel_bounds_.left(), |
754 -screen_pixel_bounds_.left(), -screen_pixel_bounds_.top()); | 760 -screen_pixel_bounds_.top()); |
755 out_ptr = frame.data() + | |
756 (window_bounds_relative_to_desktop.left() * src_bytes_per_pixel) + | |
757 (window_bounds_relative_to_desktop.top() * frame.stride()); | |
758 | 761 |
759 CopyRect(display_base_address, | 762 DesktopRect rect_to_copy = |
760 src_bytes_per_row, | 763 DesktopRect::MakeSize(excluded_window_bounds.size()); |
761 out_ptr, | 764 rect_to_copy.IntersectWith(DesktopRect::MakeWH( |
762 frame.stride(), | 765 CGImageGetWidth(excluded_image), CGImageGetHeight(excluded_image))); |
763 src_bytes_per_pixel, | 766 |
764 DesktopRect::MakeSize(excluded_window_bounds.size())); | 767 if (CGImageGetBitsPerPixel(excluded_image) / 8 == |
765 CFRelease(excluded_window_region_data); | 768 DesktopFrame::kBytesPerPixel) { |
| 769 CopyRect(display_base_address, src_bytes_per_row, |
| 770 frame.GetFrameDataAtPos( |
| 771 window_bounds_relative_to_desktop.top_left()), |
| 772 frame.stride(), DesktopFrame::kBytesPerPixel, rect_to_copy); |
| 773 } |
| 774 |
| 775 CFRelease(excluded_image_data); |
766 CFRelease(excluded_image); | 776 CFRelease(excluded_image); |
767 } | 777 } |
768 | |
769 CFRelease(data); | |
770 CFRelease(image); | |
771 } | 778 } |
772 if (window_list) | 779 if (window_list) |
773 CFRelease(window_list); | 780 CFRelease(window_list); |
774 return true; | 781 return true; |
775 } | 782 } |
776 | 783 |
777 void ScreenCapturerMac::ScreenConfigurationChanged() { | 784 void ScreenCapturerMac::ScreenConfigurationChanged() { |
778 if (current_display_) { | 785 if (current_display_) { |
779 const MacDisplayConfiguration* config = | 786 const MacDisplayConfiguration* config = |
780 desktop_config_.FindDisplayConfigurationById(current_display_); | 787 desktop_config_.FindDisplayConfigurationById(current_display_); |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
974 return NULL; | 981 return NULL; |
975 | 982 |
976 std::unique_ptr<ScreenCapturerMac> capturer( | 983 std::unique_ptr<ScreenCapturerMac> capturer( |
977 new ScreenCapturerMac(options.configuration_monitor())); | 984 new ScreenCapturerMac(options.configuration_monitor())); |
978 if (!capturer->Init()) | 985 if (!capturer->Init()) |
979 capturer.reset(); | 986 capturer.reset(); |
980 return capturer.release(); | 987 return capturer.release(); |
981 } | 988 } |
982 | 989 |
983 } // namespace webrtc | 990 } // namespace webrtc |
OLD | NEW |