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