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

Side by Side Diff: media/video/capture/screen/screen_capturer_x11.cc

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, 7 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 <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 in the current buffer in the queue. In the DAMAGE
alexeypa (please no reviews) 2013/04/26 21:33:58 nit: "to the current buffer".
Sergey Ulanov 2013/05/07 22:25:50 Done.
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 void 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
alexeypa (please no reviews) 2013/04/26 21:33:58 nit: no need for this empty line.
Sergey Ulanov 2013/05/07 22:25:50 Done.
100 MouseShapeObserver* mouse_shape_observer_;
110 101
111 // X11 graphics context. 102 // X11 graphics context.
112 Display* display_; 103 Display* display_;
113 GC gc_; 104 GC gc_;
114 Window root_window_; 105 Window root_window_;
115 106
116 // Last known dimensions of the root window. 107 // Last known dimensions of the root window.
117 SkISize root_window_size_; 108 webrtc::DesktopSize root_window_size_;
118 109
119 // XFixes. 110 // XFixes.
120 bool has_xfixes_; 111 bool has_xfixes_;
121 int xfixes_event_base_; 112 int xfixes_event_base_;
122 int xfixes_error_base_; 113 int xfixes_error_base_;
123 114
124 // XDamage information. 115 // XDamage information.
125 bool use_damage_; 116 bool use_damage_;
126 Damage damage_handle_; 117 Damage damage_handle_;
127 int damage_event_base_; 118 int damage_event_base_;
128 int damage_error_base_; 119 int damage_error_base_;
129 XserverRegion damage_region_; 120 XserverRegion damage_region_;
130 121
131 // Access to the X Server's pixel buffer. 122 // Access to the X Server's pixel buffer.
132 XServerPixelBuffer x_server_pixel_buffer_; 123 XServerPixelBuffer x_server_pixel_buffer_;
133 124
134 // A thread-safe list of invalid rectangles, and the size of the most 125 // A thread-safe list of invalid rectangles, and the size of the most
135 // recently captured screen. 126 // recently captured screen.
136 ScreenCapturerHelper helper_; 127 ScreenCapturerHelper helper_;
137 128
138 // Queue of the frames buffers. 129 // Queue of the frames buffers.
139 ScreenCaptureFrameQueue queue_; 130 ScreenCaptureFrameQueue queue_;
140 131
141 // Invalid region from the previous capture. This is used to synchronize the 132 // Invalid region from the previous capture. This is used to synchronize the
142 // current with the last buffer used. 133 // current with the last buffer used.
143 SkRegion last_invalid_region_; 134 webrtc::DesktopRegion last_invalid_region_;
144 135
145 // |Differ| for use when polling for changes. 136 // |Differ| for use when polling for changes.
146 scoped_ptr<Differ> differ_; 137 scoped_ptr<Differ> differ_;
147 138
148 DISALLOW_COPY_AND_ASSIGN(ScreenCapturerLinux); 139 DISALLOW_COPY_AND_ASSIGN(ScreenCapturerLinux);
149 }; 140 };
150 141
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() 142 ScreenCapturerLinux::ScreenCapturerLinux()
164 : delegate_(NULL), 143 : callback_(NULL),
144 mouse_shape_observer_(NULL),
165 display_(NULL), 145 display_(NULL),
166 gc_(NULL), 146 gc_(NULL),
167 root_window_(BadValue), 147 root_window_(BadValue),
168 root_window_size_(SkISize::Make(0, 0)),
169 has_xfixes_(false), 148 has_xfixes_(false),
170 xfixes_event_base_(-1), 149 xfixes_event_base_(-1),
171 xfixes_error_base_(-1), 150 xfixes_error_base_(-1),
172 use_damage_(false), 151 use_damage_(false),
173 damage_handle_(0), 152 damage_handle_(0),
174 damage_event_base_(-1), 153 damage_event_base_(-1),
175 damage_error_base_(-1), 154 damage_error_base_(-1),
176 damage_region_(0) { 155 damage_region_(0) {
177 helper_.SetLogGridSize(4); 156 helper_.SetLogGridSize(4);
178 } 157 }
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
263 if (!damage_region_) { 242 if (!damage_region_) {
264 XDamageDestroy(display_, damage_handle_); 243 XDamageDestroy(display_, damage_handle_);
265 LOG(ERROR) << "Unable to create XFixes region."; 244 LOG(ERROR) << "Unable to create XFixes region.";
266 return; 245 return;
267 } 246 }
268 247
269 use_damage_ = true; 248 use_damage_ = true;
270 LOG(INFO) << "Using XDamage extension."; 249 LOG(INFO) << "Using XDamage extension.";
271 } 250 }
272 251
273 void ScreenCapturerLinux::Start(Delegate* delegate) { 252 void ScreenCapturerLinux::Start(Callback* callback) {
274 DCHECK(delegate_ == NULL); 253 DCHECK(callback_ == NULL);
alexeypa (please no reviews) 2013/04/26 21:33:58 DCHECK(!callback_); DCHECK(callback);
Sergey Ulanov 2013/05/07 22:25:50 Done.
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
282 // Process XEvents for XDamage and cursor shape tracking. 261 // Process XEvents for XDamage and cursor shape tracking.
283 ProcessPendingXEvents(); 262 ProcessPendingXEvents();
284 263
285 // If the current buffer is from an older generation then allocate a new one. 264 // 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 265 // Note that we can't reallocate other buffers at this point, since the caller
287 // may still be reading from them. 266 // may still be reading from them.
288 if (queue_.current_frame_needs_update()) { 267 if (queue_.current_frame_needs_update()) {
289 scoped_ptr<ScreenCaptureFrameLinux> buffer(new ScreenCaptureFrameLinux( 268 scoped_ptr<webrtc::DesktopFrame> frame(
290 root_window_size_)); 269 new webrtc::BasicDesktopFrame(root_window_size_));
291 queue_.ReplaceCurrentFrame(buffer.PassAs<ScreenCaptureFrame>()); 270 queue_.ReplaceCurrentFrame(frame.Pass());
292 } 271 }
293 272
294 // Refresh the Differ helper used by CaptureFrame(), if needed. 273 // Refresh the Differ helper used by CaptureFrame(), if needed.
295 const ScreenCaptureFrame* current_buffer = queue_.current_frame(); 274 webrtc::DesktopFrame* frame = queue_.current_frame();
296 if (!use_damage_ && ( 275 if (!use_damage_ && (
297 !differ_.get() || 276 !differ_.get() ||
298 (differ_->width() != current_buffer->dimensions().width()) || 277 (differ_->width() != frame->size().width()) ||
299 (differ_->height() != current_buffer->dimensions().height()) || 278 (differ_->height() != frame->size().height()) ||
300 (differ_->bytes_per_row() != current_buffer->bytes_per_row()))) { 279 (differ_->bytes_per_row() != frame->stride()))) {
301 differ_.reset(new Differ(current_buffer->dimensions().width(), 280 differ_.reset(new Differ(frame->size().width(), frame->size().height(),
302 current_buffer->dimensions().height(), 281 webrtc::DesktopFrame::kBytesPerPixel,
303 ScreenCaptureData::kBytesPerPixel, 282 frame->stride()));
304 current_buffer->bytes_per_row()));
305 } 283 }
306 284
307 scoped_refptr<ScreenCaptureData> capture_data(CaptureScreen()); 285 CaptureScreen();
308 286
309 // Swap the current & previous buffers ready for the next capture. 287 queue_.current_frame()->set_capture_time_ms(
alexeypa (please no reviews) 2013/04/26 21:33:58 nit: queue_.current_frame() -> frame.
Sergey Ulanov 2013/05/07 22:25:50 Done.
310 last_invalid_region_ = capture_data->dirty_region(); 288 (base::Time::Now() - capture_start_time).InMillisecondsRoundedUp());
289 callback_->OnCaptureCompleted(queue_.EmitCurrentFrameAndMoveToNext());
290 }
311 291
312 queue_.DoneWithCurrentFrame(); 292 void ScreenCapturerLinux::SetMouseShapeObserver(
313 293 MouseShapeObserver* mouse_shape_observer) {
314 capture_data->set_capture_time_ms( 294 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.
315 (base::Time::Now() - capture_start_time).InMillisecondsRoundedUp());
316 delegate_->OnCaptureCompleted(capture_data);
317 } 295 }
318 296
319 void ScreenCapturerLinux::ProcessPendingXEvents() { 297 void ScreenCapturerLinux::ProcessPendingXEvents() {
320 // Find the number of events that are outstanding "now." We don't just loop 298 // Find the number of events that are outstanding "now." We don't just loop
321 // on XPending because we want to guarantee this terminates. 299 // on XPending because we want to guarantee this terminates.
322 int events_to_process = XPending(display_); 300 int events_to_process = XPending(display_);
323 XEvent e; 301 XEvent e;
324 302
325 for (int i = 0; i < events_to_process; i++) { 303 for (int i = 0; i < events_to_process; i++) {
326 XNextEvent(display_, &e); 304 XNextEvent(display_, &e);
327 if (use_damage_ && (e.type == damage_event_base_ + XDamageNotify)) { 305 if (use_damage_ && (e.type == damage_event_base_ + XDamageNotify)) {
328 XDamageNotifyEvent* event = reinterpret_cast<XDamageNotifyEvent*>(&e); 306 XDamageNotifyEvent* event = reinterpret_cast<XDamageNotifyEvent*>(&e);
329 DCHECK(event->level == XDamageReportNonEmpty); 307 DCHECK(event->level == XDamageReportNonEmpty);
330 } else if (e.type == ConfigureNotify) { 308 } else if (e.type == ConfigureNotify) {
331 const XConfigureEvent& event = e.xconfigure; 309 const XConfigureEvent& event = e.xconfigure;
332 ScreenConfigurationChanged(SkISize::Make(event.width, event.height)); 310 ScreenConfigurationChanged(
311 webrtc::DesktopSize(event.width, event.height));
333 } else if (has_xfixes_ && 312 } else if (has_xfixes_ &&
334 e.type == xfixes_event_base_ + XFixesCursorNotify) { 313 e.type == xfixes_event_base_ + XFixesCursorNotify) {
335 XFixesCursorNotifyEvent* cne; 314 XFixesCursorNotifyEvent* cne;
336 cne = reinterpret_cast<XFixesCursorNotifyEvent*>(&e); 315 cne = reinterpret_cast<XFixesCursorNotifyEvent*>(&e);
337 if (cne->subtype == XFixesDisplayCursorNotify) { 316 if (cne->subtype == XFixesDisplayCursorNotify) {
338 CaptureCursor(); 317 CaptureCursor();
339 } 318 }
340 } else { 319 } else {
341 LOG(WARNING) << "Got unknown event type: " << e.type; 320 LOG(WARNING) << "Got unknown event type: " << e.type;
342 } 321 }
343 } 322 }
344 } 323 }
345 324
346 void ScreenCapturerLinux::CaptureCursor() { 325 void ScreenCapturerLinux::CaptureCursor() {
347 DCHECK(has_xfixes_); 326 DCHECK(has_xfixes_);
348 327
349 XFixesCursorImage* img = XFixesGetCursorImage(display_); 328 XFixesCursorImage* img = XFixesGetCursorImage(display_);
350 if (!img) { 329 if (!img) {
351 return; 330 return;
352 } 331 }
353 332
354 scoped_ptr<MouseCursorShape> cursor(new MouseCursorShape()); 333 scoped_ptr<MouseCursorShape> cursor(new MouseCursorShape());
355 cursor->size.set(img->width, img->height); 334 cursor->size = webrtc::DesktopSize(img->width, img->height);
356 cursor->hotspot.set(img->xhot, img->yhot); 335 cursor->hotspot = webrtc::DesktopVector(img->xhot, img->yhot);
357 336
358 int total_bytes = cursor->size.width() * cursor->size.height() * 337 int total_bytes = cursor->size.width ()* cursor->size.height() *
359 ScreenCaptureData::kBytesPerPixel; 338 webrtc::DesktopFrame::kBytesPerPixel;
360 cursor->data.resize(total_bytes); 339 cursor->data.resize(total_bytes);
361 340
362 // Xlib stores 32-bit data in longs, even if longs are 64-bits long. 341 // Xlib stores 32-bit data in longs, even if longs are 64-bits long.
363 unsigned long* src = img->pixels; 342 unsigned long* src = img->pixels;
364 uint32* dst = reinterpret_cast<uint32*>(string_as_array(&cursor->data)); 343 uint32* dst = reinterpret_cast<uint32*>(string_as_array(&cursor->data));
365 uint32* dst_end = dst + (img->width * img->height); 344 uint32* dst_end = dst + (img->width * img->height);
366 while (dst < dst_end) { 345 while (dst < dst_end) {
367 *dst++ = static_cast<uint32>(*src++); 346 *dst++ = static_cast<uint32>(*src++);
368 } 347 }
369 XFree(img); 348 XFree(img);
370 349
371 delegate_->OnCursorShapeChanged(cursor.Pass()); 350 if (mouse_shape_observer_)
alexeypa (please no reviews) 2013/04/26 21:33:58 Can it be NULL?
Sergey Ulanov 2013/05/07 22:25:50 yes
351 mouse_shape_observer_->OnCursorShapeChanged(cursor.Pass());
372 } 352 }
373 353
374 scoped_refptr<ScreenCaptureData> ScreenCapturerLinux::CaptureScreen() { 354 void ScreenCapturerLinux::CaptureScreen() {
375 ScreenCaptureFrame* frame = queue_.current_frame(); 355 webrtc::DesktopFrame* frame = queue_.current_frame();
376 scoped_refptr<ScreenCaptureData> capture_data(new ScreenCaptureData(
377 frame->pixels(), frame->bytes_per_row(), frame->dimensions()));
378 356
379 // Pass the screen size to the helper, so it can clip the invalid region if it 357 // Pass the screen size to the helper, so it can clip the invalid region if it
380 // expands that region to a grid. 358 // expands that region to a grid.
381 helper_.set_size_most_recent(capture_data->size()); 359 helper_.set_size_most_recent(frame->size());
382 360
383 // In the DAMAGE case, ensure the frame is up-to-date with the previous frame 361 // 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 362 // 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 363 // change occurred, and |invalid_rects| will be updated to include the whole
386 // screen. 364 // screen.
387 if (use_damage_ && queue_.previous_frame()) 365 if (use_damage_ && queue_.previous_frame())
388 SynchronizeFrame(); 366 SynchronizeFrame();
389 367
390 SkRegion invalid_region; 368 webrtc::DesktopRegion invalid_region;
391 369
392 x_server_pixel_buffer_.Synchronize(); 370 x_server_pixel_buffer_.Synchronize();
393 if (use_damage_ && queue_.previous_frame()) { 371 if (use_damage_ && queue_.previous_frame()) {
394 // Atomically fetch and clear the damage region. 372 // Atomically fetch and clear the damage region.
395 XDamageSubtract(display_, damage_handle_, None, damage_region_); 373 XDamageSubtract(display_, damage_handle_, None, damage_region_);
396 int nRects = 0; 374 int nRects = 0;
397 XRectangle bounds; 375 XRectangle bounds;
398 XRectangle* rects = XFixesFetchRegionAndBounds(display_, damage_region_, 376 XRectangle* rects = XFixesFetchRegionAndBounds(display_, damage_region_,
399 &nRects, &bounds); 377 &nRects, &bounds);
400 for (int i=0; i<nRects; ++i) { 378 for (int i=0; i<nRects; ++i) {
alexeypa (please no reviews) 2013/04/26 21:33:58 nit: for (int i = 0; i < nRects; ++i) {
Sergey Ulanov 2013/05/07 22:25:50 Done.
401 invalid_region.op(SkIRect::MakeXYWH(rects[i].x, rects[i].y, 379 invalid_region.AddRect(webrtc::DesktopRect::MakeXYWH(
402 rects[i].width, rects[i].height), 380 rects[i].x, rects[i].y, rects[i].width, rects[i].height));
403 SkRegion::kUnion_Op);
404 } 381 }
405 XFree(rects); 382 XFree(rects);
406 helper_.InvalidateRegion(invalid_region); 383 helper_.InvalidateRegion(invalid_region);
407 384
408 // Capture the damaged portions of the desktop. 385 // Capture the damaged portions of the desktop.
409 helper_.SwapInvalidRegion(&invalid_region); 386 helper_.SwapInvalidRegion(&invalid_region);
410 387
411 // Clip the damaged portions to the current screen size, just in case some 388 // Clip the damaged portions to the current screen size, just in case some
412 // spurious XDamage notifications were received for a previous (larger) 389 // spurious XDamage notifications were received for a previous (larger)
413 // screen size. 390 // screen size.
414 invalid_region.op(SkIRect::MakeSize(root_window_size_), 391 invalid_region.IntersectWith(
415 SkRegion::kIntersect_Op); 392 webrtc::DesktopRect::MakeSize(root_window_size_));
416 for (SkRegion::Iterator it(invalid_region); !it.done(); it.next()) { 393 for (webrtc::DesktopRegion::Iterator it(invalid_region);
417 CaptureRect(it.rect(), capture_data); 394 !it.IsAtEnd(); it.Advance()) {
395 CaptureRect(it.rect(), frame);
418 } 396 }
419 } else { 397 } else {
420 // Doing full-screen polling, or this is the first capture after a 398 // Doing full-screen polling, or this is the first capture after a
421 // screen-resolution change. In either case, need a full-screen capture. 399 // screen-resolution change. In either case, need a full-screen capture.
422 SkIRect screen_rect = SkIRect::MakeWH(frame->dimensions().width(), 400 webrtc::DesktopRect screen_rect =
423 frame->dimensions().height()); 401 webrtc::DesktopRect::MakeSize(frame->size());
424 CaptureRect(screen_rect, capture_data); 402 CaptureRect(screen_rect, frame);
425 403
426 if (queue_.previous_frame()) { 404 if (queue_.previous_frame()) {
427 // Full-screen polling, so calculate the invalid rects here, based on the 405 // Full-screen polling, so calculate the invalid rects here, based on the
428 // changed pixels between current and previous buffers. 406 // changed pixels between current and previous buffers.
429 DCHECK(differ_ != NULL); 407 DCHECK(differ_ != NULL);
430 differ_->CalcDirtyRegion(queue_.previous_frame()->pixels(), 408 DCHECK(queue_.previous_frame()->data());
431 frame->pixels(), &invalid_region); 409 differ_->CalcDirtyRegion(queue_.previous_frame()->data(),
410 frame->data(), &invalid_region);
432 } else { 411 } else {
433 // No previous buffer, so always invalidate the whole screen, whether 412 // No previous buffer, so always invalidate the whole screen, whether
434 // or not DAMAGE is being used. DAMAGE doesn't necessarily send a 413 // or not DAMAGE is being used. DAMAGE doesn't necessarily send a
435 // full-screen notification after a screen-resolution change, so 414 // full-screen notification after a screen-resolution change, so
436 // this is done here. 415 // this is done here.
437 invalid_region.op(screen_rect, SkRegion::kUnion_Op); 416 invalid_region.SetRect(screen_rect);
438 } 417 }
439 } 418 }
440 419
441 capture_data->mutable_dirty_region() = invalid_region; 420 last_invalid_region_ = invalid_region;
442 return capture_data; 421 *frame->mutable_updated_region() = invalid_region;
443 } 422 }
444 423
445 void ScreenCapturerLinux::ScreenConfigurationChanged( 424 void ScreenCapturerLinux::ScreenConfigurationChanged(
446 const SkISize& root_window_size) { 425 const webrtc::DesktopSize& root_window_size) {
447 root_window_size_ = root_window_size; 426 root_window_size_ = root_window_size;
448 427
449 // Make sure the frame buffers will be reallocated. 428 // Make sure the frame buffers will be reallocated.
450 queue_.SetAllFramesNeedUpdate(); 429 queue_.SetAllFramesNeedUpdate();
451 430
452 helper_.ClearInvalidRegion(); 431 helper_.ClearInvalidRegion();
453 x_server_pixel_buffer_.Init(display_, root_window_size_); 432 x_server_pixel_buffer_.Init(display_, root_window_size_);
454 } 433 }
455 434
456 void ScreenCapturerLinux::SynchronizeFrame() { 435 void ScreenCapturerLinux::SynchronizeFrame() {
457 // Synchronize the current buffer with the previous one since we do not 436 // 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 437 // capture the entire desktop. Note that encoder may be reading from the
459 // previous buffer at this time so thread access complaints are false 438 // previous buffer at this time so thread access complaints are false
460 // positives. 439 // positives.
461 440
462 // TODO(hclam): We can reduce the amount of copying here by subtracting 441 // TODO(hclam): We can reduce the amount of copying here by subtracting
463 // |capturer_helper_|s region from |last_invalid_region_|. 442 // |capturer_helper_|s region from |last_invalid_region_|.
464 // http://crbug.com/92354 443 // http://crbug.com/92354
465 DCHECK(queue_.previous_frame()); 444 DCHECK(queue_.previous_frame());
466 445
467 ScreenCaptureFrame* current = queue_.current_frame(); 446 webrtc::DesktopFrame* current = queue_.current_frame();
468 ScreenCaptureFrame* last = queue_.previous_frame(); 447 webrtc::DesktopFrame* last = queue_.previous_frame();
469 DCHECK_NE(current, last); 448 DCHECK_NE(current, last);
470 for (SkRegion::Iterator it(last_invalid_region_); !it.done(); it.next()) { 449 for (webrtc::DesktopRegion::Iterator it(last_invalid_region_);
471 const SkIRect& r = it.rect(); 450 !it.IsAtEnd(); it.Advance()) {
472 int offset = r.fTop * current->bytes_per_row() + 451 const webrtc::DesktopRect& r = it.rect();
473 r.fLeft * ScreenCaptureData::kBytesPerPixel; 452 int offset = r.top() * current->stride() +
alexeypa (please no reviews) 2013/04/26 21:33:58 nit: move getting pointer to the pixel at given co
Sergey Ulanov 2013/05/07 22:25:50 That would require changes in DesktopFrame. I don'
453 r.left() * webrtc::DesktopFrame::kBytesPerPixel;
474 for (int i = 0; i < r.height(); ++i) { 454 for (int i = 0; i < r.height(); ++i) {
475 memcpy(current->pixels() + offset, last->pixels() + offset, 455 memcpy(current->data() + offset, last->data() + offset,
476 r.width() * ScreenCaptureData::kBytesPerPixel); 456 r.width() * webrtc::DesktopFrame::kBytesPerPixel);
477 offset += current->dimensions().width() * 457 offset += current->size().width() * webrtc::DesktopFrame::kBytesPerPixel;
478 ScreenCaptureData::kBytesPerPixel;
479 } 458 }
480 } 459 }
481 } 460 }
482 461
483 void ScreenCapturerLinux::DeinitXlib() { 462 void ScreenCapturerLinux::DeinitXlib() {
484 if (gc_) { 463 if (gc_) {
485 XFreeGC(display_, gc_); 464 XFreeGC(display_, gc_);
486 gc_ = NULL; 465 gc_ = NULL;
487 } 466 }
488 467
489 x_server_pixel_buffer_.Release(); 468 x_server_pixel_buffer_.Release();
490 469
491 if (display_) { 470 if (display_) {
492 if (damage_handle_) 471 if (damage_handle_)
493 XDamageDestroy(display_, damage_handle_); 472 XDamageDestroy(display_, damage_handle_);
494 if (damage_region_) 473 if (damage_region_)
495 XFixesDestroyRegion(display_, damage_region_); 474 XFixesDestroyRegion(display_, damage_region_);
496 XCloseDisplay(display_); 475 XCloseDisplay(display_);
497 display_ = NULL; 476 display_ = NULL;
498 damage_handle_ = 0; 477 damage_handle_ = 0;
499 damage_region_ = 0; 478 damage_region_ = 0;
500 } 479 }
501 } 480 }
502 481
503 void ScreenCapturerLinux::CaptureRect(const SkIRect& rect, 482 void ScreenCapturerLinux::CaptureRect(const webrtc::DesktopRect& rect,
504 ScreenCaptureData* capture_data) { 483 webrtc::DesktopFrame* frame) {
505 uint8* image = x_server_pixel_buffer_.CaptureRect(rect); 484 uint8* image = x_server_pixel_buffer_.CaptureRect(rect);
506 int depth = x_server_pixel_buffer_.GetDepth(); 485 int depth = x_server_pixel_buffer_.GetDepth();
507 if ((depth == 24 || depth == 32) && 486 if ((depth == 24 || depth == 32) &&
508 x_server_pixel_buffer_.GetBitsPerPixel() == 32 && 487 x_server_pixel_buffer_.GetBitsPerPixel() == 32 &&
509 x_server_pixel_buffer_.GetRedMask() == 0xff0000 && 488 x_server_pixel_buffer_.GetRedMask() == 0xff0000 &&
510 x_server_pixel_buffer_.GetGreenMask() == 0xff00 && 489 x_server_pixel_buffer_.GetGreenMask() == 0xff00 &&
511 x_server_pixel_buffer_.GetBlueMask() == 0xff) { 490 x_server_pixel_buffer_.GetBlueMask() == 0xff) {
512 DVLOG(3) << "Fast blitting"; 491 DVLOG(3) << "Fast blitting";
513 FastBlit(image, rect, capture_data); 492 FastBlit(image, rect, frame);
514 } else { 493 } else {
515 DVLOG(3) << "Slow blitting"; 494 DVLOG(3) << "Slow blitting";
516 SlowBlit(image, rect, capture_data); 495 SlowBlit(image, rect, frame);
517 } 496 }
518 } 497 }
519 498
520 void ScreenCapturerLinux::FastBlit(uint8* image, const SkIRect& rect, 499 void ScreenCapturerLinux::FastBlit(uint8* image,
521 ScreenCaptureData* capture_data) { 500 const webrtc::DesktopRect& rect,
501 webrtc::DesktopFrame* frame) {
522 uint8* src_pos = image; 502 uint8* src_pos = image;
523 int src_stride = x_server_pixel_buffer_.GetStride(); 503 int src_stride = x_server_pixel_buffer_.GetStride();
524 int dst_x = rect.fLeft, dst_y = rect.fTop; 504 int dst_x = rect.left(), dst_y = rect.top();
525 505
526 uint8* dst_pos = capture_data->data() + capture_data->stride() * dst_y; 506 uint8* dst_pos = frame->data() + frame->stride() * dst_y;
527 dst_pos += dst_x * ScreenCaptureData::kBytesPerPixel; 507 dst_pos += dst_x * webrtc::DesktopFrame::kBytesPerPixel;
528 508
529 int height = rect.height(); 509 int height = rect.height();
530 int row_bytes = rect.width() * ScreenCaptureData::kBytesPerPixel; 510 int row_bytes = rect.width() * webrtc::DesktopFrame::kBytesPerPixel;
531 for (int y = 0; y < height; ++y) { 511 for (int y = 0; y < height; ++y) {
532 memcpy(dst_pos, src_pos, row_bytes); 512 memcpy(dst_pos, src_pos, row_bytes);
533 src_pos += src_stride; 513 src_pos += src_stride;
534 dst_pos += capture_data->stride(); 514 dst_pos += frame->stride();
535 } 515 }
536 } 516 }
537 517
538 void ScreenCapturerLinux::SlowBlit(uint8* image, const SkIRect& rect, 518 void ScreenCapturerLinux::SlowBlit(uint8* image,
539 ScreenCaptureData* capture_data) { 519 const webrtc::DesktopRect& rect,
520 webrtc::DesktopFrame* frame) {
540 int src_stride = x_server_pixel_buffer_.GetStride(); 521 int src_stride = x_server_pixel_buffer_.GetStride();
541 int dst_x = rect.fLeft, dst_y = rect.fTop; 522 int dst_x = rect.left(), dst_y = rect.top();
542 int width = rect.width(), height = rect.height(); 523 int width = rect.width(), height = rect.height();
543 524
544 uint32 red_mask = x_server_pixel_buffer_.GetRedMask(); 525 uint32 red_mask = x_server_pixel_buffer_.GetRedMask();
545 uint32 green_mask = x_server_pixel_buffer_.GetGreenMask(); 526 uint32 green_mask = x_server_pixel_buffer_.GetGreenMask();
546 uint32 blue_mask = x_server_pixel_buffer_.GetBlueMask(); 527 uint32 blue_mask = x_server_pixel_buffer_.GetBlueMask();
547 528
548 uint32 red_shift = GetRgbShift(red_mask); 529 uint32 red_shift = GetRgbShift(red_mask);
549 uint32 green_shift = GetRgbShift(green_mask); 530 uint32 green_shift = GetRgbShift(green_mask);
550 uint32 blue_shift = GetRgbShift(blue_mask); 531 uint32 blue_shift = GetRgbShift(blue_mask);
551 532
552 unsigned int bits_per_pixel = x_server_pixel_buffer_.GetBitsPerPixel(); 533 unsigned int bits_per_pixel = x_server_pixel_buffer_.GetBitsPerPixel();
553 534
554 uint8* dst_pos = capture_data->data() + capture_data->stride() * dst_y; 535 uint8* dst_pos = frame->data() + frame->stride() * dst_y;
555 uint8* src_pos = image; 536 uint8* src_pos = image;
556 dst_pos += dst_x * ScreenCaptureData::kBytesPerPixel; 537 dst_pos += dst_x * webrtc::DesktopFrame::kBytesPerPixel;
557 // TODO(hclam): Optimize, perhaps using MMX code or by converting to 538 // TODO(hclam): Optimize, perhaps using MMX code or by converting to
558 // YUV directly 539 // YUV directly
559 for (int y = 0; y < height; y++) { 540 for (int y = 0; y < height; y++) {
560 uint32* dst_pos_32 = reinterpret_cast<uint32*>(dst_pos); 541 uint32* dst_pos_32 = reinterpret_cast<uint32*>(dst_pos);
561 uint32* src_pos_32 = reinterpret_cast<uint32*>(src_pos); 542 uint32* src_pos_32 = reinterpret_cast<uint32*>(src_pos);
562 uint16* src_pos_16 = reinterpret_cast<uint16*>(src_pos); 543 uint16* src_pos_16 = reinterpret_cast<uint16*>(src_pos);
563 for (int x = 0; x < width; x++) { 544 for (int x = 0; x < width; x++) {
564 // Dereference through an appropriately-aligned pointer. 545 // Dereference through an appropriately-aligned pointer.
565 uint32 pixel; 546 uint32 pixel;
566 if (bits_per_pixel == 32) 547 if (bits_per_pixel == 32)
567 pixel = src_pos_32[x]; 548 pixel = src_pos_32[x];
568 else if (bits_per_pixel == 16) 549 else if (bits_per_pixel == 16)
569 pixel = src_pos_16[x]; 550 pixel = src_pos_16[x];
570 else 551 else
571 pixel = src_pos[x]; 552 pixel = src_pos[x];
572 uint32 r = (pixel & red_mask) << red_shift; 553 uint32 r = (pixel & red_mask) << red_shift;
573 uint32 g = (pixel & green_mask) << green_shift; 554 uint32 g = (pixel & green_mask) << green_shift;
574 uint32 b = (pixel & blue_mask) << blue_shift; 555 uint32 b = (pixel & blue_mask) << blue_shift;
575 556
576 // Write as 32-bit RGB. 557 // Write as 32-bit RGB.
577 dst_pos_32[x] = ((r >> 8) & 0xff0000) | ((g >> 16) & 0xff00) | 558 dst_pos_32[x] = ((r >> 8) & 0xff0000) | ((g >> 16) & 0xff00) |
578 ((b >> 24) & 0xff); 559 ((b >> 24) & 0xff);
579 } 560 }
580 dst_pos += capture_data->stride(); 561 dst_pos += frame->stride();
581 src_pos += src_stride; 562 src_pos += src_stride;
582 } 563 }
583 } 564 }
584 565
585 // static 566 // static
586 uint32 ScreenCapturerLinux::GetRgbShift(uint32 mask) { 567 uint32 ScreenCapturerLinux::GetRgbShift(uint32 mask) {
587 int shift = 0; 568 int shift = 0;
588 if ((mask & 0xffff0000u) == 0) { 569 if ((mask & 0xffff0000u) == 0) {
589 mask <<= 16; 570 mask <<= 16;
590 shift += 16; 571 shift += 16;
(...skipping 11 matching lines...) Expand all
602 shift += 2; 583 shift += 2;
603 } 584 }
604 if ((mask & 0x80000000u) == 0) 585 if ((mask & 0x80000000u) == 0)
605 shift += 1; 586 shift += 1;
606 587
607 return shift; 588 return shift;
608 } 589 }
609 590
610 } // namespace 591 } // namespace
611 592
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 593 // static
622 scoped_ptr<ScreenCapturer> ScreenCapturer::Create() { 594 scoped_ptr<ScreenCapturer> ScreenCapturer::Create() {
623 scoped_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux()); 595 scoped_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux());
624 if (!capturer->Init(false)) 596 if (!capturer->Init(false))
625 capturer.reset(); 597 capturer.reset();
626 return capturer.PassAs<ScreenCapturer>(); 598 return capturer.PassAs<ScreenCapturer>();
627 } 599 }
628 600
629 // static 601 // static
630 scoped_ptr<ScreenCapturer> ScreenCapturer::CreateWithXDamage( 602 scoped_ptr<ScreenCapturer> ScreenCapturer::CreateWithXDamage(
631 bool use_x_damage) { 603 bool use_x_damage) {
632 scoped_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux()); 604 scoped_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux());
633 if (!capturer->Init(use_x_damage)) 605 if (!capturer->Init(use_x_damage))
634 capturer.reset(); 606 capturer.reset();
635 return capturer.PassAs<ScreenCapturer>(); 607 return capturer.PassAs<ScreenCapturer>();
636 } 608 }
637 609
638 } // namespace media 610 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698