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

Side by Side Diff: media/video/capture/screen/screen_capturer_mac.mm

Issue 13983010: Use webrtc::DesktopCapturer for screen capturer implementation. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: q Created 7 years, 8 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/video/capture/screen/screen_capturer.h" 5 #include "media/video/capture/screen/screen_capturer.h"
6 6
7 #include <ApplicationServices/ApplicationServices.h> 7 #include <ApplicationServices/ApplicationServices.h>
8 #include <Cocoa/Cocoa.h> 8 #include <Cocoa/Cocoa.h>
9 #include <dlfcn.h> 9 #include <dlfcn.h>
10 #include <IOKit/pwr_mgt/IOPMLib.h> 10 #include <IOKit/pwr_mgt/IOPMLib.h>
11 #include <OpenGL/CGLMacro.h> 11 #include <OpenGL/CGLMacro.h>
12 #include <OpenGL/OpenGL.h> 12 #include <OpenGL/OpenGL.h>
13 #include <stddef.h> 13 #include <stddef.h>
14 #include <set> 14 #include <set>
15 15
16 #include "base/files/file_path.h" 16 #include "base/files/file_path.h"
17 #include "base/logging.h" 17 #include "base/logging.h"
18 #include "base/mac/mac_util.h" 18 #include "base/mac/mac_util.h"
19 #include "base/mac/scoped_cftyperef.h" 19 #include "base/mac/scoped_cftyperef.h"
20 #include "base/memory/scoped_ptr.h" 20 #include "base/memory/scoped_ptr.h"
21 #include "base/scoped_native_library.h" 21 #include "base/scoped_native_library.h"
22 #include "base/synchronization/waitable_event.h" 22 #include "base/synchronization/waitable_event.h"
23 #include "base/time.h" 23 #include "base/time.h"
24 #include "media/video/capture/screen/mac/desktop_configuration.h" 24 #include "media/video/capture/screen/mac/desktop_configuration.h"
25 #include "media/video/capture/screen/mac/scoped_pixel_buffer_object.h" 25 #include "media/video/capture/screen/mac/scoped_pixel_buffer_object.h"
26 #include "media/video/capture/screen/mouse_cursor_shape.h" 26 #include "media/video/capture/screen/mouse_cursor_shape.h"
27 #include "media/video/capture/screen/screen_capture_data.h"
28 #include "media/video/capture/screen/screen_capture_frame.h"
29 #include "media/video/capture/screen/screen_capture_frame_queue.h" 27 #include "media/video/capture/screen/screen_capture_frame_queue.h"
30 #include "media/video/capture/screen/screen_capturer_helper.h" 28 #include "media/video/capture/screen/screen_capturer_helper.h"
31 #include "skia/ext/skia_utils_mac.h" 29 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
30 #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
31 #include "third_party/webrtc/modules/desktop_capture/desktop_region.h"
32 32
33 namespace media { 33 namespace media {
34 34
35 namespace { 35 namespace {
36 36
37 // Definitions used to dynamic-link to deprecated OS 10.6 functions. 37 // Definitions used to dynamic-link to deprecated OS 10.6 functions.
38 const char* kApplicationServicesLibraryName = 38 const char* kApplicationServicesLibraryName =
39 "/System/Library/Frameworks/ApplicationServices.framework/" 39 "/System/Library/Frameworks/ApplicationServices.framework/"
40 "ApplicationServices"; 40 "ApplicationServices";
41 typedef void* (*CGDisplayBaseAddressFunc)(CGDirectDisplayID); 41 typedef void* (*CGDisplayBaseAddressFunc)(CGDirectDisplayID);
42 typedef size_t (*CGDisplayBytesPerRowFunc)(CGDirectDisplayID); 42 typedef size_t (*CGDisplayBytesPerRowFunc)(CGDirectDisplayID);
43 typedef size_t (*CGDisplayBitsPerPixelFunc)(CGDirectDisplayID); 43 typedef size_t (*CGDisplayBitsPerPixelFunc)(CGDirectDisplayID);
44 const char* kOpenGlLibraryName = 44 const char* kOpenGlLibraryName =
45 "/System/Library/Frameworks/OpenGL.framework/OpenGL"; 45 "/System/Library/Frameworks/OpenGL.framework/OpenGL";
46 typedef CGLError (*CGLSetFullScreenFunc)(CGLContextObj); 46 typedef CGLError (*CGLSetFullScreenFunc)(CGLContextObj);
47 47
48 // Standard Mac displays have 72dpi, but we report 96dpi for 48 // Standard Mac displays have 72dpi, but we report 96dpi for
49 // consistency with Windows and Linux. 49 // consistency with Windows and Linux.
50 const int kStandardDPI = 96; 50 const int kStandardDPI = 96;
51 51
52 // skia/ext/skia_utils_mac.h only defines CGRectToSkRect(). 52 // Scales all coordinates of an SkRect by a specified factor.
Wez 2013/04/26 18:48:14 nit: Update comment
Sergey Ulanov 2013/05/07 22:25:50 Done.
53 SkIRect CGRectToSkIRect(const CGRect& rect) { 53 webrtc::DesktopRect ScaleAndRoundCGRect(const CGRect& rect, float scale) {
alexeypa (please no reviews) 2013/04/26 21:33:58 nit: Should |rect| be validated/sanitized before s
Sergey Ulanov 2013/05/07 22:25:50 No, it comes from the OS.
54 SkIRect result; 54 return webrtc::DesktopRect::MakeLTRB(
55 gfx::CGRectToSkRect(rect).round(&result); 55 static_cast<int>(rect.origin.x * scale),
alexeypa (please no reviews) 2013/04/26 21:33:58 I think you need an explicit floor() here and the
Sergey Ulanov 2013/05/07 22:25:50 Float->int cast just truncates the part after the
56 return result; 56 static_cast<int>(rect.origin.y * scale),
57 static_cast<int>(ceil((rect.origin.x + rect.size.width) * scale)),
58 static_cast<int>(ceil((rect.origin.y + rect.size.height) * scale)));
57 } 59 }
58 60
59 // Scales all coordinates of an SkRect by a specified factor. 61 webrtc::DesktopRect TranslateRect(const webrtc::DesktopRect& r,
alexeypa (please no reviews) 2013/04/26 21:33:58 webrtc::DesktopRect already has Translate() method
Sergey Ulanov 2013/05/07 22:25:50 Done.
60 SkRect ScaleSkRect(const SkRect& rect, float scale) { 62 int dx, int dy) {
61 SkRect result = { 63 return webrtc::DesktopRect::MakeXYWH(
62 rect.left() * scale, rect.top() * scale, 64 r.left() + dx, r.top() + dx, r.width(), r.height());
63 rect.right() * scale, rect.bottom() * scale
64 };
65 return result;
66 } 65 }
67 66
68 // Copy pixels in the |rect| from |src_place| to |dest_plane|. 67 // Copy pixels in the |rect| from |src_place| to |dest_plane|.
69 void CopyRect(const uint8* src_plane, 68 void CopyRect(const uint8* src_plane,
alexeypa (please no reviews) 2013/04/26 21:33:58 nit: There is similar remoting::CopyRGB32Rect in r
Sergey Ulanov 2013/05/07 22:25:50 Not related to this CL.
70 int src_plane_stride, 69 int src_plane_stride,
71 uint8* dest_plane, 70 uint8* dest_plane,
72 int dest_plane_stride, 71 int dest_plane_stride,
73 int bytes_per_pixel, 72 int bytes_per_pixel,
74 const SkIRect& rect) { 73 const webrtc::DesktopRect& rect) {
75 // Get the address of the starting point. 74 // Get the address of the starting point.
76 const int src_y_offset = src_plane_stride * rect.top(); 75 const int src_y_offset = src_plane_stride * rect.top();
77 const int dest_y_offset = dest_plane_stride * rect.top(); 76 const int dest_y_offset = dest_plane_stride * rect.top();
78 const int x_offset = bytes_per_pixel * rect.left(); 77 const int x_offset = bytes_per_pixel * rect.left();
79 src_plane += src_y_offset + x_offset; 78 src_plane += src_y_offset + x_offset;
80 dest_plane += dest_y_offset + x_offset; 79 dest_plane += dest_y_offset + x_offset;
81 80
82 // Copy pixels in the rectangle line by line. 81 // Copy pixels in the rectangle line by line.
83 const int bytes_per_line = bytes_per_pixel * rect.width(); 82 const int bytes_per_line = bytes_per_pixel * rect.width();
84 const int height = rect.height(); 83 const int height = rect.height();
85 for (int i = 0 ; i < height; ++i) { 84 for (int i = 0 ; i < height; ++i) {
86 memcpy(dest_plane, src_plane, bytes_per_line); 85 memcpy(dest_plane, src_plane, bytes_per_line);
87 src_plane += src_plane_stride; 86 src_plane += src_plane_stride;
88 dest_plane += dest_plane_stride; 87 dest_plane += dest_plane_stride;
89 } 88 }
90 } 89 }
91 90
92 // The amount of time allowed for displays to reconfigure. 91 // The amount of time allowed for displays to reconfigure.
93 const int64 kDisplayConfigurationEventTimeoutInSeconds = 10; 92 const int64 kDisplayConfigurationEventTimeoutInSeconds = 10;
94 93
95 // A class representing a full-frame pixel buffer.
96 class ScreenCaptureFrameMac : public ScreenCaptureFrame {
97 public:
98 explicit ScreenCaptureFrameMac(const MacDesktopConfiguration& desktop_config);
99 virtual ~ScreenCaptureFrameMac();
100
101 const SkIPoint& dpi() const { return dpi_; }
102
103 private:
104 // Allocated pixel buffer.
105 scoped_ptr<uint8[]> data_;
106
107 // DPI settings for this buffer.
108 SkIPoint dpi_;
109
110 DISALLOW_COPY_AND_ASSIGN(ScreenCaptureFrameMac);
111 };
112
113 // A class to perform video frame capturing for mac. 94 // A class to perform video frame capturing for mac.
114 class ScreenCapturerMac : public ScreenCapturer { 95 class ScreenCapturerMac : public ScreenCapturer {
115 public: 96 public:
116 ScreenCapturerMac(); 97 ScreenCapturerMac();
117 virtual ~ScreenCapturerMac(); 98 virtual ~ScreenCapturerMac();
118 99
119 bool Init(); 100 bool Init();
120 101
121 // Overridden from ScreenCapturer: 102 // Overridden from ScreenCapturer:
122 virtual void Start(Delegate* delegate) OVERRIDE; 103 virtual void Start(Callback* callback) OVERRIDE;
123 virtual void CaptureFrame() OVERRIDE; 104 virtual void Capture(const webrtc::DesktopRegion& region) OVERRIDE;
105 virtual void SetMouseShapeObserver(
106 MouseShapeObserver* mouse_shape_observer) OVERRIDE;
124 107
125 private: 108 private:
126 void CaptureCursor(); 109 void CaptureCursor();
127 110
128 void GlBlitFast(const ScreenCaptureFrame& buffer, const SkRegion& region); 111 void GlBlitFast(const webrtc::DesktopFrame& frame,
129 void GlBlitSlow(const ScreenCaptureFrame& buffer); 112 const webrtc::DesktopRegion& region);
130 void CgBlitPreLion(const ScreenCaptureFrame& buffer, const SkRegion& region); 113 void GlBlitSlow(const webrtc::DesktopFrame& frame);
131 void CgBlitPostLion(const ScreenCaptureFrame& buffer, const SkRegion& region); 114 void CgBlitPreLion(const webrtc::DesktopFrame& frame,
115 const webrtc::DesktopRegion& region);
116 void CgBlitPostLion(const webrtc::DesktopFrame& frame,
117 const webrtc::DesktopRegion& region);
132 118
133 // Called when the screen configuration is changed. 119 // Called when the screen configuration is changed.
134 void ScreenConfigurationChanged(); 120 void ScreenConfigurationChanged();
135 121
136 bool RegisterRefreshAndMoveHandlers(); 122 bool RegisterRefreshAndMoveHandlers();
137 void UnregisterRefreshAndMoveHandlers(); 123 void UnregisterRefreshAndMoveHandlers();
138 124
139 void ScreenRefresh(CGRectCount count, const CGRect *rect_array); 125 void ScreenRefresh(CGRectCount count, const CGRect *rect_array);
140 void ScreenUpdateMove(CGScreenUpdateMoveDelta delta, 126 void ScreenUpdateMove(CGScreenUpdateMoveDelta delta,
141 size_t count, 127 size_t count,
142 const CGRect *rect_array); 128 const CGRect *rect_array);
143 void DisplaysReconfigured(CGDirectDisplayID display, 129 void DisplaysReconfigured(CGDirectDisplayID display,
144 CGDisplayChangeSummaryFlags flags); 130 CGDisplayChangeSummaryFlags flags);
145 static void ScreenRefreshCallback(CGRectCount count, 131 static void ScreenRefreshCallback(CGRectCount count,
146 const CGRect *rect_array, 132 const CGRect *rect_array,
147 void *user_parameter); 133 void *user_parameter);
148 static void ScreenUpdateMoveCallback(CGScreenUpdateMoveDelta delta, 134 static void ScreenUpdateMoveCallback(CGScreenUpdateMoveDelta delta,
149 size_t count, 135 size_t count,
150 const CGRect *rect_array, 136 const CGRect *rect_array,
151 void *user_parameter); 137 void *user_parameter);
152 static void DisplaysReconfiguredCallback(CGDirectDisplayID display, 138 static void DisplaysReconfiguredCallback(CGDirectDisplayID display,
153 CGDisplayChangeSummaryFlags flags, 139 CGDisplayChangeSummaryFlags flags,
154 void *user_parameter); 140 void *user_parameter);
155 141
156 void ReleaseBuffers(); 142 void ReleaseBuffers();
157 143
158 Delegate* delegate_; 144 Callback* callback_;
145 MouseShapeObserver* mouse_shape_observer_;
159 146
160 CGLContextObj cgl_context_; 147 CGLContextObj cgl_context_;
161 ScopedPixelBufferObject pixel_buffer_object_; 148 ScopedPixelBufferObject pixel_buffer_object_;
162 149
163 // Queue of the frames buffers. 150 // Queue of the frames buffers.
164 ScreenCaptureFrameQueue queue_; 151 ScreenCaptureFrameQueue queue_;
165 152
166 // Current display configuration. 153 // Current display configuration.
167 MacDesktopConfiguration desktop_config_; 154 MacDesktopConfiguration desktop_config_;
168 155
169 // A thread-safe list of invalid rectangles, and the size of the most 156 // A thread-safe list of invalid rectangles, and the size of the most
170 // recently captured screen. 157 // recently captured screen.
171 ScreenCapturerHelper helper_; 158 ScreenCapturerHelper helper_;
172 159
173 // Image of the last cursor that we sent to the client. 160 // Image of the last cursor that we sent to the client.
174 base::mac::ScopedCFTypeRef<CGImageRef> current_cursor_; 161 base::mac::ScopedCFTypeRef<CGImageRef> current_cursor_;
175 162
176 // Contains an invalid region from the previous capture. 163 // Contains an invalid region from the previous capture.
177 SkRegion last_invalid_region_; 164 webrtc::DesktopRegion last_invalid_region_;
178 165
179 // Used to ensure that frame captures do not take place while displays 166 // Used to ensure that frame captures do not take place while displays
180 // are being reconfigured. 167 // are being reconfigured.
181 base::WaitableEvent display_configuration_capture_event_; 168 base::WaitableEvent display_configuration_capture_event_;
182 169
183 // Records the Ids of attached displays which are being reconfigured. 170 // Records the Ids of attached displays which are being reconfigured.
184 // Accessed on the thread on which we are notified of display events. 171 // Accessed on the thread on which we are notified of display events.
185 std::set<CGDirectDisplayID> reconfiguring_displays_; 172 std::set<CGDirectDisplayID> reconfiguring_displays_;
186 173
187 // Power management assertion to prevent the screen from sleeping. 174 // Power management assertion to prevent the screen from sleeping.
188 IOPMAssertionID power_assertion_id_display_; 175 IOPMAssertionID power_assertion_id_display_;
189 176
190 // Power management assertion to indicate that the user is active. 177 // Power management assertion to indicate that the user is active.
191 IOPMAssertionID power_assertion_id_user_; 178 IOPMAssertionID power_assertion_id_user_;
192 179
193 // Dynamically link to deprecated APIs for Mac OS X 10.6 support. 180 // Dynamically link to deprecated APIs for Mac OS X 10.6 support.
194 base::ScopedNativeLibrary app_services_library_; 181 base::ScopedNativeLibrary app_services_library_;
195 CGDisplayBaseAddressFunc cg_display_base_address_; 182 CGDisplayBaseAddressFunc cg_display_base_address_;
196 CGDisplayBytesPerRowFunc cg_display_bytes_per_row_; 183 CGDisplayBytesPerRowFunc cg_display_bytes_per_row_;
197 CGDisplayBitsPerPixelFunc cg_display_bits_per_pixel_; 184 CGDisplayBitsPerPixelFunc cg_display_bits_per_pixel_;
198 base::ScopedNativeLibrary opengl_library_; 185 base::ScopedNativeLibrary opengl_library_;
199 CGLSetFullScreenFunc cgl_set_full_screen_; 186 CGLSetFullScreenFunc cgl_set_full_screen_;
200 187
201 DISALLOW_COPY_AND_ASSIGN(ScreenCapturerMac); 188 DISALLOW_COPY_AND_ASSIGN(ScreenCapturerMac);
202 }; 189 };
203 190
204 ScreenCaptureFrameMac::ScreenCaptureFrameMac( 191 scoped_ptr<webrtc::DesktopFrame> CreateFrame(
205 const MacDesktopConfiguration& desktop_config) { 192 const MacDesktopConfiguration& desktop_config) {
206 SkISize size = SkISize::Make(desktop_config.pixel_bounds.width(),
207 desktop_config.pixel_bounds.height());
208 set_bytes_per_row(size.width() * sizeof(uint32_t));
209 set_dimensions(size);
210 193
211 size_t buffer_size = size.width() * size.height() * sizeof(uint32_t); 194 webrtc::DesktopSize size(desktop_config.pixel_bounds.width(),
212 data_.reset(new uint8[buffer_size]); 195 desktop_config.pixel_bounds.height());
213 set_pixels(data_.get()); 196 scoped_ptr<webrtc::DesktopFrame> frame(new webrtc::BasicDesktopFrame(size));
214 197
215 dpi_ = SkIPoint::Make(kStandardDPI * desktop_config.dip_to_pixel_scale, 198 frame->set_dpi(webrtc::DesktopVector(
216 kStandardDPI * desktop_config.dip_to_pixel_scale); 199 kStandardDPI * desktop_config.dip_to_pixel_scale,
217 } 200 kStandardDPI * desktop_config.dip_to_pixel_scale));
218 201 return frame.Pass();
219 ScreenCaptureFrameMac::~ScreenCaptureFrameMac() {
220 } 202 }
221 203
222 ScreenCapturerMac::ScreenCapturerMac() 204 ScreenCapturerMac::ScreenCapturerMac()
223 : delegate_(NULL), 205 : callback_(NULL),
206 mouse_shape_observer_(NULL),
224 cgl_context_(NULL), 207 cgl_context_(NULL),
225 display_configuration_capture_event_(false, true), 208 display_configuration_capture_event_(false, true),
226 power_assertion_id_display_(kIOPMNullAssertionID), 209 power_assertion_id_display_(kIOPMNullAssertionID),
227 power_assertion_id_user_(kIOPMNullAssertionID), 210 power_assertion_id_user_(kIOPMNullAssertionID),
228 cg_display_base_address_(NULL), 211 cg_display_base_address_(NULL),
229 cg_display_bytes_per_row_(NULL), 212 cg_display_bytes_per_row_(NULL),
230 cg_display_bits_per_pixel_(NULL), 213 cg_display_bits_per_pixel_(NULL),
231 cgl_set_full_screen_(NULL) 214 cgl_set_full_screen_(NULL) {
232 {
233 } 215 }
234 216
235 ScreenCapturerMac::~ScreenCapturerMac() { 217 ScreenCapturerMac::~ScreenCapturerMac() {
236 if (power_assertion_id_display_ != kIOPMNullAssertionID) { 218 if (power_assertion_id_display_ != kIOPMNullAssertionID) {
237 IOPMAssertionRelease(power_assertion_id_display_); 219 IOPMAssertionRelease(power_assertion_id_display_);
238 power_assertion_id_display_ = kIOPMNullAssertionID; 220 power_assertion_id_display_ = kIOPMNullAssertionID;
239 } 221 }
240 if (power_assertion_id_user_ != kIOPMNullAssertionID) { 222 if (power_assertion_id_user_ != kIOPMNullAssertionID) {
241 IOPMAssertionRelease(power_assertion_id_user_); 223 IOPMAssertionRelease(power_assertion_id_user_);
242 power_assertion_id_user_ = kIOPMNullAssertionID; 224 power_assertion_id_user_ = kIOPMNullAssertionID;
(...skipping 29 matching lines...) Expand all
272 pixel_buffer_object_.Release(); 254 pixel_buffer_object_.Release();
273 CGLDestroyContext(cgl_context_); 255 CGLDestroyContext(cgl_context_);
274 cgl_context_ = NULL; 256 cgl_context_ = NULL;
275 } 257 }
276 // The buffers might be in use by the encoder, so don't delete them here. 258 // The buffers might be in use by the encoder, so don't delete them here.
277 // Instead, mark them as "needs update"; next time the buffers are used by 259 // Instead, mark them as "needs update"; next time the buffers are used by
278 // the capturer, they will be recreated if necessary. 260 // the capturer, they will be recreated if necessary.
279 queue_.SetAllFramesNeedUpdate(); 261 queue_.SetAllFramesNeedUpdate();
280 } 262 }
281 263
282 void ScreenCapturerMac::Start(Delegate* delegate) { 264 void ScreenCapturerMac::Start(Callback* callback) {
283 DCHECK(delegate_ == NULL); 265 DCHECK(callback_ == NULL);
alexeypa (please no reviews) 2013/04/26 21:33:58 nit: DCHECK(!callback_); Add DCHECK(callback);
Sergey Ulanov 2013/05/07 22:25:50 Done.
284 266
285 delegate_ = delegate; 267 callback_ = callback;
286 268
287 // Create power management assertions to wake the display and prevent it from 269 // Create power management assertions to wake the display and prevent it from
288 // going to sleep on user idle. 270 // going to sleep on user idle.
289 // TODO(jamiewalch): Use IOPMAssertionDeclareUserActivity on 10.7.3 and above 271 // TODO(jamiewalch): Use IOPMAssertionDeclareUserActivity on 10.7.3 and above
290 // instead of the following two assertions. 272 // instead of the following two assertions.
291 IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep, 273 IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep,
292 kIOPMAssertionLevelOn, 274 kIOPMAssertionLevelOn,
293 CFSTR("Chrome Remote Desktop connection active"), 275 CFSTR("Chrome Remote Desktop connection active"),
294 &power_assertion_id_display_); 276 &power_assertion_id_display_);
295 // This assertion ensures that the display is woken up if it already asleep 277 // This assertion ensures that the display is woken up if it already asleep
296 // (as used by Apple Remote Desktop). 278 // (as used by Apple Remote Desktop).
297 IOPMAssertionCreateWithName(CFSTR("UserIsActive"), 279 IOPMAssertionCreateWithName(CFSTR("UserIsActive"),
298 kIOPMAssertionLevelOn, 280 kIOPMAssertionLevelOn,
299 CFSTR("Chrome Remote Desktop connection active"), 281 CFSTR("Chrome Remote Desktop connection active"),
300 &power_assertion_id_user_); 282 &power_assertion_id_user_);
301 } 283 }
302 284
303 void ScreenCapturerMac::CaptureFrame() { 285 void ScreenCapturerMac::Capture(
304 // Only allow captures when the display configuration is not occurring. 286 const webrtc::DesktopRegion& region_to_capture) {
305 scoped_refptr<ScreenCaptureData> data;
306
307 base::Time capture_start_time = base::Time::Now(); 287 base::Time capture_start_time = base::Time::Now();
308 288
309 // Wait until the display configuration is stable. If one or more displays 289 // Wait until the display configuration is stable. If one or more displays
310 // are reconfiguring then |display_configuration_capture_event_| will not be 290 // are reconfiguring then |display_configuration_capture_event_| will not be
311 // set until the reconfiguration completes. 291 // set until the reconfiguration completes.
312 // TODO(wez): Replace this with an early-exit (See crbug.com/104542). 292 // TODO(wez): Replace this with an early-exit (See crbug.com/104542).
313 CHECK(display_configuration_capture_event_.TimedWait( 293 CHECK(display_configuration_capture_event_.TimedWait(
314 base::TimeDelta::FromSeconds( 294 base::TimeDelta::FromSeconds(
315 kDisplayConfigurationEventTimeoutInSeconds))); 295 kDisplayConfigurationEventTimeoutInSeconds)));
316 296
317 SkRegion region; 297 webrtc::DesktopRegion region;
318 helper_.SwapInvalidRegion(&region); 298 helper_.SwapInvalidRegion(&region);
319 299
320 // If the current buffer is from an older generation then allocate a new one. 300 // If the current buffer is from an older generation then allocate a new one.
321 // Note that we can't reallocate other buffers at this point, since the caller 301 // Note that we can't reallocate other buffers at this point, since the caller
322 // may still be reading from them. 302 // may still be reading from them.
323 if (queue_.current_frame_needs_update()) { 303 if (queue_.current_frame_needs_update())
324 scoped_ptr<ScreenCaptureFrameMac> buffer( 304 queue_.ReplaceCurrentFrame(CreateFrame(desktop_config_));
325 new ScreenCaptureFrameMac(desktop_config_));
326 queue_.ReplaceCurrentFrame(buffer.PassAs<ScreenCaptureFrame>());
327 }
328 305
329 ScreenCaptureFrame* current_buffer = queue_.current_frame(); 306 webrtc::DesktopFrame* current_frame = queue_.current_frame();
330 307
331 bool flip = false; // GL capturers need flipping. 308 bool flip = false; // GL capturers need flipping.
332 if (base::mac::IsOSLionOrLater()) { 309 if (base::mac::IsOSLionOrLater()) {
333 // Lion requires us to use their new APIs for doing screen capture. These 310 // Lion requires us to use their new APIs for doing screen capture. These
334 // APIS currently crash on 10.6.8 if there is no monitor attached. 311 // APIS currently crash on 10.6.8 if there is no monitor attached.
335 CgBlitPostLion(*current_buffer, region); 312 CgBlitPostLion(*current_frame, region);
336 } else if (cgl_context_) { 313 } else if (cgl_context_) {
337 flip = true; 314 flip = true;
338 if (pixel_buffer_object_.get() != 0) { 315 if (pixel_buffer_object_.get() != 0) {
339 GlBlitFast(*current_buffer, region); 316 GlBlitFast(*current_frame, region);
340 } else { 317 } else {
341 // See comment in ScopedPixelBufferObject::Init about why the slow 318 // See comment in ScopedPixelBufferObject::Init about why the slow
342 // path is always used on 10.5. 319 // path is always used on 10.5.
343 GlBlitSlow(*current_buffer); 320 GlBlitSlow(*current_frame);
344 } 321 }
345 } else { 322 } else {
346 CgBlitPreLion(*current_buffer, region); 323 CgBlitPreLion(*current_frame, region);
347 } 324 }
348 325
349 uint8* buffer = current_buffer->pixels(); 326 uint8* buffer = current_frame->data();
350 int stride = current_buffer->bytes_per_row(); 327 int stride = current_frame->stride();
351 if (flip) { 328 if (flip) {
352 stride = -stride; 329 stride = -stride;
353 buffer += (current_buffer->dimensions().height() - 1) * 330 buffer += (current_frame->size().height() - 1) *
354 current_buffer->bytes_per_row(); 331 current_frame->stride();
355 } 332 }
356 333
357 data = new ScreenCaptureData(buffer, stride, current_buffer->dimensions()); 334 webrtc::DesktopFrame* new_frame = queue_.EmitCurrentFrameAndMoveToNext();
358 data->set_dpi(static_cast<ScreenCaptureFrameMac*>(current_buffer)->dpi()); 335 *new_frame->mutable_updated_region() = region;
359 data->mutable_dirty_region() = region;
360 336
361 helper_.set_size_most_recent(data->size()); 337 helper_.set_size_most_recent(new_frame->size());
362 338
363 // Signal that we are done capturing data from the display framebuffer, 339 // Signal that we are done capturing data from the display framebuffer,
364 // and accessing display structures. 340 // and accessing display structures.
365 display_configuration_capture_event_.Signal(); 341 display_configuration_capture_event_.Signal();
366 342
367 // Capture the current cursor shape and notify |delegate_| if it has changed. 343 // Capture the current cursor shape and notify |callback_| if it has changed.
368 CaptureCursor(); 344 CaptureCursor();
369 345
370 // Move the capture frame buffer queue on to the next buffer. 346 new_frame->set_capture_time_ms(
371 queue_.DoneWithCurrentFrame(); 347 (base::Time::Now() - capture_start_time).InMillisecondsRoundedUp());
348 callback_->OnCaptureCompleted(new_frame);
349 }
372 350
373 data->set_capture_time_ms( 351 void ScreenCapturerMac::SetMouseShapeObserver(
374 (base::Time::Now() - capture_start_time).InMillisecondsRoundedUp()); 352 MouseShapeObserver* mouse_shape_observer) {
375 delegate_->OnCaptureCompleted(data); 353 mouse_shape_observer_ = mouse_shape_observer;
alexeypa (please no reviews) 2013/04/26 21:33:58 DCHECK(!mouse_shape_observer_); DCHECK(mouse_shape
Sergey Ulanov 2013/05/07 22:25:50 Done.
376 } 354 }
377 355
378 void ScreenCapturerMac::CaptureCursor() { 356 void ScreenCapturerMac::CaptureCursor() {
379 NSCursor* cursor = [NSCursor currentSystemCursor]; 357 NSCursor* cursor = [NSCursor currentSystemCursor];
380 if (cursor == nil) { 358 if (cursor == nil) {
381 return; 359 return;
382 } 360 }
383 361
384 NSImage* nsimage = [cursor image]; 362 NSImage* nsimage = [cursor image];
385 NSPoint hotspot = [cursor hotSpot]; 363 NSPoint hotspot = [cursor hotSpot];
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
441 reinterpret_cast<const char*>(CFDataGetBytePtr(image_data_ref)); 419 reinterpret_cast<const char*>(CFDataGetBytePtr(image_data_ref));
442 int data_size = CFDataGetLength(image_data_ref); 420 int data_size = CFDataGetLength(image_data_ref);
443 421
444 // Create a MouseCursorShape that describes the cursor and pass it to 422 // Create a MouseCursorShape that describes the cursor and pass it to
445 // the client. 423 // the client.
446 scoped_ptr<MouseCursorShape> cursor_shape(new MouseCursorShape()); 424 scoped_ptr<MouseCursorShape> cursor_shape(new MouseCursorShape());
447 cursor_shape->size.set(size.width, size.height); 425 cursor_shape->size.set(size.width, size.height);
448 cursor_shape->hotspot.set(hotspot.x, hotspot.y); 426 cursor_shape->hotspot.set(hotspot.x, hotspot.y);
449 cursor_shape->data.assign(cursor_src_data, cursor_src_data + data_size); 427 cursor_shape->data.assign(cursor_src_data, cursor_src_data + data_size);
450 428
451 delegate_->OnCursorShapeChanged(cursor_shape.Pass()); 429 if (mouse_shape_observer_)
alexeypa (please no reviews) 2013/04/26 21:33:58 Can it be NULL? Will it be better to force it to b
Sergey Ulanov 2013/05/07 22:25:50 Yes. The caller doesn't always care about mouse sh
430 mouse_shape_observer_->OnCursorShapeChanged(cursor_shape.Pass());
452 } 431 }
453 432
454 void ScreenCapturerMac::GlBlitFast(const ScreenCaptureFrame& buffer, 433 void ScreenCapturerMac::GlBlitFast(const webrtc::DesktopFrame& frame,
455 const SkRegion& region) { 434 const webrtc::DesktopRegion& region) {
456 const int buffer_height = buffer.dimensions().height();
457 const int buffer_width = buffer.dimensions().width();
458
459 // Clip to the size of our current screen. 435 // Clip to the size of our current screen.
460 SkIRect clip_rect = SkIRect::MakeWH(buffer_width, buffer_height); 436 webrtc::DesktopRect clip_rect = webrtc::DesktopRect::MakeSize(frame.size());
461 if (queue_.previous_frame()) { 437 if (queue_.previous_frame()) {
462 // We are doing double buffer for the capture data so we just need to copy 438 // We are doing double buffer for the capture data so we just need to copy
463 // the invalid region from the previous capture in the current buffer. 439 // the invalid region from the previous capture in the current buffer.
464 // TODO(hclam): We can reduce the amount of copying here by subtracting 440 // TODO(hclam): We can reduce the amount of copying here by subtracting
465 // |capturer_helper_|s region from |last_invalid_region_|. 441 // |capturer_helper_|s region from |last_invalid_region_|.
466 // http://crbug.com/92354 442 // http://crbug.com/92354
467 443
468 // Since the image obtained from OpenGL is upside-down, need to do some 444 // Since the image obtained from OpenGL is upside-down, need to do some
469 // magic here to copy the correct rectangle. 445 // magic here to copy the correct rectangle.
470 const int y_offset = (buffer_height - 1) * buffer.bytes_per_row(); 446 const int y_offset = (frame.size().width() - 1) * frame.stride();
471 for(SkRegion::Iterator i(last_invalid_region_); !i.done(); i.next()) { 447 for (webrtc::DesktopRegion::Iterator i(last_invalid_region_);
472 SkIRect copy_rect = i.rect(); 448 !i.IsAtEnd(); i.Advance()) {
473 if (copy_rect.intersect(clip_rect)) { 449 webrtc::DesktopRect copy_rect = i.rect();
alexeypa (please no reviews) 2013/04/26 21:33:58 nit: Make |copy_rect| a const reference?
Sergey Ulanov 2013/05/07 22:25:50 It's mutated below.
474 CopyRect(queue_.previous_frame()->pixels() + y_offset, 450 copy_rect.IntersectWith(clip_rect);
475 -buffer.bytes_per_row(), 451 if (!copy_rect.is_empty()) {
476 buffer.pixels() + y_offset, 452 CopyRect(queue_.previous_frame()->data() + y_offset,
477 -buffer.bytes_per_row(), 453 -frame.stride(),
478 4, // Bytes for pixel for RGBA. 454 frame.data() + y_offset,
455 -frame.stride(),
456 webrtc::DesktopFrame::kBytesPerPixel,
479 copy_rect); 457 copy_rect);
480 } 458 }
481 } 459 }
482 } 460 }
483 last_invalid_region_ = region; 461 last_invalid_region_ = region;
484 462
485 CGLContextObj CGL_MACRO_CONTEXT = cgl_context_; 463 CGLContextObj CGL_MACRO_CONTEXT = cgl_context_;
486 glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pixel_buffer_object_.get()); 464 glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pixel_buffer_object_.get());
487 glReadPixels(0, 0, buffer_width, buffer_height, GL_BGRA, GL_UNSIGNED_BYTE, 0); 465 glReadPixels(0, 0, frame.size().height(), frame.size().width(), GL_BGRA,
alexeypa (please no reviews) 2013/04/26 21:33:58 nit: This call seems to assume that frame.stride()
Sergey Ulanov 2013/05/07 22:25:50 Yes, but it has be done in a separate CL in webrtc
466 GL_UNSIGNED_BYTE, 0);
488 GLubyte* ptr = static_cast<GLubyte*>( 467 GLubyte* ptr = static_cast<GLubyte*>(
489 glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB)); 468 glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB));
490 if (ptr == NULL) { 469 if (ptr == NULL) {
491 // If the buffer can't be mapped, assume that it's no longer valid and 470 // If the buffer can't be mapped, assume that it's no longer valid and
492 // release it. 471 // release it.
493 pixel_buffer_object_.Release(); 472 pixel_buffer_object_.Release();
494 } else { 473 } else {
495 // Copy only from the dirty rects. Since the image obtained from OpenGL is 474 // Copy only from the dirty rects. Since the image obtained from OpenGL is
496 // upside-down we need to do some magic here to copy the correct rectangle. 475 // upside-down we need to do some magic here to copy the correct rectangle.
497 const int y_offset = (buffer_height - 1) * buffer.bytes_per_row(); 476 const int y_offset = (frame.size().width() - 1) * frame.stride();
498 for(SkRegion::Iterator i(region); !i.done(); i.next()) { 477 for (webrtc::DesktopRegion::Iterator i(region);
499 SkIRect copy_rect = i.rect(); 478 !i.IsAtEnd(); i.Advance()) {
500 if (copy_rect.intersect(clip_rect)) { 479 webrtc::DesktopRect copy_rect = i.rect();
alexeypa (please no reviews) 2013/04/26 21:33:58 nit: Make |copy_rect| a const reference?
Sergey Ulanov 2013/05/07 22:25:50 see my previous comment.
480 copy_rect.IntersectWith(clip_rect);
481 if (!copy_rect.is_empty()) {
501 CopyRect(ptr + y_offset, 482 CopyRect(ptr + y_offset,
502 -buffer.bytes_per_row(), 483 -frame.stride(),
503 buffer.pixels() + y_offset, 484 frame.data() + y_offset,
504 -buffer.bytes_per_row(), 485 -frame.stride(),
505 4, // Bytes for pixel for RGBA. 486 webrtc::DesktopFrame::kBytesPerPixel,
506 copy_rect); 487 copy_rect);
507 } 488 }
508 } 489 }
509 } 490 }
510 if (!glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB)) { 491 if (!glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB)) {
511 // If glUnmapBuffer returns false, then the contents of the data store are 492 // If glUnmapBuffer returns false, then the contents of the data store are
512 // undefined. This might be because the screen mode has changed, in which 493 // undefined. This might be because the screen mode has changed, in which
513 // case it will be recreated in ScreenConfigurationChanged, but releasing 494 // case it will be recreated in ScreenConfigurationChanged, but releasing
514 // the object here is the best option. Capturing will fall back on 495 // the object here is the best option. Capturing will fall back on
515 // GlBlitSlow until such time as the pixel buffer object is recreated. 496 // GlBlitSlow until such time as the pixel buffer object is recreated.
516 pixel_buffer_object_.Release(); 497 pixel_buffer_object_.Release();
517 } 498 }
518 glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0); 499 glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
519 } 500 }
520 501
521 void ScreenCapturerMac::GlBlitSlow(const ScreenCaptureFrame& buffer) { 502 void ScreenCapturerMac::GlBlitSlow(const webrtc::DesktopFrame& frame) {
522 CGLContextObj CGL_MACRO_CONTEXT = cgl_context_; 503 CGLContextObj CGL_MACRO_CONTEXT = cgl_context_;
523 glReadBuffer(GL_FRONT); 504 glReadBuffer(GL_FRONT);
524 glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); 505 glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
525 glPixelStorei(GL_PACK_ALIGNMENT, 4); // Force 4-byte alignment. 506 glPixelStorei(GL_PACK_ALIGNMENT, 4); // Force 4-byte alignment.
526 glPixelStorei(GL_PACK_ROW_LENGTH, 0); 507 glPixelStorei(GL_PACK_ROW_LENGTH, 0);
527 glPixelStorei(GL_PACK_SKIP_ROWS, 0); 508 glPixelStorei(GL_PACK_SKIP_ROWS, 0);
528 glPixelStorei(GL_PACK_SKIP_PIXELS, 0); 509 glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
529 // Read a block of pixels from the frame buffer. 510 // Read a block of pixels from the frame buffer.
530 glReadPixels(0, 0, buffer.dimensions().width(), buffer.dimensions().height(), 511 glReadPixels(0, 0, frame.size().width(), frame.size().height(),
531 GL_BGRA, GL_UNSIGNED_BYTE, buffer.pixels()); 512 GL_BGRA, GL_UNSIGNED_BYTE, frame.data());
532 glPopClientAttrib(); 513 glPopClientAttrib();
533 } 514 }
534 515
535 void ScreenCapturerMac::CgBlitPreLion(const ScreenCaptureFrame& buffer, 516 void ScreenCapturerMac::CgBlitPreLion(const webrtc::DesktopFrame& frame,
536 const SkRegion& region) { 517 const webrtc::DesktopRegion& region) {
537 const int buffer_height = buffer.dimensions().height();
538
539 // Copy the entire contents of the previous capture buffer, to capture over. 518 // Copy the entire contents of the previous capture buffer, to capture over.
540 // TODO(wez): Get rid of this as per crbug.com/145064, or implement 519 // TODO(wez): Get rid of this as per crbug.com/145064, or implement
541 // crbug.com/92354. 520 // crbug.com/92354.
542 if (queue_.previous_frame()) { 521 if (queue_.previous_frame()) {
543 memcpy(buffer.pixels(), 522 memcpy(frame.data(),
544 queue_.previous_frame()->pixels(), 523 queue_.previous_frame()->data(),
545 buffer.bytes_per_row() * buffer_height); 524 frame.stride() * frame.size().width());
alexeypa (please no reviews) 2013/04/26 21:33:58 width() -> height()
Sergey Ulanov 2013/05/07 22:25:50 Done.
546 } 525 }
547 526
548 for (size_t i = 0; i < desktop_config_.displays.size(); ++i) { 527 for (size_t i = 0; i < desktop_config_.displays.size(); ++i) {
549 const MacDisplayConfiguration& display_config = desktop_config_.displays[i]; 528 const MacDisplayConfiguration& display_config = desktop_config_.displays[i];
550 529
551 // Use deprecated APIs to determine the display buffer layout. 530 // Use deprecated APIs to determine the display buffer layout.
552 DCHECK(cg_display_base_address_ && cg_display_bytes_per_row_ && 531 DCHECK(cg_display_base_address_ && cg_display_bytes_per_row_ &&
553 cg_display_bits_per_pixel_); 532 cg_display_bits_per_pixel_);
554 uint8* display_base_address = 533 uint8* display_base_address =
555 reinterpret_cast<uint8*>((*cg_display_base_address_)(display_config.id)); 534 reinterpret_cast<uint8*>((*cg_display_base_address_)(display_config.id));
556 CHECK(display_base_address); 535 CHECK(display_base_address);
557 int src_bytes_per_row = (*cg_display_bytes_per_row_)(display_config.id); 536 int src_bytes_per_row = (*cg_display_bytes_per_row_)(display_config.id);
558 int src_bytes_per_pixel = 537 int src_bytes_per_pixel =
559 (*cg_display_bits_per_pixel_)(display_config.id) / 8; 538 (*cg_display_bits_per_pixel_)(display_config.id) / 8;
560 539
561 // Determine the display's position relative to the desktop, in pixels. 540 // Determine the display's position relative to the desktop, in pixels.
562 SkIRect display_bounds = display_config.pixel_bounds; 541 webrtc::DesktopRect display_bounds = display_config.pixel_bounds;
563 display_bounds.offset(-desktop_config_.pixel_bounds.left(), 542 display_bounds.Translate(-desktop_config_.pixel_bounds.left(),
564 -desktop_config_.pixel_bounds.top()); 543 -desktop_config_.pixel_bounds.top());
565 544
566 // Determine which parts of the blit region, if any, lay within the monitor. 545 // Determine which parts of the blit region, if any, lay within the monitor.
567 SkRegion copy_region; 546 webrtc::DesktopRegion copy_region;
568 if (!copy_region.op(region, display_bounds, SkRegion::kIntersect_Op)) 547 copy_region.IntersectWith(display_bounds);
548 if (copy_region.is_empty())
alexeypa (please no reviews) 2013/04/26 21:33:58 This will always be true because an empty |copy_re
Sergey Ulanov 2013/05/07 22:25:50 Done.
569 continue; 549 continue;
570 550
571 // Translate the region to be copied into display-relative coordinates. 551 // Translate the region to be copied into display-relative coordinates.
572 copy_region.translate(-display_bounds.left(), -display_bounds.top()); 552 copy_region.Translate(-display_bounds.left(), -display_bounds.top());
573 553
574 // Calculate where in the output buffer the display's origin is. 554 // Calculate where in the output buffer the display's origin is.
575 uint8* out_ptr = buffer.pixels() + 555 uint8* out_ptr = frame.data() +
576 (display_bounds.left() * src_bytes_per_pixel) + 556 (display_bounds.left() * src_bytes_per_pixel) +
577 (display_bounds.top() * buffer.bytes_per_row()); 557 (display_bounds.top() * frame.stride());
578 558
579 // Copy the dirty region from the display buffer into our desktop buffer. 559 // Copy the dirty region from the display buffer into our desktop buffer.
580 for(SkRegion::Iterator i(copy_region); !i.done(); i.next()) { 560 for (webrtc::DesktopRegion::Iterator i(copy_region);
561 !i.IsAtEnd(); i.Advance()) {
581 CopyRect(display_base_address, 562 CopyRect(display_base_address,
582 src_bytes_per_row, 563 src_bytes_per_row,
583 out_ptr, 564 out_ptr,
584 buffer.bytes_per_row(), 565 frame.stride(),
585 src_bytes_per_pixel, 566 src_bytes_per_pixel,
586 i.rect()); 567 i.rect());
587 } 568 }
588 } 569 }
589 } 570 }
590 571
591 void ScreenCapturerMac::CgBlitPostLion(const ScreenCaptureFrame& buffer, 572 void ScreenCapturerMac::CgBlitPostLion(const webrtc::DesktopFrame& frame,
592 const SkRegion& region) { 573 const webrtc::DesktopRegion& region) {
593 const int buffer_height = buffer.dimensions().height();
594
595 // Copy the entire contents of the previous capture buffer, to capture over. 574 // Copy the entire contents of the previous capture buffer, to capture over.
596 // TODO(wez): Get rid of this as per crbug.com/145064, or implement 575 // TODO(wez): Get rid of this as per crbug.com/145064, or implement
597 // crbug.com/92354. 576 // crbug.com/92354.
598 if (queue_.previous_frame()) { 577 if (queue_.previous_frame()) {
599 memcpy(buffer.pixels(), 578 memcpy(frame.data(),
600 queue_.previous_frame()->pixels(), 579 queue_.previous_frame()->data(),
601 buffer.bytes_per_row() * buffer_height); 580 frame.stride() * frame.size().width());
alexeypa (please no reviews) 2013/04/26 21:33:58 width() -> height().
Sergey Ulanov 2013/05/07 22:25:50 Thanks for catching it!
602 } 581 }
603 582
604 for (size_t i = 0; i < desktop_config_.displays.size(); ++i) { 583 for (size_t i = 0; i < desktop_config_.displays.size(); ++i) {
605 const MacDisplayConfiguration& display_config = desktop_config_.displays[i]; 584 const MacDisplayConfiguration& display_config = desktop_config_.displays[i];
606 585
607 // Determine the display's position relative to the desktop, in pixels. 586 // Determine the display's position relative to the desktop, in pixels.
608 SkIRect display_bounds = display_config.pixel_bounds; 587 webrtc::DesktopRect display_bounds = display_config.pixel_bounds;
609 display_bounds.offset(-desktop_config_.pixel_bounds.left(), 588 display_bounds.Translate(-desktop_config_.pixel_bounds.left(),
610 -desktop_config_.pixel_bounds.top()); 589 -desktop_config_.pixel_bounds.top());
611 590
612 // Determine which parts of the blit region, if any, lay within the monitor. 591 // Determine which parts of the blit region, if any, lay within the monitor.
613 SkRegion copy_region; 592 webrtc::DesktopRegion copy_region = region;
614 if (!copy_region.op(region, display_bounds, SkRegion::kIntersect_Op)) 593 copy_region.IntersectWith(display_bounds);
594 if (copy_region.is_empty())
alexeypa (please no reviews) 2013/04/26 21:33:58 Same as above.
Sergey Ulanov 2013/05/07 22:25:50 Here copy_region is set to region.
615 continue; 595 continue;
616 596
617 // Translate the region to be copied into display-relative coordinates. 597 // Translate the region to be copied into display-relative coordinates.
618 copy_region.translate(-display_bounds.left(), -display_bounds.top()); 598 copy_region.Translate(-display_bounds.left(), -display_bounds.top());
619 599
620 // Create an image containing a snapshot of the display. 600 // Create an image containing a snapshot of the display.
621 base::mac::ScopedCFTypeRef<CGImageRef> image( 601 base::mac::ScopedCFTypeRef<CGImageRef> image(
622 CGDisplayCreateImage(display_config.id)); 602 CGDisplayCreateImage(display_config.id));
623 if (image.get() == NULL) 603 if (image.get() == NULL)
624 continue; 604 continue;
625 605
626 // Request access to the raw pixel data via the image's DataProvider. 606 // Request access to the raw pixel data via the image's DataProvider.
627 CGDataProviderRef provider = CGImageGetDataProvider(image); 607 CGDataProviderRef provider = CGImageGetDataProvider(image);
628 base::mac::ScopedCFTypeRef<CFDataRef> data( 608 base::mac::ScopedCFTypeRef<CFDataRef> data(
629 CGDataProviderCopyData(provider)); 609 CGDataProviderCopyData(provider));
630 if (data.get() == NULL) 610 if (data.get() == NULL)
631 continue; 611 continue;
632 612
633 const uint8* display_base_address = CFDataGetBytePtr(data); 613 const uint8* display_base_address = CFDataGetBytePtr(data);
634 int src_bytes_per_row = CGImageGetBytesPerRow(image); 614 int src_bytes_per_row = CGImageGetBytesPerRow(image);
635 int src_bytes_per_pixel = CGImageGetBitsPerPixel(image) / 8; 615 int src_bytes_per_pixel = CGImageGetBitsPerPixel(image) / 8;
636 616
637 // Calculate where in the output buffer the display's origin is. 617 // Calculate where in the output buffer the display's origin is.
638 uint8* out_ptr = buffer.pixels() + 618 uint8* out_ptr = frame.data() +
alexeypa (please no reviews) 2013/04/26 21:33:58 This logic can be moved to DesktopFrame itself. Th
Sergey Ulanov 2013/05/07 22:25:50 Maybe, but it's not related to this CL.
639 (display_bounds.left() * src_bytes_per_pixel) + 619 (display_bounds.left() * src_bytes_per_pixel) +
640 (display_bounds.top() * buffer.bytes_per_row()); 620 (display_bounds.top() * frame.stride());
641 621
642 // Copy the dirty region from the display buffer into our desktop buffer. 622 // Copy the dirty region from the display buffer into our desktop buffer.
643 for (SkRegion::Iterator i(copy_region); !i.done(); i.next()) { 623 for (webrtc::DesktopRegion::Iterator i(copy_region);
624 !i.IsAtEnd(); i.Advance()) {
644 CopyRect(display_base_address, 625 CopyRect(display_base_address,
645 src_bytes_per_row, 626 src_bytes_per_row,
646 out_ptr, 627 out_ptr,
647 buffer.bytes_per_row(), 628 frame.stride(),
648 src_bytes_per_pixel, 629 src_bytes_per_pixel,
649 i.rect()); 630 i.rect());
650 } 631 }
651 } 632 }
652 } 633 }
653 634
654 void ScreenCapturerMac::ScreenConfigurationChanged() { 635 void ScreenCapturerMac::ScreenConfigurationChanged() {
655 // Release existing buffers, which will be of the wrong size. 636 // Release existing buffers, which will be of the wrong size.
656 ReleaseBuffers(); 637 ReleaseBuffers();
657 638
658 // Clear the dirty region, in case the display is down-sizing. 639 // Clear the dirty region, in case the display is down-sizing.
659 helper_.ClearInvalidRegion(); 640 helper_.ClearInvalidRegion();
660 641
661 // Refresh the cached desktop configuration. 642 // Refresh the cached desktop configuration.
662 desktop_config_ = MacDesktopConfiguration::GetCurrent( 643 desktop_config_ = MacDesktopConfiguration::GetCurrent(
663 MacDesktopConfiguration::TopLeftOrigin); 644 MacDesktopConfiguration::TopLeftOrigin);
664 645
665 // Re-mark the entire desktop as dirty. 646 // Re-mark the entire desktop as dirty.
666 helper_.InvalidateScreen( 647 helper_.InvalidateScreen(
667 SkISize::Make(desktop_config_.pixel_bounds.width(), 648 webrtc::DesktopSize(desktop_config_.pixel_bounds.width(),
668 desktop_config_.pixel_bounds.height())); 649 desktop_config_.pixel_bounds.height()));
669 650
670 // Make sure the frame buffers will be reallocated. 651 // Make sure the frame buffers will be reallocated.
671 queue_.SetAllFramesNeedUpdate(); 652 queue_.SetAllFramesNeedUpdate();
672 653
673 // CgBlitPostLion uses CGDisplayCreateImage() to snapshot each display's 654 // CgBlitPostLion uses CGDisplayCreateImage() to snapshot each display's
674 // contents. Although the API exists in OS 10.6, it crashes the caller if 655 // contents. Although the API exists in OS 10.6, it crashes the caller if
675 // the machine has no monitor connected, so we fall back to depcreated APIs 656 // the machine has no monitor connected, so we fall back to depcreated APIs
676 // when running on 10.6. 657 // when running on 10.6.
677 if (base::mac::IsOSLionOrLater()) { 658 if (base::mac::IsOSLionOrLater()) {
678 LOG(INFO) << "Using CgBlitPostLion."; 659 LOG(INFO) << "Using CgBlitPostLion.";
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
761 742
762 void ScreenCapturerMac::UnregisterRefreshAndMoveHandlers() { 743 void ScreenCapturerMac::UnregisterRefreshAndMoveHandlers() {
763 CGUnregisterScreenRefreshCallback( 744 CGUnregisterScreenRefreshCallback(
764 ScreenCapturerMac::ScreenRefreshCallback, this); 745 ScreenCapturerMac::ScreenRefreshCallback, this);
765 CGScreenUnregisterMoveCallback( 746 CGScreenUnregisterMoveCallback(
766 ScreenCapturerMac::ScreenUpdateMoveCallback, this); 747 ScreenCapturerMac::ScreenUpdateMoveCallback, this);
767 } 748 }
768 749
769 void ScreenCapturerMac::ScreenRefresh(CGRectCount count, 750 void ScreenCapturerMac::ScreenRefresh(CGRectCount count,
770 const CGRect* rect_array) { 751 const CGRect* rect_array) {
771 if (desktop_config_.pixel_bounds.isEmpty()) { 752 if (desktop_config_.pixel_bounds.is_empty())
772 return; 753 return;
773 } 754
774 SkIRect skirect_array[count]; 755 webrtc::DesktopRegion region;
775 756
776 for (CGRectCount i = 0; i < count; ++i) { 757 for (CGRectCount i = 0; i < count; ++i) {
777 SkRect sk_rect = gfx::CGRectToSkRect(rect_array[i]);
778
779 // Convert from Density-Independent Pixel to physical pixel coordinates. 758 // Convert from Density-Independent Pixel to physical pixel coordinates.
780 sk_rect = ScaleSkRect(sk_rect, desktop_config_.dip_to_pixel_scale); 759 webrtc::DesktopRect rect =
781 sk_rect.round(&skirect_array[i]); 760 ScaleAndRoundCGRect(rect_array[i], desktop_config_.dip_to_pixel_scale);
782 761
783 // Translate from local desktop to capturer framebuffer coordinates. 762 // Translate from local desktop to capturer framebuffer coordinates.
784 skirect_array[i].offset(-desktop_config_.pixel_bounds.left(), 763 rect = TranslateRect(rect,
alexeypa (please no reviews) 2013/04/26 21:33:58 nit: use DesktopRect::Translate() here
Sergey Ulanov 2013/05/07 22:25:50 Done.
785 -desktop_config_.pixel_bounds.top()); 764 -desktop_config_.pixel_bounds.left(),
765 -desktop_config_.pixel_bounds.top());
766
767 region.AddRect(rect);
786 } 768 }
787 769
788 SkRegion region;
789 region.setRects(skirect_array, count);
alexeypa (please no reviews) 2013/04/26 21:33:58 nit: SkRegion::setRects can be more optimal than a
Sergey Ulanov 2013/05/07 22:25:50 in skia setRects() is not faster - in fact it just
790 helper_.InvalidateRegion(region); 770 helper_.InvalidateRegion(region);
791 } 771 }
792 772
793 void ScreenCapturerMac::ScreenUpdateMove(CGScreenUpdateMoveDelta delta, 773 void ScreenCapturerMac::ScreenUpdateMove(CGScreenUpdateMoveDelta delta,
794 size_t count, 774 size_t count,
795 const CGRect* rect_array) { 775 const CGRect* rect_array) {
796 // Translate |rect_array| to identify the move's destination. 776 // Translate |rect_array| to identify the move's destination.
797 CGRect refresh_rects[count]; 777 CGRect refresh_rects[count];
798 for (CGRectCount i = 0; i < count; ++i) { 778 for (CGRectCount i = 0; i < count; ++i) {
799 refresh_rects[i] = CGRectOffset(rect_array[i], delta.dX, delta.dY); 779 refresh_rects[i] = CGRectOffset(rect_array[i], delta.dX, delta.dY);
(...skipping 28 matching lines...) Expand all
828 // the reconfiguration handler itself). 808 // the reconfiguration handler itself).
829 UnregisterRefreshAndMoveHandlers(); 809 UnregisterRefreshAndMoveHandlers();
830 RegisterRefreshAndMoveHandlers(); 810 RegisterRefreshAndMoveHandlers();
831 ScreenConfigurationChanged(); 811 ScreenConfigurationChanged();
832 display_configuration_capture_event_.Signal(); 812 display_configuration_capture_event_.Signal();
833 } 813 }
834 } 814 }
835 } 815 }
836 816
837 void ScreenCapturerMac::ScreenRefreshCallback(CGRectCount count, 817 void ScreenCapturerMac::ScreenRefreshCallback(CGRectCount count,
838 const CGRect* rect_array, 818 const CGRect* rect_array,
839 void* user_parameter) { 819 void* user_parameter) {
840 ScreenCapturerMac* capturer = reinterpret_cast<ScreenCapturerMac*>( 820 ScreenCapturerMac* capturer = reinterpret_cast<ScreenCapturerMac*>(
841 user_parameter); 821 user_parameter);
842 if (capturer->desktop_config_.pixel_bounds.isEmpty()) { 822 if (capturer->desktop_config_.pixel_bounds.is_empty()) {
843 capturer->ScreenConfigurationChanged(); 823 capturer->ScreenConfigurationChanged();
844 } 824 }
845 capturer->ScreenRefresh(count, rect_array); 825 capturer->ScreenRefresh(count, rect_array);
846 } 826 }
847 827
848 void ScreenCapturerMac::ScreenUpdateMoveCallback( 828 void ScreenCapturerMac::ScreenUpdateMoveCallback(
849 CGScreenUpdateMoveDelta delta, 829 CGScreenUpdateMoveDelta delta,
850 size_t count, 830 size_t count,
851 const CGRect* rect_array, 831 const CGRect* rect_array,
852 void* user_parameter) { 832 void* user_parameter) {
853 ScreenCapturerMac* capturer = reinterpret_cast<ScreenCapturerMac*>( 833 ScreenCapturerMac* capturer = reinterpret_cast<ScreenCapturerMac*>(
854 user_parameter); 834 user_parameter);
855 capturer->ScreenUpdateMove(delta, count, rect_array); 835 capturer->ScreenUpdateMove(delta, count, rect_array);
856 } 836 }
857 837
858 void ScreenCapturerMac::DisplaysReconfiguredCallback( 838 void ScreenCapturerMac::DisplaysReconfiguredCallback(
859 CGDirectDisplayID display, 839 CGDirectDisplayID display,
860 CGDisplayChangeSummaryFlags flags, 840 CGDisplayChangeSummaryFlags flags,
861 void* user_parameter) { 841 void* user_parameter) {
862 ScreenCapturerMac* capturer = reinterpret_cast<ScreenCapturerMac*>( 842 ScreenCapturerMac* capturer = reinterpret_cast<ScreenCapturerMac*>(
863 user_parameter); 843 user_parameter);
864 capturer->DisplaysReconfigured(display, flags); 844 capturer->DisplaysReconfigured(display, flags);
865 } 845 }
866 846
867 } // namespace 847 } // namespace
868 848
869 scoped_refptr<SharedBuffer> ScreenCapturer::Delegate::CreateSharedBuffer(
870 uint32 size) {
871 return scoped_refptr<SharedBuffer>();
872 }
873
874 void ScreenCapturer::Delegate::ReleaseSharedBuffer(
875 scoped_refptr<SharedBuffer> buffer) {
876 }
877
878 // static 849 // static
879 scoped_ptr<ScreenCapturer> ScreenCapturer::Create() { 850 scoped_ptr<ScreenCapturer> ScreenCapturer::Create() {
880 scoped_ptr<ScreenCapturerMac> capturer(new ScreenCapturerMac()); 851 scoped_ptr<ScreenCapturerMac> capturer(new ScreenCapturerMac());
881 if (!capturer->Init()) 852 if (!capturer->Init())
882 capturer.reset(); 853 capturer.reset();
883 return capturer.PassAs<ScreenCapturer>(); 854 return capturer.PassAs<ScreenCapturer>();
884 } 855 }
885 856
886 } // namespace media 857 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698