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 #include <utility> | 17 #include <utility> |
18 | 18 |
19 #include <ApplicationServices/ApplicationServices.h> | 19 #include <ApplicationServices/ApplicationServices.h> |
20 #include <Cocoa/Cocoa.h> | 20 #include <Cocoa/Cocoa.h> |
21 #include <CoreGraphics/CoreGraphics.h> | |
21 #include <dlfcn.h> | 22 #include <dlfcn.h> |
22 #include <OpenGL/CGLMacro.h> | 23 #include <OpenGL/CGLMacro.h> |
23 #include <OpenGL/OpenGL.h> | 24 #include <OpenGL/OpenGL.h> |
24 | 25 |
25 #include "webrtc/base/checks.h" | 26 #include "webrtc/base/checks.h" |
26 #include "webrtc/base/constructormagic.h" | 27 #include "webrtc/base/constructormagic.h" |
27 #include "webrtc/base/macutils.h" | 28 #include "webrtc/base/macutils.h" |
29 #include "webrtc/base/criticalsection.h" | |
28 #include "webrtc/base/timeutils.h" | 30 #include "webrtc/base/timeutils.h" |
29 #include "webrtc/modules/desktop_capture/desktop_capture_options.h" | 31 #include "webrtc/modules/desktop_capture/desktop_capture_options.h" |
30 #include "webrtc/modules/desktop_capture/desktop_frame.h" | 32 #include "webrtc/modules/desktop_capture/desktop_frame.h" |
31 #include "webrtc/modules/desktop_capture/desktop_geometry.h" | 33 #include "webrtc/modules/desktop_capture/desktop_geometry.h" |
32 #include "webrtc/modules/desktop_capture/desktop_region.h" | 34 #include "webrtc/modules/desktop_capture/desktop_region.h" |
33 #include "webrtc/modules/desktop_capture/mac/desktop_configuration.h" | 35 #include "webrtc/modules/desktop_capture/mac/desktop_configuration.h" |
34 #include "webrtc/modules/desktop_capture/mac/desktop_configuration_monitor.h" | 36 #include "webrtc/modules/desktop_capture/mac/desktop_configuration_monitor.h" |
35 #include "webrtc/modules/desktop_capture/mac/scoped_pixel_buffer_object.h" | 37 #include "webrtc/modules/desktop_capture/mac/scoped_pixel_buffer_object.h" |
36 #include "webrtc/modules/desktop_capture/screen_capture_frame_queue.h" | 38 #include "webrtc/modules/desktop_capture/screen_capture_frame_queue.h" |
37 #include "webrtc/modules/desktop_capture/screen_capturer_differ_wrapper.h" | 39 #include "webrtc/modules/desktop_capture/screen_capturer_differ_wrapper.h" |
38 #include "webrtc/modules/desktop_capture/screen_capturer_helper.h" | 40 #include "webrtc/modules/desktop_capture/screen_capturer_helper.h" |
39 #include "webrtc/modules/desktop_capture/shared_desktop_frame.h" | 41 #include "webrtc/modules/desktop_capture/shared_desktop_frame.h" |
40 #include "webrtc/system_wrappers/include/logging.h" | 42 #include "webrtc/system_wrappers/include/logging.h" |
41 | 43 |
42 namespace webrtc { | 44 namespace webrtc { |
43 | 45 |
44 namespace { | 46 namespace { |
45 | 47 |
48 struct DisplayStreamWrapper { | |
Eugene But (OOO till 7-30)
2016/10/04 23:13:52
Do you want to add comments for this?
erikchen
2016/10/04 23:52:39
Done.
Note that I added an |owner| field.
| |
49 CGDisplayStreamRef stream = nullptr; | |
50 int unique_id = 0; | |
51 bool active = true; | |
52 }; | |
53 | |
54 // CGDisplayStreamRef needs to be destroyed asynchronously, after a callback | |
55 // with status kCGDisplayStreamFrameStatusStopped. There's no guarantee that | |
56 // ScreenCapturerMac will still be around, so we need a global to ensure that | |
57 // the map from callback to CGDisplayStreamRef is still valid. | |
58 static std::map<int, DisplayStreamWrapper> g_display_stream_wrappers; | |
Eugene But (OOO till 7-30)
2016/10/04 23:13:53
I don't think that static global objects are allow
erikchen
2016/10/04 23:52:39
We do use them:
https://cs.chromium.org/search/?q=
Eugene But (OOO till 7-30)
2016/10/05 00:19:53
Maybe a function which returns a map reference?:
Sergey Ulanov
2016/10/06 23:57:24
this pattern is used in several places in WebRTC,
| |
59 static int g_unique_id_generator = 0; | |
60 static rtc::CriticalSection g_display_stream_critical_section; | |
61 | |
46 // Definitions used to dynamic-link to deprecated OS 10.6 functions. | 62 // Definitions used to dynamic-link to deprecated OS 10.6 functions. |
47 const char* kApplicationServicesLibraryName = | 63 const char* kApplicationServicesLibraryName = |
48 "/System/Library/Frameworks/ApplicationServices.framework/" | 64 "/System/Library/Frameworks/ApplicationServices.framework/" |
49 "ApplicationServices"; | 65 "ApplicationServices"; |
50 typedef void* (*CGDisplayBaseAddressFunc)(CGDirectDisplayID); | 66 typedef void* (*CGDisplayBaseAddressFunc)(CGDirectDisplayID); |
51 typedef size_t (*CGDisplayBytesPerRowFunc)(CGDirectDisplayID); | 67 typedef size_t (*CGDisplayBytesPerRowFunc)(CGDirectDisplayID); |
52 typedef size_t (*CGDisplayBitsPerPixelFunc)(CGDirectDisplayID); | 68 typedef size_t (*CGDisplayBitsPerPixelFunc)(CGDirectDisplayID); |
53 const char* kOpenGlLibraryName = | 69 const char* kOpenGlLibraryName = |
54 "/System/Library/Frameworks/OpenGL.framework/OpenGL"; | 70 "/System/Library/Frameworks/OpenGL.framework/OpenGL"; |
55 typedef CGLError (*CGLSetFullScreenFunc)(CGLContextObj); | 71 typedef CGLError (*CGLSetFullScreenFunc)(CGLContextObj); |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
211 bool CgBlitPostLion(const DesktopFrame& frame, | 227 bool CgBlitPostLion(const DesktopFrame& frame, |
212 const DesktopRegion& region); | 228 const DesktopRegion& region); |
213 | 229 |
214 // Called when the screen configuration is changed. | 230 // Called when the screen configuration is changed. |
215 void ScreenConfigurationChanged(); | 231 void ScreenConfigurationChanged(); |
216 | 232 |
217 bool RegisterRefreshAndMoveHandlers(); | 233 bool RegisterRefreshAndMoveHandlers(); |
218 void UnregisterRefreshAndMoveHandlers(); | 234 void UnregisterRefreshAndMoveHandlers(); |
219 | 235 |
220 void ScreenRefresh(CGRectCount count, const CGRect *rect_array); | 236 void ScreenRefresh(CGRectCount count, const CGRect *rect_array); |
221 void ScreenUpdateMove(CGScreenUpdateMoveDelta delta, | 237 void ScreenUpdateMove(CGFloat delta_x, |
238 CGFloat delta_y, | |
222 size_t count, | 239 size_t count, |
223 const CGRect *rect_array); | 240 const CGRect* rect_array); |
224 static void ScreenRefreshCallback(CGRectCount count, | 241 void ScreenRefreshCallback(CGRectCount count, const CGRect* rect_array); |
225 const CGRect *rect_array, | |
226 void *user_parameter); | |
227 static void ScreenUpdateMoveCallback(CGScreenUpdateMoveDelta delta, | |
228 size_t count, | |
229 const CGRect *rect_array, | |
230 void *user_parameter); | |
231 void ReleaseBuffers(); | 242 void ReleaseBuffers(); |
232 | 243 |
233 std::unique_ptr<DesktopFrame> CreateFrame(); | 244 std::unique_ptr<DesktopFrame> CreateFrame(); |
234 | 245 |
235 Callback* callback_ = nullptr; | 246 Callback* callback_ = nullptr; |
236 | 247 |
237 CGLContextObj cgl_context_ = nullptr; | 248 CGLContextObj cgl_context_ = nullptr; |
238 ScopedPixelBufferObject pixel_buffer_object_; | 249 ScopedPixelBufferObject pixel_buffer_object_; |
239 | 250 |
240 // Queue of the frames buffers. | 251 // Queue of the frames buffers. |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
304 : desktop_config_monitor_(desktop_config_monitor) {} | 315 : desktop_config_monitor_(desktop_config_monitor) {} |
305 | 316 |
306 ScreenCapturerMac::~ScreenCapturerMac() { | 317 ScreenCapturerMac::~ScreenCapturerMac() { |
307 ReleaseBuffers(); | 318 ReleaseBuffers(); |
308 UnregisterRefreshAndMoveHandlers(); | 319 UnregisterRefreshAndMoveHandlers(); |
309 dlclose(app_services_library_); | 320 dlclose(app_services_library_); |
310 dlclose(opengl_library_); | 321 dlclose(opengl_library_); |
311 } | 322 } |
312 | 323 |
313 bool ScreenCapturerMac::Init() { | 324 bool ScreenCapturerMac::Init() { |
325 desktop_config_monitor_->Lock(); | |
326 desktop_config_ = desktop_config_monitor_->desktop_configuration(); | |
327 desktop_config_monitor_->Unlock(); | |
314 if (!RegisterRefreshAndMoveHandlers()) { | 328 if (!RegisterRefreshAndMoveHandlers()) { |
315 return false; | 329 return false; |
316 } | 330 } |
317 desktop_config_monitor_->Lock(); | |
318 desktop_config_ = desktop_config_monitor_->desktop_configuration(); | |
319 desktop_config_monitor_->Unlock(); | |
320 ScreenConfigurationChanged(); | 331 ScreenConfigurationChanged(); |
321 return true; | 332 return true; |
322 } | 333 } |
323 | 334 |
324 void ScreenCapturerMac::ReleaseBuffers() { | 335 void ScreenCapturerMac::ReleaseBuffers() { |
325 if (cgl_context_) { | 336 if (cgl_context_) { |
326 pixel_buffer_object_.Release(); | 337 pixel_buffer_object_.Release(); |
327 CGLDestroyContext(cgl_context_); | 338 CGLDestroyContext(cgl_context_); |
328 cgl_context_ = nullptr; | 339 cgl_context_ = nullptr; |
329 } | 340 } |
(...skipping 511 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
841 (*cgl_set_full_screen_)(cgl_context_); | 852 (*cgl_set_full_screen_)(cgl_context_); |
842 CGLSetCurrentContext(cgl_context_); | 853 CGLSetCurrentContext(cgl_context_); |
843 | 854 |
844 size_t buffer_size = screen_pixel_bounds_.width() * | 855 size_t buffer_size = screen_pixel_bounds_.width() * |
845 screen_pixel_bounds_.height() * | 856 screen_pixel_bounds_.height() * |
846 sizeof(uint32_t); | 857 sizeof(uint32_t); |
847 pixel_buffer_object_.Init(cgl_context_, buffer_size); | 858 pixel_buffer_object_.Init(cgl_context_, buffer_size); |
848 } | 859 } |
849 | 860 |
850 bool ScreenCapturerMac::RegisterRefreshAndMoveHandlers() { | 861 bool ScreenCapturerMac::RegisterRefreshAndMoveHandlers() { |
851 CGError err = CGRegisterScreenRefreshCallback( | 862 desktop_config_ = desktop_config_monitor_->desktop_configuration(); |
Eugene But (OOO till 7-30)
2016/10/04 23:13:53
Is this thing can be called on different threads?
erikchen
2016/10/04 23:52:39
Based on the usage of desktop_config_ in the rest
Eugene But (OOO till 7-30)
2016/10/05 00:19:53
So if it is single threaded, then what is the reas
| |
852 ScreenCapturerMac::ScreenRefreshCallback, this); | 863 for (MacDisplayConfigurations::iterator it = desktop_config_.displays.begin(); |
Eugene But (OOO till 7-30)
2016/10/04 23:13:53
NIT: Maybe use auto and for in?
erikchen
2016/10/04 23:52:39
Done.
| |
853 if (err != kCGErrorSuccess) { | 864 it != desktop_config_.displays.end(); ++it) { |
854 LOG(LS_ERROR) << "CGRegisterScreenRefreshCallback " << err; | 865 size_t pixel_width = it->pixel_bounds.width(); |
855 return false; | 866 size_t pixel_height = it->pixel_bounds.height(); |
856 } | 867 if (pixel_width == 0 || pixel_height == 0) |
868 continue; | |
869 int unique_id; | |
Eugene But (OOO till 7-30)
2016/10/04 23:13:53
Please initialize
erikchen
2016/10/04 23:52:39
Done.
| |
870 { | |
871 rtc::CritScope scoper(&g_display_stream_critical_section); | |
872 unique_id = ++g_unique_id_generator; | |
873 } | |
874 CGDirectDisplayID display_id = it->id; | |
875 CGDisplayStreamFrameAvailableHandler handler = | |
876 ^(CGDisplayStreamFrameStatus status, uint64_t displayTime, | |
Eugene But (OOO till 7-30)
2016/10/04 23:13:53
s/displayTime/display_time
erikchen
2016/10/04 23:52:39
Done.
| |
877 IOSurfaceRef frameSurface, CGDisplayStreamUpdateRef updateRef) { | |
Eugene But (OOO till 7-30)
2016/10/04 23:13:53
s/frameSurface/frame_surface s/updateRef/update_re
Eugene But (OOO till 7-30)
2016/10/04 23:13:53
Is this hander called on different thread (other t
erikchen
2016/10/04 23:52:39
No. The reason for the lock I added was to deal wi
erikchen
2016/10/04 23:52:39
Done.
Eugene But (OOO till 7-30)
2016/10/05 00:19:53
So if |g_display_stream_wrappers| is always access
| |
878 if (status == kCGDisplayStreamFrameStatusStopped) { | |
879 rtc::CritScope scoper(&g_display_stream_critical_section); | |
880 auto it = g_display_stream_wrappers.find(unique_id); | |
881 assert(it != g_display_stream_wrappers.end()); | |
Eugene But (OOO till 7-30)
2016/10/04 23:13:52
Should this be DCHECK?
erikchen
2016/10/04 23:52:39
I think the answer is no. Assuming we don't immedi
| |
882 assert(!it->second.active); | |
883 CFRelease(it->second.stream); | |
884 g_display_stream_wrappers.erase(it); | |
885 return; | |
886 } | |
857 | 887 |
858 err = CGScreenRegisterMoveCallback( | 888 // Only pay attention to frame updates. |
859 ScreenCapturerMac::ScreenUpdateMoveCallback, this); | 889 if (status != kCGDisplayStreamFrameStatusFrameComplete) |
860 if (err != kCGErrorSuccess) { | 890 return; |
861 LOG(LS_ERROR) << "CGScreenRegisterMoveCallback " << err; | 891 |
862 return false; | 892 size_t count = 0; |
893 const CGRect* rects = CGDisplayStreamUpdateGetRects( | |
894 updateRef, kCGDisplayStreamUpdateMovedRects, &count); | |
895 if (count != 0) { | |
896 CGFloat dx = 0; | |
897 CGFloat dy = 0; | |
898 CGDisplayStreamUpdateGetMovedRectsDelta(updateRef, &dx, &dy); | |
899 ScreenUpdateMove(dx, dy, count, rects); | |
900 } | |
901 | |
902 count = 0; | |
903 rects = CGDisplayStreamUpdateGetRects( | |
904 updateRef, kCGDisplayStreamUpdateRefreshedRects, &count); | |
905 if (count != 0) { | |
906 ScreenRefreshCallback(count, rects); | |
907 } | |
908 }; | |
909 CGDisplayStreamRef display_stream = CGDisplayStreamCreate( | |
910 display_id, pixel_width, pixel_height, 'BGRA', nullptr, handler); | |
911 if (display_stream) { | |
912 DisplayStreamWrapper wrapper; | |
913 wrapper.stream = display_stream; | |
914 wrapper.unique_id = unique_id; | |
915 { | |
916 rtc::CritScope scoper(&g_display_stream_critical_section); | |
917 assert(g_display_stream_wrappers.find(unique_id) == | |
918 g_display_stream_wrappers.end()); | |
919 g_display_stream_wrappers[unique_id] = wrapper; | |
920 } | |
921 CGDisplayStreamStart(display_stream); | |
922 } | |
863 } | 923 } |
864 | 924 |
865 return true; | 925 return true; |
866 } | 926 } |
867 | 927 |
868 void ScreenCapturerMac::UnregisterRefreshAndMoveHandlers() { | 928 void ScreenCapturerMac::UnregisterRefreshAndMoveHandlers() { |
869 CGUnregisterScreenRefreshCallback( | 929 rtc::CritScope scoper(&g_display_stream_critical_section); |
870 ScreenCapturerMac::ScreenRefreshCallback, this); | 930 for (auto& pair : g_display_stream_wrappers) { |
871 CGScreenUnregisterMoveCallback( | 931 DisplayStreamWrapper& wrapper = pair.second; |
872 ScreenCapturerMac::ScreenUpdateMoveCallback, this); | 932 if (wrapper.active) { |
933 wrapper.active = false; | |
934 CGDisplayStreamStop(wrapper.stream); | |
935 } | |
936 } | |
873 } | 937 } |
874 | 938 |
875 void ScreenCapturerMac::ScreenRefresh(CGRectCount count, | 939 void ScreenCapturerMac::ScreenRefresh(CGRectCount count, |
876 const CGRect* rect_array) { | 940 const CGRect* rect_array) { |
877 if (screen_pixel_bounds_.is_empty()) | 941 if (screen_pixel_bounds_.is_empty()) |
878 return; | 942 return; |
879 | 943 |
880 DesktopRegion region; | 944 DesktopRegion region; |
881 DesktopVector translate_vector = | 945 DesktopVector translate_vector = |
882 DesktopVector().subtract(screen_pixel_bounds_.top_left()); | 946 DesktopVector().subtract(screen_pixel_bounds_.top_left()); |
883 for (CGRectCount i = 0; i < count; ++i) { | 947 for (CGRectCount i = 0; i < count; ++i) { |
884 // Convert from Density-Independent Pixel to physical pixel coordinates. | 948 // Convert from Density-Independent Pixel to physical pixel coordinates. |
885 DesktopRect rect = ScaleAndRoundCGRect(rect_array[i], dip_to_pixel_scale_); | 949 DesktopRect rect = ScaleAndRoundCGRect(rect_array[i], dip_to_pixel_scale_); |
886 // Translate from local desktop to capturer framebuffer coordinates. | 950 // Translate from local desktop to capturer framebuffer coordinates. |
887 rect.Translate(translate_vector); | 951 rect.Translate(translate_vector); |
888 region.AddRect(rect); | 952 region.AddRect(rect); |
889 } | 953 } |
890 | 954 |
891 helper_.InvalidateRegion(region); | 955 helper_.InvalidateRegion(region); |
892 } | 956 } |
893 | 957 |
894 void ScreenCapturerMac::ScreenUpdateMove(CGScreenUpdateMoveDelta delta, | 958 void ScreenCapturerMac::ScreenUpdateMove(CGFloat delta_x, |
959 CGFloat delta_y, | |
895 size_t count, | 960 size_t count, |
896 const CGRect* rect_array) { | 961 const CGRect* rect_array) { |
897 // Translate |rect_array| to identify the move's destination. | 962 // Translate |rect_array| to identify the move's destination. |
898 CGRect refresh_rects[count]; | 963 CGRect refresh_rects[count]; |
899 for (CGRectCount i = 0; i < count; ++i) { | 964 for (CGRectCount i = 0; i < count; ++i) { |
900 refresh_rects[i] = CGRectOffset(rect_array[i], delta.dX, delta.dY); | 965 refresh_rects[i] = CGRectOffset(rect_array[i], delta_x, delta_y); |
901 } | 966 } |
902 | 967 |
903 // Currently we just treat move events the same as refreshes. | 968 // Currently we just treat move events the same as refreshes. |
904 ScreenRefresh(count, refresh_rects); | 969 ScreenRefresh(count, refresh_rects); |
905 } | 970 } |
906 | 971 |
907 void ScreenCapturerMac::ScreenRefreshCallback(CGRectCount count, | 972 void ScreenCapturerMac::ScreenRefreshCallback(CGRectCount count, |
908 const CGRect* rect_array, | 973 const CGRect* rect_array) { |
909 void* user_parameter) { | 974 if (screen_pixel_bounds_.is_empty()) |
910 ScreenCapturerMac* capturer = | 975 ScreenConfigurationChanged(); |
911 reinterpret_cast<ScreenCapturerMac*>(user_parameter); | 976 ScreenRefresh(count, rect_array); |
912 if (capturer->screen_pixel_bounds_.is_empty()) | |
913 capturer->ScreenConfigurationChanged(); | |
914 capturer->ScreenRefresh(count, rect_array); | |
915 } | |
916 | |
917 void ScreenCapturerMac::ScreenUpdateMoveCallback( | |
918 CGScreenUpdateMoveDelta delta, | |
919 size_t count, | |
920 const CGRect* rect_array, | |
921 void* user_parameter) { | |
922 ScreenCapturerMac* capturer = | |
923 reinterpret_cast<ScreenCapturerMac*>(user_parameter); | |
924 capturer->ScreenUpdateMove(delta, count, rect_array); | |
925 } | 977 } |
926 | 978 |
927 std::unique_ptr<DesktopFrame> ScreenCapturerMac::CreateFrame() { | 979 std::unique_ptr<DesktopFrame> ScreenCapturerMac::CreateFrame() { |
928 std::unique_ptr<DesktopFrame> frame( | 980 std::unique_ptr<DesktopFrame> frame( |
929 new BasicDesktopFrame(screen_pixel_bounds_.size())); | 981 new BasicDesktopFrame(screen_pixel_bounds_.size())); |
930 frame->set_dpi(DesktopVector(kStandardDPI * dip_to_pixel_scale_, | 982 frame->set_dpi(DesktopVector(kStandardDPI * dip_to_pixel_scale_, |
931 kStandardDPI * dip_to_pixel_scale_)); | 983 kStandardDPI * dip_to_pixel_scale_)); |
932 return frame; | 984 return frame; |
933 } | 985 } |
934 | 986 |
(...skipping 11 matching lines...) Expand all Loading... | |
946 } | 998 } |
947 | 999 |
948 if (options.detect_updated_region()) { | 1000 if (options.detect_updated_region()) { |
949 capturer.reset(new ScreenCapturerDifferWrapper(std::move(capturer))); | 1001 capturer.reset(new ScreenCapturerDifferWrapper(std::move(capturer))); |
950 } | 1002 } |
951 | 1003 |
952 return capturer.release(); | 1004 return capturer.release(); |
953 } | 1005 } |
954 | 1006 |
955 } // namespace webrtc | 1007 } // namespace webrtc |
OLD | NEW |