OLD | NEW |
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 <X11/extensions/Xdamage.h> | 7 #include <X11/extensions/Xdamage.h> |
8 #include <X11/extensions/Xfixes.h> | 8 #include <X11/extensions/Xfixes.h> |
9 #include <X11/Xlib.h> | 9 #include <X11/Xlib.h> |
10 #include <X11/Xutil.h> | 10 #include <X11/Xutil.h> |
11 | 11 |
12 #include <set> | 12 #include <set> |
13 | 13 |
14 #include "base/basictypes.h" | 14 #include "base/basictypes.h" |
15 #include "base/logging.h" | 15 #include "base/logging.h" |
16 #include "base/memory/scoped_ptr.h" | 16 #include "base/memory/scoped_ptr.h" |
17 #include "base/stl_util.h" | 17 #include "base/stl_util.h" |
18 #include "base/time.h" | |
19 #include "media/video/capture/screen/differ.h" | 18 #include "media/video/capture/screen/differ.h" |
20 #include "media/video/capture/screen/mouse_cursor_shape.h" | 19 #include "media/video/capture/screen/mouse_cursor_shape.h" |
21 #include "media/video/capture/screen/screen_capture_data.h" | |
22 #include "media/video/capture/screen/screen_capture_frame.h" | |
23 #include "media/video/capture/screen/screen_capture_frame_queue.h" | 20 #include "media/video/capture/screen/screen_capture_frame_queue.h" |
24 #include "media/video/capture/screen/screen_capturer_helper.h" | 21 #include "media/video/capture/screen/screen_capturer_helper.h" |
25 #include "media/video/capture/screen/x11/x_server_pixel_buffer.h" | 22 #include "media/video/capture/screen/x11/x_server_pixel_buffer.h" |
| 23 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" |
26 | 24 |
27 namespace media { | 25 namespace media { |
28 | 26 |
29 namespace { | 27 namespace { |
30 | 28 |
31 // A class representing a full-frame pixel buffer. | |
32 class ScreenCaptureFrameLinux : public ScreenCaptureFrame { | |
33 public: | |
34 explicit ScreenCaptureFrameLinux(const SkISize& window_size); | |
35 virtual ~ScreenCaptureFrameLinux(); | |
36 | |
37 private: | |
38 // Allocated pixel buffer. | |
39 scoped_ptr<uint8[]> data_; | |
40 | |
41 DISALLOW_COPY_AND_ASSIGN(ScreenCaptureFrameLinux); | |
42 }; | |
43 | |
44 // A class to perform video frame capturing for Linux. | 29 // A class to perform video frame capturing for Linux. |
45 class ScreenCapturerLinux : public ScreenCapturer { | 30 class ScreenCapturerLinux : public ScreenCapturer { |
46 public: | 31 public: |
47 ScreenCapturerLinux(); | 32 ScreenCapturerLinux(); |
48 virtual ~ScreenCapturerLinux(); | 33 virtual ~ScreenCapturerLinux(); |
49 | 34 |
50 // TODO(ajwong): Do we really want this to be synchronous? | 35 // TODO(ajwong): Do we really want this to be synchronous? |
51 bool Init(bool use_x_damage); | 36 bool Init(bool use_x_damage); |
52 | 37 |
53 // Capturer interface. | 38 // DesktopCapturer interface. |
54 virtual void Start(Delegate* delegate) OVERRIDE; | 39 virtual void Start(Callback* delegate) OVERRIDE; |
55 virtual void CaptureFrame() OVERRIDE; | 40 virtual void Capture(const webrtc::DesktopRegion& region) OVERRIDE; |
| 41 |
| 42 // ScreenCapturer interface. |
| 43 virtual void SetMouseShapeObserver( |
| 44 MouseShapeObserver* mouse_shape_observer) OVERRIDE; |
56 | 45 |
57 private: | 46 private: |
58 void InitXDamage(); | 47 void InitXDamage(); |
59 | 48 |
60 // Read and handle all currently-pending XEvents. | 49 // Read and handle all currently-pending XEvents. |
61 // In the DAMAGE case, process the XDamage events and store the resulting | 50 // In the DAMAGE case, process the XDamage events and store the resulting |
62 // damage rectangles in the ScreenCapturerHelper. | 51 // damage rectangles in the ScreenCapturerHelper. |
63 // In all cases, call ScreenConfigurationChanged() in response to any | 52 // In all cases, call ScreenConfigurationChanged() in response to any |
64 // ConfigNotify events. | 53 // ConfigNotify events. |
65 void ProcessPendingXEvents(); | 54 void ProcessPendingXEvents(); |
66 | 55 |
67 // Capture the cursor image and notify the delegate if it was captured. | 56 // Capture the cursor image and notify the delegate if it was captured. |
68 void CaptureCursor(); | 57 void CaptureCursor(); |
69 | 58 |
70 // Capture screen pixels, and return the data in a new ScreenCaptureData | 59 // Capture screen pixels to the current buffer in the queue. In the DAMAGE |
71 // object, to be freed by the caller. In the DAMAGE case, the | 60 // case, the ScreenCapturerHelper already holds the list of invalid rectangles |
72 // ScreenCapturerHelper already holds the list of invalid rectangles from | 61 // from ProcessPendingXEvents(). In the non-DAMAGE case, this captures the |
73 // ProcessPendingXEvents(). In the non-DAMAGE case, this captures the whole | 62 // whole screen, then calculates some invalid rectangles that include any |
74 // screen, then calculates some invalid rectangles that include any | |
75 // differences between this and the previous capture. | 63 // differences between this and the previous capture. |
76 scoped_refptr<ScreenCaptureData> CaptureScreen(); | 64 webrtc::DesktopFrame* CaptureScreen(); |
77 | 65 |
78 // Called when the screen configuration is changed. |root_window_size| | 66 // Called when the screen configuration is changed. |root_window_size| |
79 // specifies the most recent size of the root window. | 67 // specifies the most recent size of the root window. |
80 void ScreenConfigurationChanged(const SkISize& root_window_size); | 68 void ScreenConfigurationChanged(const webrtc::DesktopSize& root_window_size); |
81 | 69 |
82 // Synchronize the current buffer with |last_buffer_|, by copying pixels from | 70 // Synchronize the current buffer with |last_buffer_|, by copying pixels from |
83 // the area of |last_invalid_rects|. | 71 // the area of |last_invalid_rects|. |
84 // Note this only works on the assumption that kNumBuffers == 2, as | 72 // Note this only works on the assumption that kNumBuffers == 2, as |
85 // |last_invalid_rects| holds the differences from the previous buffer and | 73 // |last_invalid_rects| holds the differences from the previous buffer and |
86 // the one prior to that (which will then be the current buffer). | 74 // the one prior to that (which will then be the current buffer). |
87 void SynchronizeFrame(); | 75 void SynchronizeFrame(); |
88 | 76 |
89 void DeinitXlib(); | 77 void DeinitXlib(); |
90 | 78 |
91 // Capture a rectangle from |x_server_pixel_buffer_|, and copy the data into | 79 // Capture a rectangle from |x_server_pixel_buffer_|, and copy the data into |
92 // |capture_data|. | 80 // |frame|. |
93 void CaptureRect(const SkIRect& rect, ScreenCaptureData* capture_data); | 81 void CaptureRect(const webrtc::DesktopRect& rect, |
| 82 webrtc::DesktopFrame* frame); |
94 | 83 |
95 // We expose two forms of blitting to handle variations in the pixel format. | 84 // We expose two forms of blitting to handle variations in the pixel format. |
96 // In FastBlit, the operation is effectively a memcpy. | 85 // In FastBlit, the operation is effectively a memcpy. |
97 void FastBlit(uint8* image, | 86 void FastBlit(uint8* image, |
98 const SkIRect& rect, | 87 const webrtc::DesktopRect& rect, |
99 ScreenCaptureData* capture_data); | 88 webrtc::DesktopFrame* frame); |
100 void SlowBlit(uint8* image, | 89 void SlowBlit(uint8* image, |
101 const SkIRect& rect, | 90 const webrtc::DesktopRect& rect, |
102 ScreenCaptureData* capture_data); | 91 webrtc::DesktopFrame* frame); |
103 | 92 |
104 // Returns the number of bits |mask| has to be shifted left so its last | 93 // Returns the number of bits |mask| has to be shifted left so its last |
105 // (most-significant) bit set becomes the most-significant bit of the word. | 94 // (most-significant) bit set becomes the most-significant bit of the word. |
106 // When |mask| is 0 the function returns 31. | 95 // When |mask| is 0 the function returns 31. |
107 static uint32 GetRgbShift(uint32 mask); | 96 static uint32 GetRgbShift(uint32 mask); |
108 | 97 |
109 Delegate* delegate_; | 98 Callback* callback_; |
| 99 MouseShapeObserver* mouse_shape_observer_; |
110 | 100 |
111 // X11 graphics context. | 101 // X11 graphics context. |
112 Display* display_; | 102 Display* display_; |
113 GC gc_; | 103 GC gc_; |
114 Window root_window_; | 104 Window root_window_; |
115 | 105 |
116 // Last known dimensions of the root window. | 106 // Last known dimensions of the root window. |
117 SkISize root_window_size_; | 107 webrtc::DesktopSize root_window_size_; |
118 | 108 |
119 // XFixes. | 109 // XFixes. |
120 bool has_xfixes_; | 110 bool has_xfixes_; |
121 int xfixes_event_base_; | 111 int xfixes_event_base_; |
122 int xfixes_error_base_; | 112 int xfixes_error_base_; |
123 | 113 |
124 // XDamage information. | 114 // XDamage information. |
125 bool use_damage_; | 115 bool use_damage_; |
126 Damage damage_handle_; | 116 Damage damage_handle_; |
127 int damage_event_base_; | 117 int damage_event_base_; |
128 int damage_error_base_; | 118 int damage_error_base_; |
129 XserverRegion damage_region_; | 119 XserverRegion damage_region_; |
130 | 120 |
131 // Access to the X Server's pixel buffer. | 121 // Access to the X Server's pixel buffer. |
132 XServerPixelBuffer x_server_pixel_buffer_; | 122 XServerPixelBuffer x_server_pixel_buffer_; |
133 | 123 |
134 // A thread-safe list of invalid rectangles, and the size of the most | 124 // A thread-safe list of invalid rectangles, and the size of the most |
135 // recently captured screen. | 125 // recently captured screen. |
136 ScreenCapturerHelper helper_; | 126 ScreenCapturerHelper helper_; |
137 | 127 |
138 // Queue of the frames buffers. | 128 // Queue of the frames buffers. |
139 ScreenCaptureFrameQueue queue_; | 129 ScreenCaptureFrameQueue queue_; |
140 | 130 |
141 // Invalid region from the previous capture. This is used to synchronize the | 131 // Invalid region from the previous capture. This is used to synchronize the |
142 // current with the last buffer used. | 132 // current with the last buffer used. |
143 SkRegion last_invalid_region_; | 133 webrtc::DesktopRegion last_invalid_region_; |
144 | 134 |
145 // |Differ| for use when polling for changes. | 135 // |Differ| for use when polling for changes. |
146 scoped_ptr<Differ> differ_; | 136 scoped_ptr<Differ> differ_; |
147 | 137 |
148 DISALLOW_COPY_AND_ASSIGN(ScreenCapturerLinux); | 138 DISALLOW_COPY_AND_ASSIGN(ScreenCapturerLinux); |
149 }; | 139 }; |
150 | 140 |
151 ScreenCaptureFrameLinux::ScreenCaptureFrameLinux(const SkISize& window_size) { | |
152 set_bytes_per_row(window_size.width() * ScreenCaptureData::kBytesPerPixel); | |
153 set_dimensions(window_size); | |
154 | |
155 size_t buffer_size = bytes_per_row() * window_size.height(); | |
156 data_.reset(new uint8[buffer_size]); | |
157 set_pixels(data_.get()); | |
158 } | |
159 | |
160 ScreenCaptureFrameLinux::~ScreenCaptureFrameLinux() { | |
161 } | |
162 | |
163 ScreenCapturerLinux::ScreenCapturerLinux() | 141 ScreenCapturerLinux::ScreenCapturerLinux() |
164 : delegate_(NULL), | 142 : callback_(NULL), |
| 143 mouse_shape_observer_(NULL), |
165 display_(NULL), | 144 display_(NULL), |
166 gc_(NULL), | 145 gc_(NULL), |
167 root_window_(BadValue), | 146 root_window_(BadValue), |
168 root_window_size_(SkISize::Make(0, 0)), | |
169 has_xfixes_(false), | 147 has_xfixes_(false), |
170 xfixes_event_base_(-1), | 148 xfixes_event_base_(-1), |
171 xfixes_error_base_(-1), | 149 xfixes_error_base_(-1), |
172 use_damage_(false), | 150 use_damage_(false), |
173 damage_handle_(0), | 151 damage_handle_(0), |
174 damage_event_base_(-1), | 152 damage_event_base_(-1), |
175 damage_error_base_(-1), | 153 damage_error_base_(-1), |
176 damage_region_(0) { | 154 damage_region_(0) { |
177 helper_.SetLogGridSize(4); | 155 helper_.SetLogGridSize(4); |
178 } | 156 } |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
263 if (!damage_region_) { | 241 if (!damage_region_) { |
264 XDamageDestroy(display_, damage_handle_); | 242 XDamageDestroy(display_, damage_handle_); |
265 LOG(ERROR) << "Unable to create XFixes region."; | 243 LOG(ERROR) << "Unable to create XFixes region."; |
266 return; | 244 return; |
267 } | 245 } |
268 | 246 |
269 use_damage_ = true; | 247 use_damage_ = true; |
270 LOG(INFO) << "Using XDamage extension."; | 248 LOG(INFO) << "Using XDamage extension."; |
271 } | 249 } |
272 | 250 |
273 void ScreenCapturerLinux::Start(Delegate* delegate) { | 251 void ScreenCapturerLinux::Start(Callback* callback) { |
274 DCHECK(delegate_ == NULL); | 252 DCHECK(!callback_); |
| 253 DCHECK(callback); |
275 | 254 |
276 delegate_ = delegate; | 255 callback_ = callback; |
277 } | 256 } |
278 | 257 |
279 void ScreenCapturerLinux::CaptureFrame() { | 258 void ScreenCapturerLinux::Capture(const webrtc::DesktopRegion& region) { |
280 base::Time capture_start_time = base::Time::Now(); | 259 base::Time capture_start_time = base::Time::Now(); |
281 | 260 |
| 261 queue_.MoveToNextFrame(); |
| 262 |
282 // Process XEvents for XDamage and cursor shape tracking. | 263 // Process XEvents for XDamage and cursor shape tracking. |
283 ProcessPendingXEvents(); | 264 ProcessPendingXEvents(); |
284 | 265 |
285 // If the current buffer is from an older generation then allocate a new one. | 266 // If the current frame is from an older generation then allocate a new one. |
286 // Note that we can't reallocate other buffers at this point, since the caller | 267 // Note that we can't reallocate other buffers at this point, since the caller |
287 // may still be reading from them. | 268 // may still be reading from them. |
288 if (queue_.current_frame_needs_update()) { | 269 if (!queue_.current_frame()) { |
289 scoped_ptr<ScreenCaptureFrameLinux> buffer(new ScreenCaptureFrameLinux( | 270 scoped_ptr<webrtc::DesktopFrame> frame( |
290 root_window_size_)); | 271 new webrtc::BasicDesktopFrame(root_window_size_)); |
291 queue_.ReplaceCurrentFrame(buffer.PassAs<ScreenCaptureFrame>()); | 272 queue_.ReplaceCurrentFrame(frame.Pass()); |
292 } | 273 } |
293 | 274 |
294 // Refresh the Differ helper used by CaptureFrame(), if needed. | 275 // Refresh the Differ helper used by CaptureFrame(), if needed. |
295 const ScreenCaptureFrame* current_buffer = queue_.current_frame(); | 276 webrtc::DesktopFrame* frame = queue_.current_frame(); |
296 if (!use_damage_ && ( | 277 if (!use_damage_ && ( |
297 !differ_.get() || | 278 !differ_.get() || |
298 (differ_->width() != current_buffer->dimensions().width()) || | 279 (differ_->width() != frame->size().width()) || |
299 (differ_->height() != current_buffer->dimensions().height()) || | 280 (differ_->height() != frame->size().height()) || |
300 (differ_->bytes_per_row() != current_buffer->bytes_per_row()))) { | 281 (differ_->bytes_per_row() != frame->stride()))) { |
301 differ_.reset(new Differ(current_buffer->dimensions().width(), | 282 differ_.reset(new Differ(frame->size().width(), frame->size().height(), |
302 current_buffer->dimensions().height(), | 283 webrtc::DesktopFrame::kBytesPerPixel, |
303 ScreenCaptureData::kBytesPerPixel, | 284 frame->stride())); |
304 current_buffer->bytes_per_row())); | |
305 } | 285 } |
306 | 286 |
307 scoped_refptr<ScreenCaptureData> capture_data(CaptureScreen()); | 287 webrtc::DesktopFrame* result = CaptureScreen(); |
| 288 last_invalid_region_ = result->updated_region(); |
| 289 result->set_capture_time_ms( |
| 290 (base::Time::Now() - capture_start_time).InMillisecondsRoundedUp()); |
| 291 callback_->OnCaptureCompleted(result); |
| 292 } |
308 | 293 |
309 // Swap the current & previous buffers ready for the next capture. | 294 void ScreenCapturerLinux::SetMouseShapeObserver( |
310 last_invalid_region_ = capture_data->dirty_region(); | 295 MouseShapeObserver* mouse_shape_observer) { |
| 296 DCHECK(!mouse_shape_observer_); |
| 297 DCHECK(mouse_shape_observer); |
311 | 298 |
312 queue_.DoneWithCurrentFrame(); | 299 mouse_shape_observer_ = mouse_shape_observer; |
313 | |
314 capture_data->set_capture_time_ms( | |
315 (base::Time::Now() - capture_start_time).InMillisecondsRoundedUp()); | |
316 delegate_->OnCaptureCompleted(capture_data); | |
317 } | 300 } |
318 | 301 |
319 void ScreenCapturerLinux::ProcessPendingXEvents() { | 302 void ScreenCapturerLinux::ProcessPendingXEvents() { |
320 // Find the number of events that are outstanding "now." We don't just loop | 303 // Find the number of events that are outstanding "now." We don't just loop |
321 // on XPending because we want to guarantee this terminates. | 304 // on XPending because we want to guarantee this terminates. |
322 int events_to_process = XPending(display_); | 305 int events_to_process = XPending(display_); |
323 XEvent e; | 306 XEvent e; |
324 | 307 |
325 for (int i = 0; i < events_to_process; i++) { | 308 for (int i = 0; i < events_to_process; i++) { |
326 XNextEvent(display_, &e); | 309 XNextEvent(display_, &e); |
327 if (use_damage_ && (e.type == damage_event_base_ + XDamageNotify)) { | 310 if (use_damage_ && (e.type == damage_event_base_ + XDamageNotify)) { |
328 XDamageNotifyEvent* event = reinterpret_cast<XDamageNotifyEvent*>(&e); | 311 XDamageNotifyEvent* event = reinterpret_cast<XDamageNotifyEvent*>(&e); |
329 DCHECK(event->level == XDamageReportNonEmpty); | 312 DCHECK(event->level == XDamageReportNonEmpty); |
330 } else if (e.type == ConfigureNotify) { | 313 } else if (e.type == ConfigureNotify) { |
331 const XConfigureEvent& event = e.xconfigure; | 314 const XConfigureEvent& event = e.xconfigure; |
332 ScreenConfigurationChanged(SkISize::Make(event.width, event.height)); | 315 ScreenConfigurationChanged( |
| 316 webrtc::DesktopSize(event.width, event.height)); |
333 } else if (has_xfixes_ && | 317 } else if (has_xfixes_ && |
334 e.type == xfixes_event_base_ + XFixesCursorNotify) { | 318 e.type == xfixes_event_base_ + XFixesCursorNotify) { |
335 XFixesCursorNotifyEvent* cne; | 319 XFixesCursorNotifyEvent* cne; |
336 cne = reinterpret_cast<XFixesCursorNotifyEvent*>(&e); | 320 cne = reinterpret_cast<XFixesCursorNotifyEvent*>(&e); |
337 if (cne->subtype == XFixesDisplayCursorNotify) { | 321 if (cne->subtype == XFixesDisplayCursorNotify) { |
338 CaptureCursor(); | 322 CaptureCursor(); |
339 } | 323 } |
340 } else { | 324 } else { |
341 LOG(WARNING) << "Got unknown event type: " << e.type; | 325 LOG(WARNING) << "Got unknown event type: " << e.type; |
342 } | 326 } |
343 } | 327 } |
344 } | 328 } |
345 | 329 |
346 void ScreenCapturerLinux::CaptureCursor() { | 330 void ScreenCapturerLinux::CaptureCursor() { |
347 DCHECK(has_xfixes_); | 331 DCHECK(has_xfixes_); |
348 | 332 |
349 XFixesCursorImage* img = XFixesGetCursorImage(display_); | 333 XFixesCursorImage* img = XFixesGetCursorImage(display_); |
350 if (!img) { | 334 if (!img) { |
351 return; | 335 return; |
352 } | 336 } |
353 | 337 |
354 scoped_ptr<MouseCursorShape> cursor(new MouseCursorShape()); | 338 scoped_ptr<MouseCursorShape> cursor(new MouseCursorShape()); |
355 cursor->size.set(img->width, img->height); | 339 cursor->size = webrtc::DesktopSize(img->width, img->height); |
356 cursor->hotspot.set(img->xhot, img->yhot); | 340 cursor->hotspot = webrtc::DesktopVector(img->xhot, img->yhot); |
357 | 341 |
358 int total_bytes = cursor->size.width() * cursor->size.height() * | 342 int total_bytes = cursor->size.width ()* cursor->size.height() * |
359 ScreenCaptureData::kBytesPerPixel; | 343 webrtc::DesktopFrame::kBytesPerPixel; |
360 cursor->data.resize(total_bytes); | 344 cursor->data.resize(total_bytes); |
361 | 345 |
362 // Xlib stores 32-bit data in longs, even if longs are 64-bits long. | 346 // Xlib stores 32-bit data in longs, even if longs are 64-bits long. |
363 unsigned long* src = img->pixels; | 347 unsigned long* src = img->pixels; |
364 uint32* dst = reinterpret_cast<uint32*>(string_as_array(&cursor->data)); | 348 uint32* dst = reinterpret_cast<uint32*>(string_as_array(&cursor->data)); |
365 uint32* dst_end = dst + (img->width * img->height); | 349 uint32* dst_end = dst + (img->width * img->height); |
366 while (dst < dst_end) { | 350 while (dst < dst_end) { |
367 *dst++ = static_cast<uint32>(*src++); | 351 *dst++ = static_cast<uint32>(*src++); |
368 } | 352 } |
369 XFree(img); | 353 XFree(img); |
370 | 354 |
371 delegate_->OnCursorShapeChanged(cursor.Pass()); | 355 if (mouse_shape_observer_) |
| 356 mouse_shape_observer_->OnCursorShapeChanged(cursor.Pass()); |
372 } | 357 } |
373 | 358 |
374 scoped_refptr<ScreenCaptureData> ScreenCapturerLinux::CaptureScreen() { | 359 webrtc::DesktopFrame* ScreenCapturerLinux::CaptureScreen() { |
375 ScreenCaptureFrame* frame = queue_.current_frame(); | 360 webrtc::DesktopFrame* frame = queue_.current_frame()->Share(); |
376 scoped_refptr<ScreenCaptureData> capture_data(new ScreenCaptureData( | |
377 frame->pixels(), frame->bytes_per_row(), frame->dimensions())); | |
378 | 361 |
379 // Pass the screen size to the helper, so it can clip the invalid region if it | 362 // Pass the screen size to the helper, so it can clip the invalid region if it |
380 // expands that region to a grid. | 363 // expands that region to a grid. |
381 helper_.set_size_most_recent(capture_data->size()); | 364 helper_.set_size_most_recent(frame->size()); |
382 | 365 |
383 // In the DAMAGE case, ensure the frame is up-to-date with the previous frame | 366 // In the DAMAGE case, ensure the frame is up-to-date with the previous frame |
384 // if any. If there isn't a previous frame, that means a screen-resolution | 367 // if any. If there isn't a previous frame, that means a screen-resolution |
385 // change occurred, and |invalid_rects| will be updated to include the whole | 368 // change occurred, and |invalid_rects| will be updated to include the whole |
386 // screen. | 369 // screen. |
387 if (use_damage_ && queue_.previous_frame()) | 370 if (use_damage_ && queue_.previous_frame()) |
388 SynchronizeFrame(); | 371 SynchronizeFrame(); |
389 | 372 |
390 SkRegion invalid_region; | 373 webrtc::DesktopRegion* updated_region = frame->mutable_updated_region(); |
391 | 374 |
392 x_server_pixel_buffer_.Synchronize(); | 375 x_server_pixel_buffer_.Synchronize(); |
393 if (use_damage_ && queue_.previous_frame()) { | 376 if (use_damage_ && queue_.previous_frame()) { |
394 // Atomically fetch and clear the damage region. | 377 // Atomically fetch and clear the damage region. |
395 XDamageSubtract(display_, damage_handle_, None, damage_region_); | 378 XDamageSubtract(display_, damage_handle_, None, damage_region_); |
396 int nRects = 0; | 379 int rects_num = 0; |
397 XRectangle bounds; | 380 XRectangle bounds; |
398 XRectangle* rects = XFixesFetchRegionAndBounds(display_, damage_region_, | 381 XRectangle* rects = XFixesFetchRegionAndBounds(display_, damage_region_, |
399 &nRects, &bounds); | 382 &rects_num, &bounds); |
400 for (int i=0; i<nRects; ++i) { | 383 for (int i = 0; i < rects_num; ++i) { |
401 invalid_region.op(SkIRect::MakeXYWH(rects[i].x, rects[i].y, | 384 updated_region->AddRect(webrtc::DesktopRect::MakeXYWH( |
402 rects[i].width, rects[i].height), | 385 rects[i].x, rects[i].y, rects[i].width, rects[i].height)); |
403 SkRegion::kUnion_Op); | |
404 } | 386 } |
405 XFree(rects); | 387 XFree(rects); |
406 helper_.InvalidateRegion(invalid_region); | 388 helper_.InvalidateRegion(*updated_region); |
407 | 389 |
408 // Capture the damaged portions of the desktop. | 390 // Capture the damaged portions of the desktop. |
409 helper_.SwapInvalidRegion(&invalid_region); | 391 helper_.TakeInvalidRegion(updated_region); |
410 | 392 |
411 // Clip the damaged portions to the current screen size, just in case some | 393 // Clip the damaged portions to the current screen size, just in case some |
412 // spurious XDamage notifications were received for a previous (larger) | 394 // spurious XDamage notifications were received for a previous (larger) |
413 // screen size. | 395 // screen size. |
414 invalid_region.op(SkIRect::MakeSize(root_window_size_), | 396 updated_region->IntersectWith( |
415 SkRegion::kIntersect_Op); | 397 webrtc::DesktopRect::MakeSize(root_window_size_)); |
416 for (SkRegion::Iterator it(invalid_region); !it.done(); it.next()) { | 398 for (webrtc::DesktopRegion::Iterator it(*updated_region); |
417 CaptureRect(it.rect(), capture_data); | 399 !it.IsAtEnd(); it.Advance()) { |
| 400 CaptureRect(it.rect(), frame); |
418 } | 401 } |
419 } else { | 402 } else { |
420 // Doing full-screen polling, or this is the first capture after a | 403 // Doing full-screen polling, or this is the first capture after a |
421 // screen-resolution change. In either case, need a full-screen capture. | 404 // screen-resolution change. In either case, need a full-screen capture. |
422 SkIRect screen_rect = SkIRect::MakeWH(frame->dimensions().width(), | 405 webrtc::DesktopRect screen_rect = |
423 frame->dimensions().height()); | 406 webrtc::DesktopRect::MakeSize(frame->size()); |
424 CaptureRect(screen_rect, capture_data); | 407 CaptureRect(screen_rect, frame); |
425 | 408 |
426 if (queue_.previous_frame()) { | 409 if (queue_.previous_frame()) { |
427 // Full-screen polling, so calculate the invalid rects here, based on the | 410 // Full-screen polling, so calculate the invalid rects here, based on the |
428 // changed pixels between current and previous buffers. | 411 // changed pixels between current and previous buffers. |
429 DCHECK(differ_ != NULL); | 412 DCHECK(differ_ != NULL); |
430 differ_->CalcDirtyRegion(queue_.previous_frame()->pixels(), | 413 DCHECK(queue_.previous_frame()->data()); |
431 frame->pixels(), &invalid_region); | 414 differ_->CalcDirtyRegion(queue_.previous_frame()->data(), |
| 415 frame->data(), updated_region); |
432 } else { | 416 } else { |
433 // No previous buffer, so always invalidate the whole screen, whether | 417 // No previous buffer, so always invalidate the whole screen, whether |
434 // or not DAMAGE is being used. DAMAGE doesn't necessarily send a | 418 // or not DAMAGE is being used. DAMAGE doesn't necessarily send a |
435 // full-screen notification after a screen-resolution change, so | 419 // full-screen notification after a screen-resolution change, so |
436 // this is done here. | 420 // this is done here. |
437 invalid_region.op(screen_rect, SkRegion::kUnion_Op); | 421 updated_region->SetRect(screen_rect); |
438 } | 422 } |
439 } | 423 } |
440 | 424 |
441 capture_data->mutable_dirty_region() = invalid_region; | 425 return frame; |
442 return capture_data; | |
443 } | 426 } |
444 | 427 |
445 void ScreenCapturerLinux::ScreenConfigurationChanged( | 428 void ScreenCapturerLinux::ScreenConfigurationChanged( |
446 const SkISize& root_window_size) { | 429 const webrtc::DesktopSize& root_window_size) { |
447 root_window_size_ = root_window_size; | 430 root_window_size_ = root_window_size; |
448 | 431 |
449 // Make sure the frame buffers will be reallocated. | 432 // Make sure the frame buffers will be reallocated. |
450 queue_.SetAllFramesNeedUpdate(); | 433 queue_.Reset(); |
451 | 434 |
452 helper_.ClearInvalidRegion(); | 435 helper_.ClearInvalidRegion(); |
453 x_server_pixel_buffer_.Init(display_, root_window_size_); | 436 x_server_pixel_buffer_.Init(display_, root_window_size_); |
454 } | 437 } |
455 | 438 |
456 void ScreenCapturerLinux::SynchronizeFrame() { | 439 void ScreenCapturerLinux::SynchronizeFrame() { |
457 // Synchronize the current buffer with the previous one since we do not | 440 // Synchronize the current buffer with the previous one since we do not |
458 // capture the entire desktop. Note that encoder may be reading from the | 441 // capture the entire desktop. Note that encoder may be reading from the |
459 // previous buffer at this time so thread access complaints are false | 442 // previous buffer at this time so thread access complaints are false |
460 // positives. | 443 // positives. |
461 | 444 |
462 // TODO(hclam): We can reduce the amount of copying here by subtracting | 445 // TODO(hclam): We can reduce the amount of copying here by subtracting |
463 // |capturer_helper_|s region from |last_invalid_region_|. | 446 // |capturer_helper_|s region from |last_invalid_region_|. |
464 // http://crbug.com/92354 | 447 // http://crbug.com/92354 |
465 DCHECK(queue_.previous_frame()); | 448 DCHECK(queue_.previous_frame()); |
466 | 449 |
467 ScreenCaptureFrame* current = queue_.current_frame(); | 450 webrtc::DesktopFrame* current = queue_.current_frame(); |
468 ScreenCaptureFrame* last = queue_.previous_frame(); | 451 webrtc::DesktopFrame* last = queue_.previous_frame(); |
469 DCHECK_NE(current, last); | 452 DCHECK_NE(current, last); |
470 for (SkRegion::Iterator it(last_invalid_region_); !it.done(); it.next()) { | 453 for (webrtc::DesktopRegion::Iterator it(last_invalid_region_); |
471 const SkIRect& r = it.rect(); | 454 !it.IsAtEnd(); it.Advance()) { |
472 int offset = r.fTop * current->bytes_per_row() + | 455 const webrtc::DesktopRect& r = it.rect(); |
473 r.fLeft * ScreenCaptureData::kBytesPerPixel; | 456 int offset = r.top() * current->stride() + |
| 457 r.left() * webrtc::DesktopFrame::kBytesPerPixel; |
474 for (int i = 0; i < r.height(); ++i) { | 458 for (int i = 0; i < r.height(); ++i) { |
475 memcpy(current->pixels() + offset, last->pixels() + offset, | 459 memcpy(current->data() + offset, last->data() + offset, |
476 r.width() * ScreenCaptureData::kBytesPerPixel); | 460 r.width() * webrtc::DesktopFrame::kBytesPerPixel); |
477 offset += current->dimensions().width() * | 461 offset += current->size().width() * webrtc::DesktopFrame::kBytesPerPixel; |
478 ScreenCaptureData::kBytesPerPixel; | |
479 } | 462 } |
480 } | 463 } |
481 } | 464 } |
482 | 465 |
483 void ScreenCapturerLinux::DeinitXlib() { | 466 void ScreenCapturerLinux::DeinitXlib() { |
484 if (gc_) { | 467 if (gc_) { |
485 XFreeGC(display_, gc_); | 468 XFreeGC(display_, gc_); |
486 gc_ = NULL; | 469 gc_ = NULL; |
487 } | 470 } |
488 | 471 |
489 x_server_pixel_buffer_.Release(); | 472 x_server_pixel_buffer_.Release(); |
490 | 473 |
491 if (display_) { | 474 if (display_) { |
492 if (damage_handle_) | 475 if (damage_handle_) |
493 XDamageDestroy(display_, damage_handle_); | 476 XDamageDestroy(display_, damage_handle_); |
494 if (damage_region_) | 477 if (damage_region_) |
495 XFixesDestroyRegion(display_, damage_region_); | 478 XFixesDestroyRegion(display_, damage_region_); |
496 XCloseDisplay(display_); | 479 XCloseDisplay(display_); |
497 display_ = NULL; | 480 display_ = NULL; |
498 damage_handle_ = 0; | 481 damage_handle_ = 0; |
499 damage_region_ = 0; | 482 damage_region_ = 0; |
500 } | 483 } |
501 } | 484 } |
502 | 485 |
503 void ScreenCapturerLinux::CaptureRect(const SkIRect& rect, | 486 void ScreenCapturerLinux::CaptureRect(const webrtc::DesktopRect& rect, |
504 ScreenCaptureData* capture_data) { | 487 webrtc::DesktopFrame* frame) { |
505 uint8* image = x_server_pixel_buffer_.CaptureRect(rect); | 488 uint8* image = x_server_pixel_buffer_.CaptureRect(rect); |
506 int depth = x_server_pixel_buffer_.GetDepth(); | 489 int depth = x_server_pixel_buffer_.GetDepth(); |
507 if ((depth == 24 || depth == 32) && | 490 if ((depth == 24 || depth == 32) && |
508 x_server_pixel_buffer_.GetBitsPerPixel() == 32 && | 491 x_server_pixel_buffer_.GetBitsPerPixel() == 32 && |
509 x_server_pixel_buffer_.GetRedMask() == 0xff0000 && | 492 x_server_pixel_buffer_.GetRedMask() == 0xff0000 && |
510 x_server_pixel_buffer_.GetGreenMask() == 0xff00 && | 493 x_server_pixel_buffer_.GetGreenMask() == 0xff00 && |
511 x_server_pixel_buffer_.GetBlueMask() == 0xff) { | 494 x_server_pixel_buffer_.GetBlueMask() == 0xff) { |
512 DVLOG(3) << "Fast blitting"; | 495 DVLOG(3) << "Fast blitting"; |
513 FastBlit(image, rect, capture_data); | 496 FastBlit(image, rect, frame); |
514 } else { | 497 } else { |
515 DVLOG(3) << "Slow blitting"; | 498 DVLOG(3) << "Slow blitting"; |
516 SlowBlit(image, rect, capture_data); | 499 SlowBlit(image, rect, frame); |
517 } | 500 } |
518 } | 501 } |
519 | 502 |
520 void ScreenCapturerLinux::FastBlit(uint8* image, const SkIRect& rect, | 503 void ScreenCapturerLinux::FastBlit(uint8* image, |
521 ScreenCaptureData* capture_data) { | 504 const webrtc::DesktopRect& rect, |
| 505 webrtc::DesktopFrame* frame) { |
522 uint8* src_pos = image; | 506 uint8* src_pos = image; |
523 int src_stride = x_server_pixel_buffer_.GetStride(); | 507 int src_stride = x_server_pixel_buffer_.GetStride(); |
524 int dst_x = rect.fLeft, dst_y = rect.fTop; | 508 int dst_x = rect.left(), dst_y = rect.top(); |
525 | 509 |
526 uint8* dst_pos = capture_data->data() + capture_data->stride() * dst_y; | 510 uint8* dst_pos = frame->data() + frame->stride() * dst_y; |
527 dst_pos += dst_x * ScreenCaptureData::kBytesPerPixel; | 511 dst_pos += dst_x * webrtc::DesktopFrame::kBytesPerPixel; |
528 | 512 |
529 int height = rect.height(); | 513 int height = rect.height(); |
530 int row_bytes = rect.width() * ScreenCaptureData::kBytesPerPixel; | 514 int row_bytes = rect.width() * webrtc::DesktopFrame::kBytesPerPixel; |
531 for (int y = 0; y < height; ++y) { | 515 for (int y = 0; y < height; ++y) { |
532 memcpy(dst_pos, src_pos, row_bytes); | 516 memcpy(dst_pos, src_pos, row_bytes); |
533 src_pos += src_stride; | 517 src_pos += src_stride; |
534 dst_pos += capture_data->stride(); | 518 dst_pos += frame->stride(); |
535 } | 519 } |
536 } | 520 } |
537 | 521 |
538 void ScreenCapturerLinux::SlowBlit(uint8* image, const SkIRect& rect, | 522 void ScreenCapturerLinux::SlowBlit(uint8* image, |
539 ScreenCaptureData* capture_data) { | 523 const webrtc::DesktopRect& rect, |
| 524 webrtc::DesktopFrame* frame) { |
540 int src_stride = x_server_pixel_buffer_.GetStride(); | 525 int src_stride = x_server_pixel_buffer_.GetStride(); |
541 int dst_x = rect.fLeft, dst_y = rect.fTop; | 526 int dst_x = rect.left(), dst_y = rect.top(); |
542 int width = rect.width(), height = rect.height(); | 527 int width = rect.width(), height = rect.height(); |
543 | 528 |
544 uint32 red_mask = x_server_pixel_buffer_.GetRedMask(); | 529 uint32 red_mask = x_server_pixel_buffer_.GetRedMask(); |
545 uint32 green_mask = x_server_pixel_buffer_.GetGreenMask(); | 530 uint32 green_mask = x_server_pixel_buffer_.GetGreenMask(); |
546 uint32 blue_mask = x_server_pixel_buffer_.GetBlueMask(); | 531 uint32 blue_mask = x_server_pixel_buffer_.GetBlueMask(); |
547 | 532 |
548 uint32 red_shift = GetRgbShift(red_mask); | 533 uint32 red_shift = GetRgbShift(red_mask); |
549 uint32 green_shift = GetRgbShift(green_mask); | 534 uint32 green_shift = GetRgbShift(green_mask); |
550 uint32 blue_shift = GetRgbShift(blue_mask); | 535 uint32 blue_shift = GetRgbShift(blue_mask); |
551 | 536 |
552 unsigned int bits_per_pixel = x_server_pixel_buffer_.GetBitsPerPixel(); | 537 unsigned int bits_per_pixel = x_server_pixel_buffer_.GetBitsPerPixel(); |
553 | 538 |
554 uint8* dst_pos = capture_data->data() + capture_data->stride() * dst_y; | 539 uint8* dst_pos = frame->data() + frame->stride() * dst_y; |
555 uint8* src_pos = image; | 540 uint8* src_pos = image; |
556 dst_pos += dst_x * ScreenCaptureData::kBytesPerPixel; | 541 dst_pos += dst_x * webrtc::DesktopFrame::kBytesPerPixel; |
557 // TODO(hclam): Optimize, perhaps using MMX code or by converting to | 542 // TODO(hclam): Optimize, perhaps using MMX code or by converting to |
558 // YUV directly | 543 // YUV directly |
559 for (int y = 0; y < height; y++) { | 544 for (int y = 0; y < height; y++) { |
560 uint32* dst_pos_32 = reinterpret_cast<uint32*>(dst_pos); | 545 uint32* dst_pos_32 = reinterpret_cast<uint32*>(dst_pos); |
561 uint32* src_pos_32 = reinterpret_cast<uint32*>(src_pos); | 546 uint32* src_pos_32 = reinterpret_cast<uint32*>(src_pos); |
562 uint16* src_pos_16 = reinterpret_cast<uint16*>(src_pos); | 547 uint16* src_pos_16 = reinterpret_cast<uint16*>(src_pos); |
563 for (int x = 0; x < width; x++) { | 548 for (int x = 0; x < width; x++) { |
564 // Dereference through an appropriately-aligned pointer. | 549 // Dereference through an appropriately-aligned pointer. |
565 uint32 pixel; | 550 uint32 pixel; |
566 if (bits_per_pixel == 32) | 551 if (bits_per_pixel == 32) |
567 pixel = src_pos_32[x]; | 552 pixel = src_pos_32[x]; |
568 else if (bits_per_pixel == 16) | 553 else if (bits_per_pixel == 16) |
569 pixel = src_pos_16[x]; | 554 pixel = src_pos_16[x]; |
570 else | 555 else |
571 pixel = src_pos[x]; | 556 pixel = src_pos[x]; |
572 uint32 r = (pixel & red_mask) << red_shift; | 557 uint32 r = (pixel & red_mask) << red_shift; |
573 uint32 g = (pixel & green_mask) << green_shift; | 558 uint32 g = (pixel & green_mask) << green_shift; |
574 uint32 b = (pixel & blue_mask) << blue_shift; | 559 uint32 b = (pixel & blue_mask) << blue_shift; |
575 | 560 |
576 // Write as 32-bit RGB. | 561 // Write as 32-bit RGB. |
577 dst_pos_32[x] = ((r >> 8) & 0xff0000) | ((g >> 16) & 0xff00) | | 562 dst_pos_32[x] = ((r >> 8) & 0xff0000) | ((g >> 16) & 0xff00) | |
578 ((b >> 24) & 0xff); | 563 ((b >> 24) & 0xff); |
579 } | 564 } |
580 dst_pos += capture_data->stride(); | 565 dst_pos += frame->stride(); |
581 src_pos += src_stride; | 566 src_pos += src_stride; |
582 } | 567 } |
583 } | 568 } |
584 | 569 |
585 // static | 570 // static |
586 uint32 ScreenCapturerLinux::GetRgbShift(uint32 mask) { | 571 uint32 ScreenCapturerLinux::GetRgbShift(uint32 mask) { |
587 int shift = 0; | 572 int shift = 0; |
588 if ((mask & 0xffff0000u) == 0) { | 573 if ((mask & 0xffff0000u) == 0) { |
589 mask <<= 16; | 574 mask <<= 16; |
590 shift += 16; | 575 shift += 16; |
(...skipping 11 matching lines...) Expand all Loading... |
602 shift += 2; | 587 shift += 2; |
603 } | 588 } |
604 if ((mask & 0x80000000u) == 0) | 589 if ((mask & 0x80000000u) == 0) |
605 shift += 1; | 590 shift += 1; |
606 | 591 |
607 return shift; | 592 return shift; |
608 } | 593 } |
609 | 594 |
610 } // namespace | 595 } // namespace |
611 | 596 |
612 scoped_refptr<SharedBuffer> ScreenCapturer::Delegate::CreateSharedBuffer( | |
613 uint32 size) { | |
614 return scoped_refptr<SharedBuffer>(); | |
615 } | |
616 | |
617 void ScreenCapturer::Delegate::ReleaseSharedBuffer( | |
618 scoped_refptr<SharedBuffer> buffer) { | |
619 } | |
620 | |
621 // static | 597 // static |
622 scoped_ptr<ScreenCapturer> ScreenCapturer::Create() { | 598 scoped_ptr<ScreenCapturer> ScreenCapturer::Create() { |
623 scoped_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux()); | 599 scoped_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux()); |
624 if (!capturer->Init(false)) | 600 if (!capturer->Init(false)) |
625 capturer.reset(); | 601 capturer.reset(); |
626 return capturer.PassAs<ScreenCapturer>(); | 602 return capturer.PassAs<ScreenCapturer>(); |
627 } | 603 } |
628 | 604 |
629 // static | 605 // static |
630 scoped_ptr<ScreenCapturer> ScreenCapturer::CreateWithXDamage( | 606 scoped_ptr<ScreenCapturer> ScreenCapturer::CreateWithXDamage( |
631 bool use_x_damage) { | 607 bool use_x_damage) { |
632 scoped_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux()); | 608 scoped_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux()); |
633 if (!capturer->Init(use_x_damage)) | 609 if (!capturer->Init(use_x_damage)) |
634 capturer.reset(); | 610 capturer.reset(); |
635 return capturer.PassAs<ScreenCapturer>(); | 611 return capturer.PassAs<ScreenCapturer>(); |
636 } | 612 } |
637 | 613 |
638 } // namespace media | 614 } // namespace media |
OLD | NEW |