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 22 matching lines...) Expand all Loading... |
33 #include "webrtc/modules/desktop_capture/desktop_region.h" | 33 #include "webrtc/modules/desktop_capture/desktop_region.h" |
34 #include "webrtc/modules/desktop_capture/mac/desktop_configuration.h" | 34 #include "webrtc/modules/desktop_capture/mac/desktop_configuration.h" |
35 #include "webrtc/modules/desktop_capture/mac/desktop_configuration_monitor.h" | 35 #include "webrtc/modules/desktop_capture/mac/desktop_configuration_monitor.h" |
36 #include "webrtc/modules/desktop_capture/mac/scoped_pixel_buffer_object.h" | 36 #include "webrtc/modules/desktop_capture/mac/scoped_pixel_buffer_object.h" |
37 #include "webrtc/modules/desktop_capture/screen_capture_frame_queue.h" | 37 #include "webrtc/modules/desktop_capture/screen_capture_frame_queue.h" |
38 #include "webrtc/modules/desktop_capture/screen_capturer_differ_wrapper.h" | 38 #include "webrtc/modules/desktop_capture/screen_capturer_differ_wrapper.h" |
39 #include "webrtc/modules/desktop_capture/screen_capturer_helper.h" | 39 #include "webrtc/modules/desktop_capture/screen_capturer_helper.h" |
40 #include "webrtc/modules/desktop_capture/shared_desktop_frame.h" | 40 #include "webrtc/modules/desktop_capture/shared_desktop_frame.h" |
41 #include "webrtc/system_wrappers/include/logging.h" | 41 #include "webrtc/system_wrappers/include/logging.h" |
42 | 42 |
| 43 // Once Chrome no longer supports OSX 10.8, everything within this |
| 44 // preprocessor block can be removed. https://crbug.com/579255 |
| 45 #if !defined(MAC_OS_X_VERSION_10_9) || \ |
| 46 MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9 |
| 47 CG_EXTERN const CGRect* CGDisplayStreamUpdateGetRects( |
| 48 CGDisplayStreamUpdateRef updateRef, |
| 49 CGDisplayStreamUpdateRectType rectType, |
| 50 size_t* rectCount); |
| 51 CG_EXTERN CFRunLoopSourceRef |
| 52 CGDisplayStreamGetRunLoopSource(CGDisplayStreamRef displayStream); |
| 53 CG_EXTERN CGError CGDisplayStreamStop(CGDisplayStreamRef displayStream); |
| 54 CG_EXTERN CGError CGDisplayStreamStart(CGDisplayStreamRef displayStream); |
| 55 CG_EXTERN CGDisplayStreamRef |
| 56 CGDisplayStreamCreate(CGDirectDisplayID display, |
| 57 size_t outputWidth, |
| 58 size_t outputHeight, |
| 59 int32_t pixelFormat, |
| 60 CFDictionaryRef properties, |
| 61 CGDisplayStreamFrameAvailableHandler handler); |
| 62 #endif |
| 63 |
43 namespace webrtc { | 64 namespace webrtc { |
44 | 65 |
45 namespace { | 66 namespace { |
46 | 67 |
47 // CGDisplayStreamRefs need to be destroyed asynchronously after receiving a | 68 // CGDisplayStreamRefs need to be destroyed asynchronously after receiving a |
48 // kCGDisplayStreamFrameStatusStopped callback from CoreGraphics. This may | 69 // kCGDisplayStreamFrameStatusStopped callback from CoreGraphics. This may |
49 // happen after the ScreenCapturerMac has been destroyed. DisplayStreamManager | 70 // happen after the ScreenCapturerMac has been destroyed. DisplayStreamManager |
50 // is responsible for destroying all extant CGDisplayStreamRefs, and will | 71 // is responsible for destroying all extant CGDisplayStreamRefs, and will |
51 // destroy itself once it's done. | 72 // destroy itself once it's done. |
52 class DisplayStreamManager { | 73 class DisplayStreamManager { |
53 public: | 74 public: |
54 int GetUniqueId() { return ++unique_id_generator_; } | 75 int GetUniqueId() { return ++unique_id_generator_; } |
55 void DestroyStream(int unique_id) { | 76 void DestroyStream(int unique_id) { |
56 auto it = display_stream_wrappers_.find(unique_id); | 77 auto it = display_stream_wrappers_.find(unique_id); |
57 RTC_CHECK(it != display_stream_wrappers_.end()); | 78 RTC_CHECK(it != display_stream_wrappers_.end()); |
58 RTC_CHECK(!it->second.active); | 79 RTC_CHECK(!it->second.active); |
59 CFRelease(it->second.stream); | 80 CFRelease(it->second.stream); |
60 display_stream_wrappers_.erase(it); | 81 display_stream_wrappers_.erase(it); |
61 | 82 |
62 if (ready_for_self_destruction_ && display_stream_wrappers_.empty()) | 83 if (ready_for_self_destruction_ && display_stream_wrappers_.empty()) |
63 delete this; | 84 delete this; |
64 } | 85 } |
65 | 86 |
66 void SaveStream(int unique_id, CGDisplayStreamRef stream) { | 87 void SaveStream(int unique_id, |
| 88 CGDisplayStreamRef stream) { |
67 RTC_CHECK(unique_id <= unique_id_generator_); | 89 RTC_CHECK(unique_id <= unique_id_generator_); |
68 DisplayStreamWrapper wrapper; | 90 DisplayStreamWrapper wrapper; |
69 wrapper.stream = stream; | 91 wrapper.stream = stream; |
70 display_stream_wrappers_[unique_id] = wrapper; | 92 display_stream_wrappers_[unique_id] = wrapper; |
71 } | 93 } |
72 | 94 |
73 void UnregisterActiveStreams() { | 95 void UnregisterActiveStreams() { |
74 for (auto& pair : display_stream_wrappers_) { | 96 for (auto& pair : display_stream_wrappers_) { |
75 DisplayStreamWrapper& wrapper = pair.second; | 97 DisplayStreamWrapper& wrapper = pair.second; |
76 if (wrapper.active) { | 98 if (wrapper.active) { |
77 wrapper.active = false; | 99 wrapper.active = false; |
78 // CGDisplayStream* functions are only available in 10.8+. Chrome only supports | 100 CFRunLoopSourceRef source = |
79 // 10.9+, but we can't remove these warning suppressions until the deployment | 101 CGDisplayStreamGetRunLoopSource(wrapper.stream); |
80 // target is updated. https://crbug.com/579255 | 102 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source, |
81 #pragma clang diagnostic push | 103 kCFRunLoopDefaultMode); |
82 #pragma clang diagnostic ignored "-Wunguarded-availability" | |
83 CGDisplayStreamStop(wrapper.stream); | 104 CGDisplayStreamStop(wrapper.stream); |
84 #pragma clang diagnostic pop | |
85 } | 105 } |
86 } | 106 } |
87 } | 107 } |
88 | 108 |
89 void PrepareForSelfDestruction() { | 109 void PrepareForSelfDestruction() { |
90 ready_for_self_destruction_ = true; | 110 ready_for_self_destruction_ = true; |
91 | 111 |
92 if (display_stream_wrappers_.empty()) | 112 if (display_stream_wrappers_.empty()) |
93 delete this; | 113 delete this; |
94 } | 114 } |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
280 bool CgBlitPostLion(const DesktopFrame& frame, | 300 bool CgBlitPostLion(const DesktopFrame& frame, |
281 const DesktopRegion& region); | 301 const DesktopRegion& region); |
282 | 302 |
283 // Called when the screen configuration is changed. | 303 // Called when the screen configuration is changed. |
284 void ScreenConfigurationChanged(); | 304 void ScreenConfigurationChanged(); |
285 | 305 |
286 bool RegisterRefreshAndMoveHandlers(); | 306 bool RegisterRefreshAndMoveHandlers(); |
287 void UnregisterRefreshAndMoveHandlers(); | 307 void UnregisterRefreshAndMoveHandlers(); |
288 | 308 |
289 void ScreenRefresh(CGRectCount count, const CGRect *rect_array); | 309 void ScreenRefresh(CGRectCount count, const CGRect *rect_array); |
290 void ScreenUpdateMove(CGFloat delta_x, | |
291 CGFloat delta_y, | |
292 size_t count, | |
293 const CGRect* rect_array); | |
294 void ScreenRefreshCallback(CGRectCount count, const CGRect* rect_array); | |
295 void ReleaseBuffers(); | 310 void ReleaseBuffers(); |
296 | 311 |
297 std::unique_ptr<DesktopFrame> CreateFrame(); | 312 std::unique_ptr<DesktopFrame> CreateFrame(); |
298 | 313 |
299 Callback* callback_ = nullptr; | 314 Callback* callback_ = nullptr; |
300 | 315 |
301 CGLContextObj cgl_context_ = nullptr; | 316 CGLContextObj cgl_context_ = nullptr; |
302 ScopedPixelBufferObject pixel_buffer_object_; | 317 ScopedPixelBufferObject pixel_buffer_object_; |
303 | 318 |
304 // Queue of the frames buffers. | 319 // Queue of the frames buffers. |
(...skipping 613 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
918 pixel_buffer_object_.Init(cgl_context_, buffer_size); | 933 pixel_buffer_object_.Init(cgl_context_, buffer_size); |
919 } | 934 } |
920 | 935 |
921 bool ScreenCapturerMac::RegisterRefreshAndMoveHandlers() { | 936 bool ScreenCapturerMac::RegisterRefreshAndMoveHandlers() { |
922 desktop_config_ = desktop_config_monitor_->desktop_configuration(); | 937 desktop_config_ = desktop_config_monitor_->desktop_configuration(); |
923 for (const auto& config : desktop_config_.displays) { | 938 for (const auto& config : desktop_config_.displays) { |
924 size_t pixel_width = config.pixel_bounds.width(); | 939 size_t pixel_width = config.pixel_bounds.width(); |
925 size_t pixel_height = config.pixel_bounds.height(); | 940 size_t pixel_height = config.pixel_bounds.height(); |
926 if (pixel_width == 0 || pixel_height == 0) | 941 if (pixel_width == 0 || pixel_height == 0) |
927 continue; | 942 continue; |
928 int unique_id = display_stream_manager_->GetUniqueId(); | 943 // Using a local variable forces the block to capture the raw pointer. |
| 944 DisplayStreamManager* manager = display_stream_manager_; |
| 945 int unique_id = manager->GetUniqueId(); |
929 CGDirectDisplayID display_id = config.id; | 946 CGDirectDisplayID display_id = config.id; |
930 CGDisplayStreamFrameAvailableHandler handler = | 947 CGDisplayStreamFrameAvailableHandler handler = |
931 ^(CGDisplayStreamFrameStatus status, uint64_t display_time, | 948 ^(CGDisplayStreamFrameStatus status, uint64_t display_time, |
932 IOSurfaceRef frame_surface, CGDisplayStreamUpdateRef updateRef) { | 949 IOSurfaceRef frame_surface, CGDisplayStreamUpdateRef updateRef) { |
933 if (status == kCGDisplayStreamFrameStatusStopped) { | 950 if (status == kCGDisplayStreamFrameStatusStopped) { |
934 display_stream_manager_->DestroyStream(unique_id); | 951 manager->DestroyStream(unique_id); |
935 return; | 952 return; |
936 } | 953 } |
937 | 954 |
938 if (display_stream_manager_->ShouldIgnoreUpdates()) | 955 if (manager->ShouldIgnoreUpdates()) |
939 return; | 956 return; |
940 | 957 |
941 // Only pay attention to frame updates. | 958 // Only pay attention to frame updates. |
942 if (status != kCGDisplayStreamFrameStatusFrameComplete) | 959 if (status != kCGDisplayStreamFrameStatusFrameComplete) |
943 return; | 960 return; |
944 | 961 |
945 size_t count = 0; | 962 size_t count = 0; |
946 #pragma clang diagnostic push | |
947 #pragma clang diagnostic ignored "-Wunguarded-availability" | |
948 // TODO(erikchen): Use kCGDisplayStreamUpdateDirtyRects. | |
949 const CGRect* rects = CGDisplayStreamUpdateGetRects( | 963 const CGRect* rects = CGDisplayStreamUpdateGetRects( |
950 updateRef, kCGDisplayStreamUpdateMovedRects, &count); | 964 updateRef, kCGDisplayStreamUpdateDirtyRects, &count); |
951 #pragma clang diagnostic pop | |
952 if (count != 0) { | |
953 CGFloat dx = 0; | |
954 CGFloat dy = 0; | |
955 #pragma clang diagnostic push | |
956 #pragma clang diagnostic ignored "-Wunguarded-availability" | |
957 CGDisplayStreamUpdateGetMovedRectsDelta(updateRef, &dx, &dy); | |
958 #pragma clang diagnostic pop | |
959 ScreenUpdateMove(dx, dy, count, rects); | |
960 } | |
961 | |
962 count = 0; | |
963 #pragma clang diagnostic push | |
964 #pragma clang diagnostic ignored "-Wunguarded-availability" | |
965 rects = CGDisplayStreamUpdateGetRects( | |
966 updateRef, kCGDisplayStreamUpdateRefreshedRects, &count); | |
967 #pragma clang diagnostic pop | |
968 if (count != 0) { | 965 if (count != 0) { |
969 // According to CGDisplayStream.h, it's safe to call | 966 // According to CGDisplayStream.h, it's safe to call |
970 // CGDisplayStreamStop() from within the callback. | 967 // CGDisplayStreamStop() from within the callback. |
971 ScreenRefreshCallback(count, rects); | 968 ScreenRefresh(count, rects); |
972 } | 969 } |
973 }; | 970 }; |
974 #pragma clang diagnostic push | |
975 #pragma clang diagnostic ignored "-Wunguarded-availability" | |
976 CGDisplayStreamRef display_stream = CGDisplayStreamCreate( | 971 CGDisplayStreamRef display_stream = CGDisplayStreamCreate( |
977 display_id, pixel_width, pixel_height, 'BGRA', nullptr, handler); | 972 display_id, pixel_width, pixel_height, 'BGRA', nullptr, handler); |
978 #pragma clang diagnostic pop | 973 |
979 if (display_stream) { | 974 if (display_stream) { |
| 975 CGError error = CGDisplayStreamStart(display_stream); |
| 976 if (error != kCGErrorSuccess) |
| 977 return false; |
| 978 |
| 979 CFRunLoopSourceRef source = |
| 980 CGDisplayStreamGetRunLoopSource(display_stream); |
| 981 CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode); |
980 display_stream_manager_->SaveStream(unique_id, display_stream); | 982 display_stream_manager_->SaveStream(unique_id, display_stream); |
981 #pragma clang diagnostic push | |
982 #pragma clang diagnostic ignored "-Wunguarded-availability" | |
983 CGDisplayStreamStart(display_stream); | |
984 #pragma clang diagnostic pop | |
985 } | 983 } |
986 } | 984 } |
987 | 985 |
988 return true; | 986 return true; |
989 } | 987 } |
990 | 988 |
991 void ScreenCapturerMac::UnregisterRefreshAndMoveHandlers() { | 989 void ScreenCapturerMac::UnregisterRefreshAndMoveHandlers() { |
992 display_stream_manager_->UnregisterActiveStreams(); | 990 display_stream_manager_->UnregisterActiveStreams(); |
993 } | 991 } |
994 | 992 |
995 void ScreenCapturerMac::ScreenRefresh(CGRectCount count, | 993 void ScreenCapturerMac::ScreenRefresh(CGRectCount count, |
996 const CGRect* rect_array) { | 994 const CGRect* rect_array) { |
997 if (screen_pixel_bounds_.is_empty()) | 995 if (screen_pixel_bounds_.is_empty()) |
998 return; | 996 ScreenConfigurationChanged(); |
999 | 997 |
1000 DesktopRegion region; | 998 DesktopRegion region; |
1001 DesktopVector translate_vector = | 999 DesktopVector translate_vector = |
1002 DesktopVector().subtract(screen_pixel_bounds_.top_left()); | 1000 DesktopVector().subtract(screen_pixel_bounds_.top_left()); |
1003 for (CGRectCount i = 0; i < count; ++i) { | 1001 for (CGRectCount i = 0; i < count; ++i) { |
1004 // Convert from Density-Independent Pixel to physical pixel coordinates. | 1002 // Convert from Density-Independent Pixel to physical pixel coordinates. |
1005 DesktopRect rect = ScaleAndRoundCGRect(rect_array[i], dip_to_pixel_scale_); | 1003 DesktopRect rect = ScaleAndRoundCGRect(rect_array[i], dip_to_pixel_scale_); |
1006 // Translate from local desktop to capturer framebuffer coordinates. | 1004 // Translate from local desktop to capturer framebuffer coordinates. |
1007 rect.Translate(translate_vector); | 1005 rect.Translate(translate_vector); |
1008 region.AddRect(rect); | 1006 region.AddRect(rect); |
1009 } | 1007 } |
1010 | 1008 |
1011 helper_.InvalidateRegion(region); | 1009 helper_.InvalidateRegion(region); |
1012 } | 1010 } |
1013 | 1011 |
1014 void ScreenCapturerMac::ScreenUpdateMove(CGFloat delta_x, | |
1015 CGFloat delta_y, | |
1016 size_t count, | |
1017 const CGRect* rect_array) { | |
1018 // Translate |rect_array| to identify the move's destination. | |
1019 CGRect refresh_rects[count]; | |
1020 for (CGRectCount i = 0; i < count; ++i) { | |
1021 refresh_rects[i] = CGRectOffset(rect_array[i], delta_x, delta_y); | |
1022 } | |
1023 | |
1024 // Currently we just treat move events the same as refreshes. | |
1025 ScreenRefresh(count, refresh_rects); | |
1026 } | |
1027 | |
1028 void ScreenCapturerMac::ScreenRefreshCallback(CGRectCount count, | |
1029 const CGRect* rect_array) { | |
1030 if (screen_pixel_bounds_.is_empty()) | |
1031 ScreenConfigurationChanged(); | |
1032 ScreenRefresh(count, rect_array); | |
1033 } | |
1034 | |
1035 std::unique_ptr<DesktopFrame> ScreenCapturerMac::CreateFrame() { | 1012 std::unique_ptr<DesktopFrame> ScreenCapturerMac::CreateFrame() { |
1036 std::unique_ptr<DesktopFrame> frame( | 1013 std::unique_ptr<DesktopFrame> frame( |
1037 new BasicDesktopFrame(screen_pixel_bounds_.size())); | 1014 new BasicDesktopFrame(screen_pixel_bounds_.size())); |
1038 frame->set_dpi(DesktopVector(kStandardDPI * dip_to_pixel_scale_, | 1015 frame->set_dpi(DesktopVector(kStandardDPI * dip_to_pixel_scale_, |
1039 kStandardDPI * dip_to_pixel_scale_)); | 1016 kStandardDPI * dip_to_pixel_scale_)); |
1040 return frame; | 1017 return frame; |
1041 } | 1018 } |
1042 | 1019 |
1043 } // namespace | 1020 } // namespace |
1044 | 1021 |
1045 // static | 1022 // static |
1046 ScreenCapturer* ScreenCapturer::Create(const DesktopCaptureOptions& options) { | 1023 ScreenCapturer* ScreenCapturer::Create(const DesktopCaptureOptions& options) { |
1047 if (!options.configuration_monitor()) | 1024 if (!options.configuration_monitor()) |
1048 return nullptr; | 1025 return nullptr; |
1049 | 1026 |
1050 std::unique_ptr<ScreenCapturer> capturer( | 1027 std::unique_ptr<ScreenCapturer> capturer( |
1051 new ScreenCapturerMac(options.configuration_monitor())); | 1028 new ScreenCapturerMac(options.configuration_monitor())); |
1052 if (!static_cast<ScreenCapturerMac*>(capturer.get())->Init()) { | 1029 if (!static_cast<ScreenCapturerMac*>(capturer.get())->Init()) { |
1053 return nullptr; | 1030 return nullptr; |
1054 } | 1031 } |
1055 | 1032 |
1056 if (options.detect_updated_region()) { | 1033 if (options.detect_updated_region()) { |
1057 capturer.reset(new ScreenCapturerDifferWrapper(std::move(capturer))); | 1034 capturer.reset(new ScreenCapturerDifferWrapper(std::move(capturer))); |
1058 } | 1035 } |
1059 | 1036 |
1060 return capturer.release(); | 1037 return capturer.release(); |
1061 } | 1038 } |
1062 | 1039 |
1063 } // namespace webrtc | 1040 } // namespace webrtc |
OLD | NEW |