Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(13)

Side by Side Diff: webrtc/modules/desktop_capture/screen_capturer_mac.mm

Issue 1816723002: Fix potential crashes in the screen capturer on Mac (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698