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

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: 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 th the current buffer in the queue. In the DAMAGE
alexeypa (please no reviews) 2013/05/08 22:24:59 nit: th -> to
Sergey Ulanov 2013/05/09 18:49:02 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 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
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 CaptureScreen();
308 288
309 // Swap the current & previous buffers ready for the next capture. 289 frame->set_capture_time_ms(
310 last_invalid_region_ = capture_data->dirty_region(); 290 (base::Time::Now() - capture_start_time).InMillisecondsRoundedUp());
291 callback_->OnCaptureCompleted(queue_.EmitCurrentFrame());
292 }
311 293
312 queue_.DoneWithCurrentFrame(); 294 void ScreenCapturerLinux::SetMouseShapeObserver(
295 MouseShapeObserver* mouse_shape_observer) {
296 DCHECK(!mouse_shape_observer_);
297 DCHECK(mouse_shape_observer);
313 298
314 capture_data->set_capture_time_ms( 299 mouse_shape_observer_ = mouse_shape_observer;
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 void ScreenCapturerLinux::CaptureScreen() {
375 ScreenCaptureFrame* frame = queue_.current_frame(); 360 webrtc::DesktopFrame* frame = queue_.current_frame();
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 invalid_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 invalid_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(invalid_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(&invalid_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 invalid_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(invalid_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(), &invalid_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 invalid_region.SetRect(screen_rect);
438 } 422 }
439 } 423 }
440 424
441 capture_data->mutable_dirty_region() = invalid_region; 425 last_invalid_region_ = invalid_region;
442 return capture_data; 426 *frame->mutable_updated_region() = invalid_region;
443 } 427 }
444 428
445 void ScreenCapturerLinux::ScreenConfigurationChanged( 429 void ScreenCapturerLinux::ScreenConfigurationChanged(
446 const SkISize& root_window_size) { 430 const webrtc::DesktopSize& root_window_size) {
447 root_window_size_ = root_window_size; 431 root_window_size_ = root_window_size;
448 432
449 // Make sure the frame buffers will be reallocated. 433 // Make sure the frame buffers will be reallocated.
450 queue_.SetAllFramesNeedUpdate(); 434 queue_.Reset();
451 435
452 helper_.ClearInvalidRegion(); 436 helper_.ClearInvalidRegion();
453 x_server_pixel_buffer_.Init(display_, root_window_size_); 437 x_server_pixel_buffer_.Init(display_, root_window_size_);
454 } 438 }
455 439
456 void ScreenCapturerLinux::SynchronizeFrame() { 440 void ScreenCapturerLinux::SynchronizeFrame() {
457 // Synchronize the current buffer with the previous one since we do not 441 // 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 442 // capture the entire desktop. Note that encoder may be reading from the
459 // previous buffer at this time so thread access complaints are false 443 // previous buffer at this time so thread access complaints are false
460 // positives. 444 // positives.
461 445
462 // TODO(hclam): We can reduce the amount of copying here by subtracting 446 // TODO(hclam): We can reduce the amount of copying here by subtracting
463 // |capturer_helper_|s region from |last_invalid_region_|. 447 // |capturer_helper_|s region from |last_invalid_region_|.
464 // http://crbug.com/92354 448 // http://crbug.com/92354
465 DCHECK(queue_.previous_frame()); 449 DCHECK(queue_.previous_frame());
466 450
467 ScreenCaptureFrame* current = queue_.current_frame(); 451 webrtc::DesktopFrame* current = queue_.current_frame();
468 ScreenCaptureFrame* last = queue_.previous_frame(); 452 webrtc::DesktopFrame* last = queue_.previous_frame();
469 DCHECK_NE(current, last); 453 DCHECK_NE(current, last);
470 for (SkRegion::Iterator it(last_invalid_region_); !it.done(); it.next()) { 454 for (webrtc::DesktopRegion::Iterator it(last_invalid_region_);
471 const SkIRect& r = it.rect(); 455 !it.IsAtEnd(); it.Advance()) {
472 int offset = r.fTop * current->bytes_per_row() + 456 const webrtc::DesktopRect& r = it.rect();
473 r.fLeft * ScreenCaptureData::kBytesPerPixel; 457 int offset = r.top() * current->stride() +
458 r.left() * webrtc::DesktopFrame::kBytesPerPixel;
474 for (int i = 0; i < r.height(); ++i) { 459 for (int i = 0; i < r.height(); ++i) {
475 memcpy(current->pixels() + offset, last->pixels() + offset, 460 memcpy(current->data() + offset, last->data() + offset,
476 r.width() * ScreenCaptureData::kBytesPerPixel); 461 r.width() * webrtc::DesktopFrame::kBytesPerPixel);
477 offset += current->dimensions().width() * 462 offset += current->size().width() * webrtc::DesktopFrame::kBytesPerPixel;
478 ScreenCaptureData::kBytesPerPixel;
479 } 463 }
480 } 464 }
481 } 465 }
482 466
483 void ScreenCapturerLinux::DeinitXlib() { 467 void ScreenCapturerLinux::DeinitXlib() {
484 if (gc_) { 468 if (gc_) {
485 XFreeGC(display_, gc_); 469 XFreeGC(display_, gc_);
486 gc_ = NULL; 470 gc_ = NULL;
487 } 471 }
488 472
489 x_server_pixel_buffer_.Release(); 473 x_server_pixel_buffer_.Release();
490 474
491 if (display_) { 475 if (display_) {
492 if (damage_handle_) 476 if (damage_handle_)
493 XDamageDestroy(display_, damage_handle_); 477 XDamageDestroy(display_, damage_handle_);
494 if (damage_region_) 478 if (damage_region_)
495 XFixesDestroyRegion(display_, damage_region_); 479 XFixesDestroyRegion(display_, damage_region_);
496 XCloseDisplay(display_); 480 XCloseDisplay(display_);
497 display_ = NULL; 481 display_ = NULL;
498 damage_handle_ = 0; 482 damage_handle_ = 0;
499 damage_region_ = 0; 483 damage_region_ = 0;
500 } 484 }
501 } 485 }
502 486
503 void ScreenCapturerLinux::CaptureRect(const SkIRect& rect, 487 void ScreenCapturerLinux::CaptureRect(const webrtc::DesktopRect& rect,
504 ScreenCaptureData* capture_data) { 488 webrtc::DesktopFrame* frame) {
505 uint8* image = x_server_pixel_buffer_.CaptureRect(rect); 489 uint8* image = x_server_pixel_buffer_.CaptureRect(rect);
506 int depth = x_server_pixel_buffer_.GetDepth(); 490 int depth = x_server_pixel_buffer_.GetDepth();
507 if ((depth == 24 || depth == 32) && 491 if ((depth == 24 || depth == 32) &&
508 x_server_pixel_buffer_.GetBitsPerPixel() == 32 && 492 x_server_pixel_buffer_.GetBitsPerPixel() == 32 &&
509 x_server_pixel_buffer_.GetRedMask() == 0xff0000 && 493 x_server_pixel_buffer_.GetRedMask() == 0xff0000 &&
510 x_server_pixel_buffer_.GetGreenMask() == 0xff00 && 494 x_server_pixel_buffer_.GetGreenMask() == 0xff00 &&
511 x_server_pixel_buffer_.GetBlueMask() == 0xff) { 495 x_server_pixel_buffer_.GetBlueMask() == 0xff) {
512 DVLOG(3) << "Fast blitting"; 496 DVLOG(3) << "Fast blitting";
513 FastBlit(image, rect, capture_data); 497 FastBlit(image, rect, frame);
514 } else { 498 } else {
515 DVLOG(3) << "Slow blitting"; 499 DVLOG(3) << "Slow blitting";
516 SlowBlit(image, rect, capture_data); 500 SlowBlit(image, rect, frame);
517 } 501 }
518 } 502 }
519 503
520 void ScreenCapturerLinux::FastBlit(uint8* image, const SkIRect& rect, 504 void ScreenCapturerLinux::FastBlit(uint8* image,
521 ScreenCaptureData* capture_data) { 505 const webrtc::DesktopRect& rect,
506 webrtc::DesktopFrame* frame) {
522 uint8* src_pos = image; 507 uint8* src_pos = image;
523 int src_stride = x_server_pixel_buffer_.GetStride(); 508 int src_stride = x_server_pixel_buffer_.GetStride();
524 int dst_x = rect.fLeft, dst_y = rect.fTop; 509 int dst_x = rect.left(), dst_y = rect.top();
525 510
526 uint8* dst_pos = capture_data->data() + capture_data->stride() * dst_y; 511 uint8* dst_pos = frame->data() + frame->stride() * dst_y;
527 dst_pos += dst_x * ScreenCaptureData::kBytesPerPixel; 512 dst_pos += dst_x * webrtc::DesktopFrame::kBytesPerPixel;
528 513
529 int height = rect.height(); 514 int height = rect.height();
530 int row_bytes = rect.width() * ScreenCaptureData::kBytesPerPixel; 515 int row_bytes = rect.width() * webrtc::DesktopFrame::kBytesPerPixel;
531 for (int y = 0; y < height; ++y) { 516 for (int y = 0; y < height; ++y) {
532 memcpy(dst_pos, src_pos, row_bytes); 517 memcpy(dst_pos, src_pos, row_bytes);
533 src_pos += src_stride; 518 src_pos += src_stride;
534 dst_pos += capture_data->stride(); 519 dst_pos += frame->stride();
535 } 520 }
536 } 521 }
537 522
538 void ScreenCapturerLinux::SlowBlit(uint8* image, const SkIRect& rect, 523 void ScreenCapturerLinux::SlowBlit(uint8* image,
539 ScreenCaptureData* capture_data) { 524 const webrtc::DesktopRect& rect,
525 webrtc::DesktopFrame* frame) {
540 int src_stride = x_server_pixel_buffer_.GetStride(); 526 int src_stride = x_server_pixel_buffer_.GetStride();
541 int dst_x = rect.fLeft, dst_y = rect.fTop; 527 int dst_x = rect.left(), dst_y = rect.top();
542 int width = rect.width(), height = rect.height(); 528 int width = rect.width(), height = rect.height();
543 529
544 uint32 red_mask = x_server_pixel_buffer_.GetRedMask(); 530 uint32 red_mask = x_server_pixel_buffer_.GetRedMask();
545 uint32 green_mask = x_server_pixel_buffer_.GetGreenMask(); 531 uint32 green_mask = x_server_pixel_buffer_.GetGreenMask();
546 uint32 blue_mask = x_server_pixel_buffer_.GetBlueMask(); 532 uint32 blue_mask = x_server_pixel_buffer_.GetBlueMask();
547 533
548 uint32 red_shift = GetRgbShift(red_mask); 534 uint32 red_shift = GetRgbShift(red_mask);
549 uint32 green_shift = GetRgbShift(green_mask); 535 uint32 green_shift = GetRgbShift(green_mask);
550 uint32 blue_shift = GetRgbShift(blue_mask); 536 uint32 blue_shift = GetRgbShift(blue_mask);
551 537
552 unsigned int bits_per_pixel = x_server_pixel_buffer_.GetBitsPerPixel(); 538 unsigned int bits_per_pixel = x_server_pixel_buffer_.GetBitsPerPixel();
553 539
554 uint8* dst_pos = capture_data->data() + capture_data->stride() * dst_y; 540 uint8* dst_pos = frame->data() + frame->stride() * dst_y;
555 uint8* src_pos = image; 541 uint8* src_pos = image;
556 dst_pos += dst_x * ScreenCaptureData::kBytesPerPixel; 542 dst_pos += dst_x * webrtc::DesktopFrame::kBytesPerPixel;
557 // TODO(hclam): Optimize, perhaps using MMX code or by converting to 543 // TODO(hclam): Optimize, perhaps using MMX code or by converting to
558 // YUV directly 544 // YUV directly
559 for (int y = 0; y < height; y++) { 545 for (int y = 0; y < height; y++) {
560 uint32* dst_pos_32 = reinterpret_cast<uint32*>(dst_pos); 546 uint32* dst_pos_32 = reinterpret_cast<uint32*>(dst_pos);
561 uint32* src_pos_32 = reinterpret_cast<uint32*>(src_pos); 547 uint32* src_pos_32 = reinterpret_cast<uint32*>(src_pos);
562 uint16* src_pos_16 = reinterpret_cast<uint16*>(src_pos); 548 uint16* src_pos_16 = reinterpret_cast<uint16*>(src_pos);
563 for (int x = 0; x < width; x++) { 549 for (int x = 0; x < width; x++) {
564 // Dereference through an appropriately-aligned pointer. 550 // Dereference through an appropriately-aligned pointer.
565 uint32 pixel; 551 uint32 pixel;
566 if (bits_per_pixel == 32) 552 if (bits_per_pixel == 32)
567 pixel = src_pos_32[x]; 553 pixel = src_pos_32[x];
568 else if (bits_per_pixel == 16) 554 else if (bits_per_pixel == 16)
569 pixel = src_pos_16[x]; 555 pixel = src_pos_16[x];
570 else 556 else
571 pixel = src_pos[x]; 557 pixel = src_pos[x];
572 uint32 r = (pixel & red_mask) << red_shift; 558 uint32 r = (pixel & red_mask) << red_shift;
573 uint32 g = (pixel & green_mask) << green_shift; 559 uint32 g = (pixel & green_mask) << green_shift;
574 uint32 b = (pixel & blue_mask) << blue_shift; 560 uint32 b = (pixel & blue_mask) << blue_shift;
575 561
576 // Write as 32-bit RGB. 562 // Write as 32-bit RGB.
577 dst_pos_32[x] = ((r >> 8) & 0xff0000) | ((g >> 16) & 0xff00) | 563 dst_pos_32[x] = ((r >> 8) & 0xff0000) | ((g >> 16) & 0xff00) |
578 ((b >> 24) & 0xff); 564 ((b >> 24) & 0xff);
579 } 565 }
580 dst_pos += capture_data->stride(); 566 dst_pos += frame->stride();
581 src_pos += src_stride; 567 src_pos += src_stride;
582 } 568 }
583 } 569 }
584 570
585 // static 571 // static
586 uint32 ScreenCapturerLinux::GetRgbShift(uint32 mask) { 572 uint32 ScreenCapturerLinux::GetRgbShift(uint32 mask) {
587 int shift = 0; 573 int shift = 0;
588 if ((mask & 0xffff0000u) == 0) { 574 if ((mask & 0xffff0000u) == 0) {
589 mask <<= 16; 575 mask <<= 16;
590 shift += 16; 576 shift += 16;
(...skipping 11 matching lines...) Expand all
602 shift += 2; 588 shift += 2;
603 } 589 }
604 if ((mask & 0x80000000u) == 0) 590 if ((mask & 0x80000000u) == 0)
605 shift += 1; 591 shift += 1;
606 592
607 return shift; 593 return shift;
608 } 594 }
609 595
610 } // namespace 596 } // namespace
611 597
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 598 // static
622 scoped_ptr<ScreenCapturer> ScreenCapturer::Create() { 599 scoped_ptr<ScreenCapturer> ScreenCapturer::Create() {
623 scoped_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux()); 600 scoped_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux());
624 if (!capturer->Init(false)) 601 if (!capturer->Init(false))
625 capturer.reset(); 602 capturer.reset();
626 return capturer.PassAs<ScreenCapturer>(); 603 return capturer.PassAs<ScreenCapturer>();
627 } 604 }
628 605
629 // static 606 // static
630 scoped_ptr<ScreenCapturer> ScreenCapturer::CreateWithXDamage( 607 scoped_ptr<ScreenCapturer> ScreenCapturer::CreateWithXDamage(
631 bool use_x_damage) { 608 bool use_x_damage) {
632 scoped_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux()); 609 scoped_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux());
633 if (!capturer->Init(use_x_damage)) 610 if (!capturer->Init(use_x_damage))
634 capturer.reset(); 611 capturer.reset();
635 return capturer.PassAs<ScreenCapturer>(); 612 return capturer.PassAs<ScreenCapturer>();
636 } 613 }
637 614
638 } // namespace media 615 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698