screen_capturer_x11.cc revision 9f282403f258162ca53eb2f16b8e9a26e7970096
13d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org/* 23d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 33d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org * 43d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org * Use of this source code is governed by a BSD-style license 53d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org * that can be found in the LICENSE file in the root of the source 63d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org * tree. An additional intellectual property rights grant can be found 73d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org * in the file PATENTS. All contributing project authors may 83d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org * be found in the AUTHORS file in the root of the source tree. 93d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org */ 103d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 113d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include "webrtc/modules/desktop_capture/screen_capturer.h" 123d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 133d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include <string.h> 143d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include <set> 153d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 163d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include <X11/extensions/Xdamage.h> 173d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include <X11/extensions/Xfixes.h> 183d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include <X11/Xlib.h> 193d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include <X11/Xutil.h> 203d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 213d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include "webrtc/modules/desktop_capture/desktop_frame.h" 223d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include "webrtc/modules/desktop_capture/differ.h" 233d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include "webrtc/modules/desktop_capture/mouse_cursor_shape.h" 243d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include "webrtc/modules/desktop_capture/screen_capture_frame_queue.h" 253d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include "webrtc/modules/desktop_capture/screen_capturer_helper.h" 263d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include "webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.h" 273d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include "webrtc/system_wrappers/interface/logging.h" 283d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include "webrtc/system_wrappers/interface/scoped_ptr.h" 293d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include "webrtc/system_wrappers/interface/tick_util.h" 303d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 313d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org// TODO(sergeyu): Move this to a header where it can be shared. 323d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#if defined(NDEBUG) 333d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#define DCHECK(condition) (void)(condition) 343d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#else // NDEBUG 353d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#define DCHECK(condition) if (!(condition)) {abort();} 363d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#endif 373d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 383d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgnamespace webrtc { 393d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 403d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgnamespace { 413d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 423d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org// A class to perform video frame capturing for Linux. 433d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgclass ScreenCapturerLinux : public ScreenCapturer { 443d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org public: 453d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org ScreenCapturerLinux(); 463d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org virtual ~ScreenCapturerLinux(); 473d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 483d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // TODO(ajwong): Do we really want this to be synchronous? 493d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org bool Init(bool use_x_damage); 503d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 513d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // DesktopCapturer interface. 523d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org virtual void Start(Callback* delegate) OVERRIDE; 533d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org virtual void Capture(const DesktopRegion& region) OVERRIDE; 543d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 553d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // ScreenCapturer interface. 563d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org virtual void SetMouseShapeObserver( 573d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org MouseShapeObserver* mouse_shape_observer) OVERRIDE; 583d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 593d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org private: 603d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org void InitXDamage(); 613d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 623d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Read and handle all currently-pending XEvents. 633d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // In the DAMAGE case, process the XDamage events and store the resulting 643d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // damage rectangles in the ScreenCapturerHelper. 653d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // In all cases, call ScreenConfigurationChanged() in response to any 663d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // ConfigNotify events. 673d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org void ProcessPendingXEvents(); 683d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 693d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Capture the cursor image and notify the delegate if it was captured. 703d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org void CaptureCursor(); 713d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 723d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Capture screen pixels to the current buffer in the queue. In the DAMAGE 733d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // case, the ScreenCapturerHelper already holds the list of invalid rectangles 743d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // from ProcessPendingXEvents(). In the non-DAMAGE case, this captures the 753d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // whole screen, then calculates some invalid rectangles that include any 763d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // differences between this and the previous capture. 773d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DesktopFrame* CaptureScreen(); 783d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 799f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org // Called when the screen configuration is changed. 809f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org void ScreenConfigurationChanged(); 813d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 823d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Synchronize the current buffer with |last_buffer_|, by copying pixels from 833d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // the area of |last_invalid_rects|. 843d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Note this only works on the assumption that kNumBuffers == 2, as 853d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // |last_invalid_rects| holds the differences from the previous buffer and 863d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // the one prior to that (which will then be the current buffer). 873d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org void SynchronizeFrame(); 883d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 893d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org void DeinitXlib(); 903d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 913d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org Callback* callback_; 923d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org MouseShapeObserver* mouse_shape_observer_; 933d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 943d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // X11 graphics context. 953d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org Display* display_; 963d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org GC gc_; 973d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org Window root_window_; 983d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 993d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // XFixes. 1003d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org bool has_xfixes_; 1013d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org int xfixes_event_base_; 1023d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org int xfixes_error_base_; 1033d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 1043d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // XDamage information. 1053d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org bool use_damage_; 1063d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org Damage damage_handle_; 1073d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org int damage_event_base_; 1083d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org int damage_error_base_; 1093d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org XserverRegion damage_region_; 1103d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 1113d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Access to the X Server's pixel buffer. 1123d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org XServerPixelBuffer x_server_pixel_buffer_; 1133d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 1143d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // A thread-safe list of invalid rectangles, and the size of the most 1153d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // recently captured screen. 1163d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org ScreenCapturerHelper helper_; 1173d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 1183d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Queue of the frames buffers. 1193d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org ScreenCaptureFrameQueue queue_; 1203d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 1213d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Invalid region from the previous capture. This is used to synchronize the 1223d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // current with the last buffer used. 1233d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DesktopRegion last_invalid_region_; 1243d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 1253d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // |Differ| for use when polling for changes. 1263d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org scoped_ptr<Differ> differ_; 1273d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 1283d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DISALLOW_COPY_AND_ASSIGN(ScreenCapturerLinux); 1293d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org}; 1303d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 1313d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgScreenCapturerLinux::ScreenCapturerLinux() 1323d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org : callback_(NULL), 1333d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org mouse_shape_observer_(NULL), 1343d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org display_(NULL), 1353d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org gc_(NULL), 1363d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org root_window_(BadValue), 1373d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org has_xfixes_(false), 1383d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org xfixes_event_base_(-1), 1393d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org xfixes_error_base_(-1), 1403d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org use_damage_(false), 1413d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org damage_handle_(0), 1423d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org damage_event_base_(-1), 1433d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org damage_error_base_(-1), 1443d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org damage_region_(0) { 1453d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org helper_.SetLogGridSize(4); 1463d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} 1473d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 1483d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgScreenCapturerLinux::~ScreenCapturerLinux() { 1493d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DeinitXlib(); 1503d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} 1513d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 1523d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgbool ScreenCapturerLinux::Init(bool use_x_damage) { 1533d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // TODO(ajwong): We should specify the display string we are attaching to 1543d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // in the constructor. 1553d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org display_ = XOpenDisplay(NULL); 1563d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (!display_) { 1573d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org LOG(LS_ERROR) << "Unable to open display"; 1583d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org return false; 1593d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 1603d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 1613d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org root_window_ = RootWindow(display_, DefaultScreen(display_)); 1623d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (root_window_ == BadValue) { 1633d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org LOG(LS_ERROR) << "Unable to get the root window"; 1643d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DeinitXlib(); 1653d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org return false; 1663d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 1673d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 1683d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org gc_ = XCreateGC(display_, root_window_, 0, NULL); 1693d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (gc_ == NULL) { 1703d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org LOG(LS_ERROR) << "Unable to get graphics context"; 1713d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DeinitXlib(); 1723d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org return false; 1733d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 1743d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 1753d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Check for XFixes extension. This is required for cursor shape 1763d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // notifications, and for our use of XDamage. 1773d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (XFixesQueryExtension(display_, &xfixes_event_base_, 1783d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org &xfixes_error_base_)) { 1793d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org has_xfixes_ = true; 1803d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } else { 1813d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org LOG(LS_INFO) << "X server does not support XFixes."; 1823d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 1833d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 1843d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Register for changes to the dimensions of the root window. 1853d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org XSelectInput(display_, root_window_, StructureNotifyMask); 1863d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 1879f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org if (!x_server_pixel_buffer_.Init(display_, DefaultRootWindow(display_))) { 1889f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org LOG(LS_ERROR) << "Failed to initialize pixel buffer."; 1899f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org return false; 1909f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org } 1913d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 1923d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (has_xfixes_) { 1933d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Register for changes to the cursor shape. 1943d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org XFixesSelectCursorInput(display_, root_window_, 1953d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org XFixesDisplayCursorNotifyMask); 1963d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 1973d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 1983d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (use_x_damage) { 1993d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org InitXDamage(); 2003d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 2013d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2023d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org return true; 2033d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} 2043d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2053d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgvoid ScreenCapturerLinux::InitXDamage() { 2063d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Our use of XDamage requires XFixes. 2073d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (!has_xfixes_) { 2083d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org return; 2093d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 2103d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2113d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Check for XDamage extension. 2123d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (!XDamageQueryExtension(display_, &damage_event_base_, 2133d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org &damage_error_base_)) { 2143d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org LOG(LS_INFO) << "X server does not support XDamage."; 2153d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org return; 2163d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 2173d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2183d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // TODO(lambroslambrou): Disable DAMAGE in situations where it is known 2193d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // to fail, such as when Desktop Effects are enabled, with graphics 2203d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // drivers (nVidia, ATI) that fail to report DAMAGE notifications 2213d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // properly. 2223d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2233d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Request notifications every time the screen becomes damaged. 2243d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org damage_handle_ = XDamageCreate(display_, root_window_, 2253d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org XDamageReportNonEmpty); 2263d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (!damage_handle_) { 2273d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org LOG(LS_ERROR) << "Unable to initialize XDamage."; 2283d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org return; 2293d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 2303d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2313d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Create an XFixes server-side region to collate damage into. 2323d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org damage_region_ = XFixesCreateRegion(display_, 0, 0); 2333d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (!damage_region_) { 2343d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org XDamageDestroy(display_, damage_handle_); 2353d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org LOG(LS_ERROR) << "Unable to create XFixes region."; 2363d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org return; 2373d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 2383d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2393d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org use_damage_ = true; 2403d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org LOG(LS_INFO) << "Using XDamage extension."; 2413d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} 2423d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2433d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgvoid ScreenCapturerLinux::Start(Callback* callback) { 2443d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DCHECK(!callback_); 2453d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DCHECK(callback); 2463d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2473d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org callback_ = callback; 2483d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} 2493d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2503d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgvoid ScreenCapturerLinux::Capture(const DesktopRegion& region) { 2513d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org TickTime capture_start_time = TickTime::Now(); 2523d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2533d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org queue_.MoveToNextFrame(); 2543d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2553d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Process XEvents for XDamage and cursor shape tracking. 2563d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org ProcessPendingXEvents(); 2573d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2589f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org // ProcessPendingXEvents() may call ScreenConfigurationChanged() which 2599f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org // reinitializes |x_server_pixel_buffer_|. Check if the pixel buffer is still 2609f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org // in a good shape. 2619f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org if (!x_server_pixel_buffer_.is_initialized()) { 2629f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org // We failed to initialize pixel buffer. 2639f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org callback_->OnCaptureCompleted(NULL); 2649f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org return; 2659f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org } 2669f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org 2673d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // If the current frame is from an older generation then allocate a new one. 2683d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Note that we can't reallocate other buffers at this point, since the caller 2693d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // may still be reading from them. 2703d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (!queue_.current_frame()) { 2713d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org scoped_ptr<DesktopFrame> frame( 2729f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org new BasicDesktopFrame(x_server_pixel_buffer_.window_size())); 2733d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org queue_.ReplaceCurrentFrame(frame.release()); 2743d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 2753d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2763d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Refresh the Differ helper used by CaptureFrame(), if needed. 2773d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DesktopFrame* frame = queue_.current_frame(); 2783d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (!use_damage_ && ( 2793d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org !differ_.get() || 2803d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org (differ_->width() != frame->size().width()) || 2813d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org (differ_->height() != frame->size().height()) || 2823d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org (differ_->bytes_per_row() != frame->stride()))) { 2833d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org differ_.reset(new Differ(frame->size().width(), frame->size().height(), 2843d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DesktopFrame::kBytesPerPixel, 2853d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org frame->stride())); 2863d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 2873d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2883d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DesktopFrame* result = CaptureScreen(); 2893d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org last_invalid_region_ = result->updated_region(); 2903d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org result->set_capture_time_ms( 2913d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org (TickTime::Now() - capture_start_time).Milliseconds()); 2923d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org callback_->OnCaptureCompleted(result); 2933d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} 2943d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2953d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgvoid ScreenCapturerLinux::SetMouseShapeObserver( 2963d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org MouseShapeObserver* mouse_shape_observer) { 2973d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DCHECK(!mouse_shape_observer_); 2983d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DCHECK(mouse_shape_observer); 2993d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3003d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org mouse_shape_observer_ = mouse_shape_observer; 3013d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} 3023d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3033d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgvoid ScreenCapturerLinux::ProcessPendingXEvents() { 3043d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Find the number of events that are outstanding "now." We don't just loop 3053d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // on XPending because we want to guarantee this terminates. 3063d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org int events_to_process = XPending(display_); 3073d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org XEvent e; 3083d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3093d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org for (int i = 0; i < events_to_process; i++) { 3103d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org XNextEvent(display_, &e); 3113d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (use_damage_ && (e.type == damage_event_base_ + XDamageNotify)) { 3123d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org XDamageNotifyEvent* event = reinterpret_cast<XDamageNotifyEvent*>(&e); 3133d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DCHECK(event->level == XDamageReportNonEmpty); 3143d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } else if (e.type == ConfigureNotify) { 3159f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org ScreenConfigurationChanged(); 3163d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } else if (has_xfixes_ && 3173d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org e.type == xfixes_event_base_ + XFixesCursorNotify) { 3183d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org XFixesCursorNotifyEvent* cne; 3193d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org cne = reinterpret_cast<XFixesCursorNotifyEvent*>(&e); 3203d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (cne->subtype == XFixesDisplayCursorNotify) { 3213d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org CaptureCursor(); 3223d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 3233d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } else { 3243d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org LOG(LS_WARNING) << "Got unknown event type: " << e.type; 3253d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 3263d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 3273d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} 3283d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3293d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgvoid ScreenCapturerLinux::CaptureCursor() { 3303d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DCHECK(has_xfixes_); 3313d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3323d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org XFixesCursorImage* img = XFixesGetCursorImage(display_); 3333d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (!img) { 3343d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org return; 3353d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 3363d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3373d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org scoped_ptr<MouseCursorShape> cursor(new MouseCursorShape()); 3383d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org cursor->size = DesktopSize(img->width, img->height); 3393d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org cursor->hotspot = DesktopVector(img->xhot, img->yhot); 3403d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3413d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org int total_bytes = cursor->size.width ()* cursor->size.height() * 3423d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DesktopFrame::kBytesPerPixel; 3433d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org cursor->data.resize(total_bytes); 3443d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3453d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Xlib stores 32-bit data in longs, even if longs are 64-bits long. 3463d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org unsigned long* src = img->pixels; 3473d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org uint32_t* dst = reinterpret_cast<uint32_t*>(&*(cursor->data.begin())); 3483d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org uint32_t* dst_end = dst + (img->width * img->height); 3493d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org while (dst < dst_end) { 3503d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org *dst++ = static_cast<uint32_t>(*src++); 3513d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 3523d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org XFree(img); 3533d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3543d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (mouse_shape_observer_) 3553d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org mouse_shape_observer_->OnCursorShapeChanged(cursor.release()); 3563d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} 3573d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3583d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgDesktopFrame* ScreenCapturerLinux::CaptureScreen() { 3593d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DesktopFrame* frame = queue_.current_frame()->Share(); 3609f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org assert(x_server_pixel_buffer_.window_size().equals(frame->size())); 3613d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3623d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Pass the screen size to the helper, so it can clip the invalid region if it 3633d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // expands that region to a grid. 3643d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org helper_.set_size_most_recent(frame->size()); 3653d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3663d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // In the DAMAGE case, ensure the frame is up-to-date with the previous frame 3673d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // if any. If there isn't a previous frame, that means a screen-resolution 3683d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // change occurred, and |invalid_rects| will be updated to include the whole 3693d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // screen. 3703d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (use_damage_ && queue_.previous_frame()) 3713d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org SynchronizeFrame(); 3723d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3733d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DesktopRegion* updated_region = frame->mutable_updated_region(); 3743d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3753d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org x_server_pixel_buffer_.Synchronize(); 3763d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (use_damage_ && queue_.previous_frame()) { 3773d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Atomically fetch and clear the damage region. 3783d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org XDamageSubtract(display_, damage_handle_, None, damage_region_); 3793d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org int rects_num = 0; 3803d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org XRectangle bounds; 3813d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org XRectangle* rects = XFixesFetchRegionAndBounds(display_, damage_region_, 3823d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org &rects_num, &bounds); 3833d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org for (int i = 0; i < rects_num; ++i) { 3843d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org updated_region->AddRect(DesktopRect::MakeXYWH( 3853d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org rects[i].x, rects[i].y, rects[i].width, rects[i].height)); 3863d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 3873d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org XFree(rects); 3883d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org helper_.InvalidateRegion(*updated_region); 3893d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3903d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Capture the damaged portions of the desktop. 3913d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org helper_.TakeInvalidRegion(updated_region); 3923d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3933d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Clip the damaged portions to the current screen size, just in case some 3943d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // spurious XDamage notifications were received for a previous (larger) 3953d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // screen size. 3963d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org updated_region->IntersectWith( 3979f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org DesktopRect::MakeSize(x_server_pixel_buffer_.window_size())); 3983d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3993d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org for (DesktopRegion::Iterator it(*updated_region); 4003d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org !it.IsAtEnd(); it.Advance()) { 4019f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org x_server_pixel_buffer_.CaptureRect(it.rect(), frame); 4023d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 4033d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } else { 4043d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Doing full-screen polling, or this is the first capture after a 4053d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // screen-resolution change. In either case, need a full-screen capture. 4069f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org DesktopRect screen_rect = DesktopRect::MakeSize(frame->size()); 4079f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org x_server_pixel_buffer_.CaptureRect(screen_rect, frame); 4083d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 4093d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (queue_.previous_frame()) { 4103d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Full-screen polling, so calculate the invalid rects here, based on the 4113d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // changed pixels between current and previous buffers. 4123d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DCHECK(differ_.get() != NULL); 4133d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DCHECK(queue_.previous_frame()->data()); 4143d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org differ_->CalcDirtyRegion(queue_.previous_frame()->data(), 4153d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org frame->data(), updated_region); 4163d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } else { 4173d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // No previous buffer, so always invalidate the whole screen, whether 4183d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // or not DAMAGE is being used. DAMAGE doesn't necessarily send a 4193d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // full-screen notification after a screen-resolution change, so 4203d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // this is done here. 4213d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org updated_region->SetRect(screen_rect); 4223d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 4233d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 4243d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 4253d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org return frame; 4263d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} 4273d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 4289f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.orgvoid ScreenCapturerLinux::ScreenConfigurationChanged() { 4293d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Make sure the frame buffers will be reallocated. 4303d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org queue_.Reset(); 4313d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 4323d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org helper_.ClearInvalidRegion(); 4339f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org if (!x_server_pixel_buffer_.Init(display_, DefaultRootWindow(display_))) { 4349f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org LOG(LS_ERROR) << "Failed to initialize pixel buffer after screen " 4359f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org "configuration change."; 4369f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org } 4373d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} 4383d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 4393d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgvoid ScreenCapturerLinux::SynchronizeFrame() { 4403d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Synchronize the current buffer with the previous one since we do not 4413d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // capture the entire desktop. Note that encoder may be reading from the 4423d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // previous buffer at this time so thread access complaints are false 4433d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // positives. 4443d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 4453d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // TODO(hclam): We can reduce the amount of copying here by subtracting 4463d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // |capturer_helper_|s region from |last_invalid_region_|. 4473d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // http://crbug.com/92354 4483d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DCHECK(queue_.previous_frame()); 4493d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 4503d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DesktopFrame* current = queue_.current_frame(); 4513d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DesktopFrame* last = queue_.previous_frame(); 4523d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DCHECK(current != last); 4533d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org for (DesktopRegion::Iterator it(last_invalid_region_); 4543d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org !it.IsAtEnd(); it.Advance()) { 4553d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org const DesktopRect& r = it.rect(); 4563d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org int offset = r.top() * current->stride() + 4573d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org r.left() * DesktopFrame::kBytesPerPixel; 4583d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org for (int i = 0; i < r.height(); ++i) { 4593d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org memcpy(current->data() + offset, last->data() + offset, 4603d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org r.width() * DesktopFrame::kBytesPerPixel); 4613d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org offset += current->size().width() * DesktopFrame::kBytesPerPixel; 4623d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 4633d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 4643d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} 4653d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 4663d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgvoid ScreenCapturerLinux::DeinitXlib() { 4673d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (gc_) { 4683d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org XFreeGC(display_, gc_); 4693d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org gc_ = NULL; 4703d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 4713d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 4723d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org x_server_pixel_buffer_.Release(); 4733d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 4743d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (display_) { 4753d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (damage_handle_) 4763d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org XDamageDestroy(display_, damage_handle_); 4773d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (damage_region_) 4783d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org XFixesDestroyRegion(display_, damage_region_); 4793d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org XCloseDisplay(display_); 4803d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org display_ = NULL; 4813d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org damage_handle_ = 0; 4823d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org damage_region_ = 0; 4833d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 4843d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} 4853d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 4863d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} // namespace 4873d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 4883d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org// static 4893d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgScreenCapturer* ScreenCapturer::Create() { 4903d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org scoped_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux()); 4913d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (!capturer->Init(false)) 4923d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org capturer.reset(); 4933d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org return capturer.release(); 4943d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} 4953d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 4963d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org// static 4973d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgScreenCapturer* ScreenCapturer::CreateWithXDamage(bool use_x_damage) { 4983d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org scoped_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux()); 4993d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (!capturer->Init(use_x_damage)) 5003d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org capturer.reset(); 5013d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org return capturer.release(); 5023d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} 5033d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 5043d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} // namespace webrtc 505