screen_capturer_x11.cc revision 894e6fe9ea16a63537ec6d453c81566d02f66059
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 21894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org#include "webrtc/modules/desktop_capture/desktop_capture_options.h" 223d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include "webrtc/modules/desktop_capture/desktop_frame.h" 233d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include "webrtc/modules/desktop_capture/differ.h" 243d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include "webrtc/modules/desktop_capture/mouse_cursor_shape.h" 253d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include "webrtc/modules/desktop_capture/screen_capture_frame_queue.h" 263d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include "webrtc/modules/desktop_capture/screen_capturer_helper.h" 273d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include "webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.h" 283d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include "webrtc/system_wrappers/interface/logging.h" 293d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include "webrtc/system_wrappers/interface/scoped_ptr.h" 303d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include "webrtc/system_wrappers/interface/tick_util.h" 313d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 323d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org// TODO(sergeyu): Move this to a header where it can be shared. 333d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#if defined(NDEBUG) 343d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#define DCHECK(condition) (void)(condition) 353d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#else // NDEBUG 363d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#define DCHECK(condition) if (!(condition)) {abort();} 373d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#endif 383d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 393d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgnamespace webrtc { 403d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 413d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgnamespace { 423d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 433d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org// A class to perform video frame capturing for Linux. 443d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgclass ScreenCapturerLinux : public ScreenCapturer { 453d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org public: 463d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org ScreenCapturerLinux(); 473d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org virtual ~ScreenCapturerLinux(); 483d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 493d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // TODO(ajwong): Do we really want this to be synchronous? 50894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org bool Init(const DesktopCaptureOptions& options); 513d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 523d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // DesktopCapturer interface. 533d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org virtual void Start(Callback* delegate) OVERRIDE; 543d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org virtual void Capture(const DesktopRegion& region) OVERRIDE; 553d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 563d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // ScreenCapturer interface. 573d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org virtual void SetMouseShapeObserver( 583d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org MouseShapeObserver* mouse_shape_observer) OVERRIDE; 593d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 603d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org private: 61894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org Display* display() { return options_.x_display()->display(); } 62894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org 633d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org void InitXDamage(); 643d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 653d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Read and handle all currently-pending XEvents. 663d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // In the DAMAGE case, process the XDamage events and store the resulting 673d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // damage rectangles in the ScreenCapturerHelper. 683d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // In all cases, call ScreenConfigurationChanged() in response to any 693d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // ConfigNotify events. 703d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org void ProcessPendingXEvents(); 713d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 723d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Capture the cursor image and notify the delegate if it was captured. 733d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org void CaptureCursor(); 743d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 753d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Capture screen pixels to the current buffer in the queue. In the DAMAGE 763d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // case, the ScreenCapturerHelper already holds the list of invalid rectangles 773d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // from ProcessPendingXEvents(). In the non-DAMAGE case, this captures the 783d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // whole screen, then calculates some invalid rectangles that include any 793d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // differences between this and the previous capture. 803d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DesktopFrame* CaptureScreen(); 813d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 829f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org // Called when the screen configuration is changed. 839f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org void ScreenConfigurationChanged(); 843d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 853d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Synchronize the current buffer with |last_buffer_|, by copying pixels from 863d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // the area of |last_invalid_rects|. 873d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Note this only works on the assumption that kNumBuffers == 2, as 883d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // |last_invalid_rects| holds the differences from the previous buffer and 893d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // the one prior to that (which will then be the current buffer). 903d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org void SynchronizeFrame(); 913d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 923d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org void DeinitXlib(); 933d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 94894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org DesktopCaptureOptions options_; 95894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org 963d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org Callback* callback_; 973d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org MouseShapeObserver* mouse_shape_observer_; 983d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 993d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // X11 graphics context. 1003d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org GC gc_; 1013d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org Window root_window_; 1023d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 1033d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // XFixes. 1043d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org bool has_xfixes_; 1053d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org int xfixes_event_base_; 1063d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org int xfixes_error_base_; 1073d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 1083d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // XDamage information. 1093d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org bool use_damage_; 1103d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org Damage damage_handle_; 1113d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org int damage_event_base_; 1123d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org int damage_error_base_; 1133d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org XserverRegion damage_region_; 1143d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 1153d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Access to the X Server's pixel buffer. 1163d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org XServerPixelBuffer x_server_pixel_buffer_; 1173d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 1183d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // A thread-safe list of invalid rectangles, and the size of the most 1193d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // recently captured screen. 1203d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org ScreenCapturerHelper helper_; 1213d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 1223d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Queue of the frames buffers. 1233d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org ScreenCaptureFrameQueue queue_; 1243d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 1253d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Invalid region from the previous capture. This is used to synchronize the 1263d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // current with the last buffer used. 1273d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DesktopRegion last_invalid_region_; 1283d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 1293d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // |Differ| for use when polling for changes. 1303d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org scoped_ptr<Differ> differ_; 1313d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 1323d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DISALLOW_COPY_AND_ASSIGN(ScreenCapturerLinux); 1333d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org}; 1343d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 1353d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgScreenCapturerLinux::ScreenCapturerLinux() 1363d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org : callback_(NULL), 1373d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org mouse_shape_observer_(NULL), 1383d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org gc_(NULL), 1393d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org root_window_(BadValue), 1403d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org has_xfixes_(false), 1413d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org xfixes_event_base_(-1), 1423d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org xfixes_error_base_(-1), 1433d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org use_damage_(false), 1443d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org damage_handle_(0), 1453d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org damage_event_base_(-1), 1463d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org damage_error_base_(-1), 1473d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org damage_region_(0) { 1483d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org helper_.SetLogGridSize(4); 1493d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} 1503d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 1513d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgScreenCapturerLinux::~ScreenCapturerLinux() { 1523d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DeinitXlib(); 1533d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} 1543d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 155894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.orgbool ScreenCapturerLinux::Init(const DesktopCaptureOptions& options) { 156894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org options_ = options; 1573d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 158894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org root_window_ = RootWindow(display(), DefaultScreen(display())); 1593d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (root_window_ == BadValue) { 1603d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org LOG(LS_ERROR) << "Unable to get the root window"; 1613d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DeinitXlib(); 1623d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org return false; 1633d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 1643d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 165894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org gc_ = XCreateGC(display(), root_window_, 0, NULL); 1663d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (gc_ == NULL) { 1673d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org LOG(LS_ERROR) << "Unable to get graphics context"; 1683d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DeinitXlib(); 1693d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org return false; 1703d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 1713d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 1723d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Check for XFixes extension. This is required for cursor shape 1733d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // notifications, and for our use of XDamage. 174894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org if (XFixesQueryExtension(display(), &xfixes_event_base_, 1753d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org &xfixes_error_base_)) { 1763d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org has_xfixes_ = true; 1773d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } else { 1783d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org LOG(LS_INFO) << "X server does not support XFixes."; 1793d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 1803d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 1813d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Register for changes to the dimensions of the root window. 182894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org XSelectInput(display(), root_window_, StructureNotifyMask); 1833d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 184894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org if (!x_server_pixel_buffer_.Init(display(), DefaultRootWindow(display()))) { 1859f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org LOG(LS_ERROR) << "Failed to initialize pixel buffer."; 1869f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org return false; 1879f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org } 1883d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 1893d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (has_xfixes_) { 1903d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Register for changes to the cursor shape. 191894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org XFixesSelectCursorInput(display(), root_window_, 1923d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org XFixesDisplayCursorNotifyMask); 1933d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 1943d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 195894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org if (options_.use_update_notifications()) { 1963d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org InitXDamage(); 1973d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 1983d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 1993d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org return true; 2003d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} 2013d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2023d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgvoid ScreenCapturerLinux::InitXDamage() { 2033d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Our use of XDamage requires XFixes. 2043d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (!has_xfixes_) { 2053d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org return; 2063d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 2073d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2083d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Check for XDamage extension. 209894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org if (!XDamageQueryExtension(display(), &damage_event_base_, 2103d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org &damage_error_base_)) { 2113d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org LOG(LS_INFO) << "X server does not support XDamage."; 2123d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org return; 2133d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 2143d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2153d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // TODO(lambroslambrou): Disable DAMAGE in situations where it is known 2163d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // to fail, such as when Desktop Effects are enabled, with graphics 2173d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // drivers (nVidia, ATI) that fail to report DAMAGE notifications 2183d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // properly. 2193d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2203d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Request notifications every time the screen becomes damaged. 221894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org damage_handle_ = XDamageCreate(display(), root_window_, 2223d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org XDamageReportNonEmpty); 2233d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (!damage_handle_) { 2243d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org LOG(LS_ERROR) << "Unable to initialize XDamage."; 2253d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org return; 2263d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 2273d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2283d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Create an XFixes server-side region to collate damage into. 229894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org damage_region_ = XFixesCreateRegion(display(), 0, 0); 2303d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (!damage_region_) { 231894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org XDamageDestroy(display(), damage_handle_); 2323d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org LOG(LS_ERROR) << "Unable to create XFixes region."; 2333d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org return; 2343d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 2353d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2363d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org use_damage_ = true; 2373d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org LOG(LS_INFO) << "Using XDamage extension."; 2383d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} 2393d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2403d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgvoid ScreenCapturerLinux::Start(Callback* callback) { 2413d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DCHECK(!callback_); 2423d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DCHECK(callback); 2433d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2443d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org callback_ = callback; 2453d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} 2463d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2473d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgvoid ScreenCapturerLinux::Capture(const DesktopRegion& region) { 2483d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org TickTime capture_start_time = TickTime::Now(); 2493d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2503d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org queue_.MoveToNextFrame(); 2513d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2523d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Process XEvents for XDamage and cursor shape tracking. 2533d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org ProcessPendingXEvents(); 2543d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2559f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org // ProcessPendingXEvents() may call ScreenConfigurationChanged() which 2569f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org // reinitializes |x_server_pixel_buffer_|. Check if the pixel buffer is still 2579f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org // in a good shape. 2589f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org if (!x_server_pixel_buffer_.is_initialized()) { 2599f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org // We failed to initialize pixel buffer. 2609f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org callback_->OnCaptureCompleted(NULL); 2619f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org return; 2629f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org } 2639f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org 2643d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // If the current frame is from an older generation then allocate a new one. 2653d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Note that we can't reallocate other buffers at this point, since the caller 2663d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // may still be reading from them. 2673d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (!queue_.current_frame()) { 2683d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org scoped_ptr<DesktopFrame> frame( 2699f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org new BasicDesktopFrame(x_server_pixel_buffer_.window_size())); 2703d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org queue_.ReplaceCurrentFrame(frame.release()); 2713d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 2723d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2733d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Refresh the Differ helper used by CaptureFrame(), if needed. 2743d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DesktopFrame* frame = queue_.current_frame(); 2753d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (!use_damage_ && ( 2763d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org !differ_.get() || 2773d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org (differ_->width() != frame->size().width()) || 2783d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org (differ_->height() != frame->size().height()) || 2793d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org (differ_->bytes_per_row() != frame->stride()))) { 2803d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org differ_.reset(new Differ(frame->size().width(), frame->size().height(), 2813d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DesktopFrame::kBytesPerPixel, 2823d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org frame->stride())); 2833d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 2843d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2853d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DesktopFrame* result = CaptureScreen(); 2863d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org last_invalid_region_ = result->updated_region(); 2873d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org result->set_capture_time_ms( 2883d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org (TickTime::Now() - capture_start_time).Milliseconds()); 2893d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org callback_->OnCaptureCompleted(result); 2903d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} 2913d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2923d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgvoid ScreenCapturerLinux::SetMouseShapeObserver( 2933d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org MouseShapeObserver* mouse_shape_observer) { 2943d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DCHECK(!mouse_shape_observer_); 2953d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DCHECK(mouse_shape_observer); 2963d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 2973d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org mouse_shape_observer_ = mouse_shape_observer; 2983d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} 2993d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3003d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgvoid ScreenCapturerLinux::ProcessPendingXEvents() { 3013d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Find the number of events that are outstanding "now." We don't just loop 3023d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // on XPending because we want to guarantee this terminates. 303894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org int events_to_process = XPending(display()); 3043d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org XEvent e; 3053d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3063d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org for (int i = 0; i < events_to_process; i++) { 307894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org XNextEvent(display(), &e); 3083d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (use_damage_ && (e.type == damage_event_base_ + XDamageNotify)) { 3093d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org XDamageNotifyEvent* event = reinterpret_cast<XDamageNotifyEvent*>(&e); 3103d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DCHECK(event->level == XDamageReportNonEmpty); 3113d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } else if (e.type == ConfigureNotify) { 3129f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org ScreenConfigurationChanged(); 3133d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } else if (has_xfixes_ && 3143d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org e.type == xfixes_event_base_ + XFixesCursorNotify) { 3153d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org XFixesCursorNotifyEvent* cne; 3163d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org cne = reinterpret_cast<XFixesCursorNotifyEvent*>(&e); 3173d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (cne->subtype == XFixesDisplayCursorNotify) { 3183d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org CaptureCursor(); 3193d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 3203d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } else { 3213d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org LOG(LS_WARNING) << "Got unknown event type: " << e.type; 3223d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 3233d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 3243d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} 3253d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3263d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgvoid ScreenCapturerLinux::CaptureCursor() { 3273d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DCHECK(has_xfixes_); 3283d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 329894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org XFixesCursorImage* img = XFixesGetCursorImage(display()); 3303d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (!img) { 3313d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org return; 3323d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 3333d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3343d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org scoped_ptr<MouseCursorShape> cursor(new MouseCursorShape()); 3353d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org cursor->size = DesktopSize(img->width, img->height); 3363d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org cursor->hotspot = DesktopVector(img->xhot, img->yhot); 3373d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3383d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org int total_bytes = cursor->size.width ()* cursor->size.height() * 3393d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DesktopFrame::kBytesPerPixel; 3403d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org cursor->data.resize(total_bytes); 3413d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3423d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Xlib stores 32-bit data in longs, even if longs are 64-bits long. 3433d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org unsigned long* src = img->pixels; 3443d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org uint32_t* dst = reinterpret_cast<uint32_t*>(&*(cursor->data.begin())); 3453d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org uint32_t* dst_end = dst + (img->width * img->height); 3463d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org while (dst < dst_end) { 3473d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org *dst++ = static_cast<uint32_t>(*src++); 3483d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 3493d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org XFree(img); 3503d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3513d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (mouse_shape_observer_) 3523d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org mouse_shape_observer_->OnCursorShapeChanged(cursor.release()); 3533d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} 3543d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3553d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgDesktopFrame* ScreenCapturerLinux::CaptureScreen() { 3563d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DesktopFrame* frame = queue_.current_frame()->Share(); 3579f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org assert(x_server_pixel_buffer_.window_size().equals(frame->size())); 3583d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3593d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Pass the screen size to the helper, so it can clip the invalid region if it 3603d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // expands that region to a grid. 3613d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org helper_.set_size_most_recent(frame->size()); 3623d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3633d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // In the DAMAGE case, ensure the frame is up-to-date with the previous frame 3643d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // if any. If there isn't a previous frame, that means a screen-resolution 3653d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // change occurred, and |invalid_rects| will be updated to include the whole 3663d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // screen. 3673d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (use_damage_ && queue_.previous_frame()) 3683d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org SynchronizeFrame(); 3693d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3703d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DesktopRegion* updated_region = frame->mutable_updated_region(); 3713d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3723d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org x_server_pixel_buffer_.Synchronize(); 3733d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (use_damage_ && queue_.previous_frame()) { 3743d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Atomically fetch and clear the damage region. 375894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org XDamageSubtract(display(), damage_handle_, None, damage_region_); 3763d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org int rects_num = 0; 3773d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org XRectangle bounds; 378894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org XRectangle* rects = XFixesFetchRegionAndBounds(display(), damage_region_, 3793d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org &rects_num, &bounds); 3803d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org for (int i = 0; i < rects_num; ++i) { 3813d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org updated_region->AddRect(DesktopRect::MakeXYWH( 3823d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org rects[i].x, rects[i].y, rects[i].width, rects[i].height)); 3833d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 3843d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org XFree(rects); 3853d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org helper_.InvalidateRegion(*updated_region); 3863d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3873d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Capture the damaged portions of the desktop. 3883d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org helper_.TakeInvalidRegion(updated_region); 3893d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3903d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Clip the damaged portions to the current screen size, just in case some 3913d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // spurious XDamage notifications were received for a previous (larger) 3923d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // screen size. 3933d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org updated_region->IntersectWith( 3949f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org DesktopRect::MakeSize(x_server_pixel_buffer_.window_size())); 3953d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 3963d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org for (DesktopRegion::Iterator it(*updated_region); 3973d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org !it.IsAtEnd(); it.Advance()) { 3989f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org x_server_pixel_buffer_.CaptureRect(it.rect(), frame); 3993d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 4003d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } else { 4013d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Doing full-screen polling, or this is the first capture after a 4023d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // screen-resolution change. In either case, need a full-screen capture. 4039f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org DesktopRect screen_rect = DesktopRect::MakeSize(frame->size()); 4049f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org x_server_pixel_buffer_.CaptureRect(screen_rect, frame); 4053d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 4063d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (queue_.previous_frame()) { 4073d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Full-screen polling, so calculate the invalid rects here, based on the 4083d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // changed pixels between current and previous buffers. 4093d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DCHECK(differ_.get() != NULL); 4103d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DCHECK(queue_.previous_frame()->data()); 4113d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org differ_->CalcDirtyRegion(queue_.previous_frame()->data(), 4123d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org frame->data(), updated_region); 4133d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } else { 4143d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // No previous buffer, so always invalidate the whole screen, whether 4153d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // or not DAMAGE is being used. DAMAGE doesn't necessarily send a 4163d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // full-screen notification after a screen-resolution change, so 4173d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // this is done here. 4183d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org updated_region->SetRect(screen_rect); 4193d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 4203d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 4213d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 4223d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org return frame; 4233d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} 4243d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 4259f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.orgvoid ScreenCapturerLinux::ScreenConfigurationChanged() { 4263d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Make sure the frame buffers will be reallocated. 4273d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org queue_.Reset(); 4283d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 4293d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org helper_.ClearInvalidRegion(); 430894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org if (!x_server_pixel_buffer_.Init(display(), DefaultRootWindow(display()))) { 4319f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org LOG(LS_ERROR) << "Failed to initialize pixel buffer after screen " 4329f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org "configuration change."; 4339f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org } 4343d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} 4353d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 4363d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgvoid ScreenCapturerLinux::SynchronizeFrame() { 4373d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // Synchronize the current buffer with the previous one since we do not 4383d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // capture the entire desktop. Note that encoder may be reading from the 4393d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // previous buffer at this time so thread access complaints are false 4403d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // positives. 4413d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 4423d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // TODO(hclam): We can reduce the amount of copying here by subtracting 4433d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // |capturer_helper_|s region from |last_invalid_region_|. 4443d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org // http://crbug.com/92354 4453d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DCHECK(queue_.previous_frame()); 4463d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 4473d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DesktopFrame* current = queue_.current_frame(); 4483d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DesktopFrame* last = queue_.previous_frame(); 4493d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org DCHECK(current != last); 4503d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org for (DesktopRegion::Iterator it(last_invalid_region_); 4513d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org !it.IsAtEnd(); it.Advance()) { 4523d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org const DesktopRect& r = it.rect(); 4533d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org int offset = r.top() * current->stride() + 4543d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org r.left() * DesktopFrame::kBytesPerPixel; 4553d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org for (int i = 0; i < r.height(); ++i) { 4563d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org memcpy(current->data() + offset, last->data() + offset, 4573d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org r.width() * DesktopFrame::kBytesPerPixel); 4583d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org offset += current->size().width() * DesktopFrame::kBytesPerPixel; 4593d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 4603d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 4613d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} 4623d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 4633d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgvoid ScreenCapturerLinux::DeinitXlib() { 4643d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org if (gc_) { 465894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org XFreeGC(display(), gc_); 4663d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org gc_ = NULL; 4673d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 4683d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 4693d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org x_server_pixel_buffer_.Release(); 4703d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 471894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org if (display()) { 472894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org if (damage_handle_) { 473894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org XDamageDestroy(display(), damage_handle_); 474894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org damage_handle_ = 0; 475894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org } 476894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org 477894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org if (damage_region_) { 478894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org XFixesDestroyRegion(display(), damage_region_); 479894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org damage_region_ = 0; 480894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org } 4813d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org } 4823d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} 4833d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 4843d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} // namespace 4853d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 4863d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org// static 487894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.orgScreenCapturer* ScreenCapturer::Create(const DesktopCaptureOptions& options) { 488894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org if (!options.x_display()) 489894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org return NULL; 4903d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 4913d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org scoped_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux()); 492894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org if (!capturer->Init(options)) 4933d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org capturer.reset(); 4943d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org return capturer.release(); 4953d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} 4963d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org 4973d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org} // namespace webrtc 498