aboutsummaryrefslogtreecommitdiff
path: root/webrtc/modules/desktop_capture/x11
diff options
context:
space:
mode:
Diffstat (limited to 'webrtc/modules/desktop_capture/x11')
-rw-r--r--webrtc/modules/desktop_capture/x11/shared_x_display.cc87
-rw-r--r--webrtc/modules/desktop_capture/x11/shared_x_display.h84
-rw-r--r--webrtc/modules/desktop_capture/x11/x_error_trap.cc69
-rw-r--r--webrtc/modules/desktop_capture/x11/x_error_trap.h39
-rw-r--r--webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.cc337
-rw-r--r--webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.h85
6 files changed, 701 insertions, 0 deletions
diff --git a/webrtc/modules/desktop_capture/x11/shared_x_display.cc b/webrtc/modules/desktop_capture/x11/shared_x_display.cc
new file mode 100644
index 0000000000..3eb5eb10a9
--- /dev/null
+++ b/webrtc/modules/desktop_capture/x11/shared_x_display.cc
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/modules/desktop_capture/x11/shared_x_display.h"
+
+#include <algorithm>
+
+#include "webrtc/system_wrappers/include/logging.h"
+
+namespace webrtc {
+
+SharedXDisplay::SharedXDisplay(Display* display)
+ : display_(display) {
+ assert(display_);
+}
+
+SharedXDisplay::~SharedXDisplay() {
+ assert(event_handlers_.empty());
+ XCloseDisplay(display_);
+}
+
+// static
+rtc::scoped_refptr<SharedXDisplay> SharedXDisplay::Create(
+ const std::string& display_name) {
+ Display* display =
+ XOpenDisplay(display_name.empty() ? NULL : display_name.c_str());
+ if (!display) {
+ LOG(LS_ERROR) << "Unable to open display";
+ return NULL;
+ }
+ return new SharedXDisplay(display);
+}
+
+// static
+rtc::scoped_refptr<SharedXDisplay> SharedXDisplay::CreateDefault() {
+ return Create(std::string());
+}
+
+void SharedXDisplay::AddEventHandler(int type, XEventHandler* handler) {
+ event_handlers_[type].push_back(handler);
+}
+
+void SharedXDisplay::RemoveEventHandler(int type, XEventHandler* handler) {
+ EventHandlersMap::iterator handlers = event_handlers_.find(type);
+ if (handlers == event_handlers_.end())
+ return;
+
+ std::vector<XEventHandler*>::iterator new_end =
+ std::remove(handlers->second.begin(), handlers->second.end(), handler);
+ handlers->second.erase(new_end, handlers->second.end());
+
+ // Check if no handlers left for this event.
+ if (handlers->second.empty())
+ event_handlers_.erase(handlers);
+}
+
+void SharedXDisplay::ProcessPendingXEvents() {
+ // Hold reference to |this| to prevent it from being destroyed while
+ // processing events.
+ rtc::scoped_refptr<SharedXDisplay> self(this);
+
+ // Find the number of events that are outstanding "now." We don't just loop
+ // on XPending because we want to guarantee this terminates.
+ int events_to_process = XPending(display());
+ XEvent e;
+
+ for (int i = 0; i < events_to_process; i++) {
+ XNextEvent(display(), &e);
+ EventHandlersMap::iterator handlers = event_handlers_.find(e.type);
+ if (handlers == event_handlers_.end())
+ continue;
+ for (std::vector<XEventHandler*>::iterator it = handlers->second.begin();
+ it != handlers->second.end(); ++it) {
+ if ((*it)->HandleXEvent(e))
+ break;
+ }
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/desktop_capture/x11/shared_x_display.h b/webrtc/modules/desktop_capture/x11/shared_x_display.h
new file mode 100644
index 0000000000..d905b9e51c
--- /dev/null
+++ b/webrtc/modules/desktop_capture/x11/shared_x_display.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_X11_SHARED_X_DISPLAY_H_
+#define WEBRTC_MODULES_DESKTOP_CAPTURE_X11_SHARED_X_DISPLAY_H_
+
+#include <map>
+#include <vector>
+
+#include <assert.h>
+#include <X11/Xlib.h>
+
+#include <string>
+
+#include "webrtc/base/scoped_ref_ptr.h"
+#include "webrtc/system_wrappers/include/atomic32.h"
+
+namespace webrtc {
+
+// A ref-counted object to store XDisplay connection.
+class SharedXDisplay {
+ public:
+ class XEventHandler {
+ public:
+ virtual ~XEventHandler() {}
+
+ // Processes XEvent. Returns true if the event has been handled.
+ virtual bool HandleXEvent(const XEvent& event) = 0;
+ };
+
+ // Takes ownership of |display|.
+ explicit SharedXDisplay(Display* display);
+
+ // Creates a new X11 Display for the |display_name|. NULL is returned if X11
+ // connection failed. Equivalent to CreateDefault() when |display_name| is
+ // empty.
+ static rtc::scoped_refptr<SharedXDisplay> Create(
+ const std::string& display_name);
+
+ // Creates X11 Display connection for the default display (e.g. specified in
+ // DISPLAY). NULL is returned if X11 connection failed.
+ static rtc::scoped_refptr<SharedXDisplay> CreateDefault();
+
+ void AddRef() { ++ref_count_; }
+ void Release() {
+ if (--ref_count_ == 0)
+ delete this;
+ }
+
+ Display* display() { return display_; }
+
+ // Adds a new event |handler| for XEvent's of |type|.
+ void AddEventHandler(int type, XEventHandler* handler);
+
+ // Removes event |handler| added using |AddEventHandler|. Doesn't do anything
+ // if |handler| is not registered.
+ void RemoveEventHandler(int type, XEventHandler* handler);
+
+ // Processes pending XEvents, calling corresponding event handlers.
+ void ProcessPendingXEvents();
+
+ private:
+ typedef std::map<int, std::vector<XEventHandler*> > EventHandlersMap;
+
+ ~SharedXDisplay();
+
+ Atomic32 ref_count_;
+ Display* display_;
+
+ EventHandlersMap event_handlers_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(SharedXDisplay);
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_X11_SHARED_X_DISPLAY_H_
diff --git a/webrtc/modules/desktop_capture/x11/x_error_trap.cc b/webrtc/modules/desktop_capture/x11/x_error_trap.cc
new file mode 100644
index 0000000000..458fbe61a0
--- /dev/null
+++ b/webrtc/modules/desktop_capture/x11/x_error_trap.cc
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/modules/desktop_capture/x11/x_error_trap.h"
+
+#include <assert.h>
+
+#if defined(TOOLKIT_GTK)
+#include <gdk/gdk.h>
+#endif // !defined(TOOLKIT_GTK)
+
+namespace webrtc {
+
+namespace {
+
+#if !defined(TOOLKIT_GTK)
+
+// TODO(sergeyu): This code is not thread safe. Fix it. Bug 2202.
+static bool g_xserver_error_trap_enabled = false;
+static int g_last_xserver_error_code = 0;
+
+int XServerErrorHandler(Display* display, XErrorEvent* error_event) {
+ assert(g_xserver_error_trap_enabled);
+ g_last_xserver_error_code = error_event->error_code;
+ return 0;
+}
+
+#endif // !defined(TOOLKIT_GTK)
+
+} // namespace
+
+XErrorTrap::XErrorTrap(Display* display)
+ : original_error_handler_(NULL),
+ enabled_(true) {
+#if defined(TOOLKIT_GTK)
+ gdk_error_trap_push();
+#else // !defined(TOOLKIT_GTK)
+ assert(!g_xserver_error_trap_enabled);
+ original_error_handler_ = XSetErrorHandler(&XServerErrorHandler);
+ g_xserver_error_trap_enabled = true;
+ g_last_xserver_error_code = 0;
+#endif // !defined(TOOLKIT_GTK)
+}
+
+int XErrorTrap::GetLastErrorAndDisable() {
+ enabled_ = false;
+#if defined(TOOLKIT_GTK)
+ return gdk_error_trap_push();
+#else // !defined(TOOLKIT_GTK)
+ assert(g_xserver_error_trap_enabled);
+ XSetErrorHandler(original_error_handler_);
+ g_xserver_error_trap_enabled = false;
+ return g_last_xserver_error_code;
+#endif // !defined(TOOLKIT_GTK)
+}
+
+XErrorTrap::~XErrorTrap() {
+ if (enabled_)
+ GetLastErrorAndDisable();
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/desktop_capture/x11/x_error_trap.h b/webrtc/modules/desktop_capture/x11/x_error_trap.h
new file mode 100644
index 0000000000..f1f6e11c63
--- /dev/null
+++ b/webrtc/modules/desktop_capture/x11/x_error_trap.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_X11_X_ERROR_TRAP_H_
+#define WEBRTC_MODULES_DESKTOP_CAPTURE_X11_X_ERROR_TRAP_H_
+
+#include <X11/Xlib.h>
+
+#include "webrtc/base/constructormagic.h"
+
+namespace webrtc {
+
+// Helper class that registers X Window error handler. Caller can use
+// GetLastErrorAndDisable() to get the last error that was caught, if any.
+class XErrorTrap {
+ public:
+ explicit XErrorTrap(Display* display);
+ ~XErrorTrap();
+
+ // Returns last error and removes unregisters the error handler.
+ int GetLastErrorAndDisable();
+
+ private:
+ XErrorHandler original_error_handler_;
+ bool enabled_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(XErrorTrap);
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_X11_X_ERROR_TRAP_H_
diff --git a/webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.cc b/webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.cc
new file mode 100644
index 0000000000..bcfcb7e027
--- /dev/null
+++ b/webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.cc
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.h"
+
+#include <assert.h>
+#include <string.h>
+#include <sys/shm.h>
+
+#include "webrtc/modules/desktop_capture/desktop_frame.h"
+#include "webrtc/modules/desktop_capture/x11/x_error_trap.h"
+#include "webrtc/system_wrappers/include/logging.h"
+
+namespace {
+
+// Returns the number of bits |mask| has to be shifted left so its last
+// (most-significant) bit set becomes the most-significant bit of the word.
+// When |mask| is 0 the function returns 31.
+uint32_t MaskToShift(uint32_t mask) {
+ int shift = 0;
+ if ((mask & 0xffff0000u) == 0) {
+ mask <<= 16;
+ shift += 16;
+ }
+ if ((mask & 0xff000000u) == 0) {
+ mask <<= 8;
+ shift += 8;
+ }
+ if ((mask & 0xf0000000u) == 0) {
+ mask <<= 4;
+ shift += 4;
+ }
+ if ((mask & 0xc0000000u) == 0) {
+ mask <<= 2;
+ shift += 2;
+ }
+ if ((mask & 0x80000000u) == 0)
+ shift += 1;
+
+ return shift;
+}
+
+// Returns true if |image| is in RGB format.
+bool IsXImageRGBFormat(XImage* image) {
+ return image->bits_per_pixel == 32 &&
+ image->red_mask == 0xff0000 &&
+ image->green_mask == 0xff00 &&
+ image->blue_mask == 0xff;
+}
+
+} // namespace
+
+namespace webrtc {
+
+XServerPixelBuffer::XServerPixelBuffer()
+ : display_(NULL), window_(0),
+ x_image_(NULL),
+ shm_segment_info_(NULL), shm_pixmap_(0), shm_gc_(NULL) {
+}
+
+XServerPixelBuffer::~XServerPixelBuffer() {
+ Release();
+}
+
+void XServerPixelBuffer::Release() {
+ if (x_image_) {
+ XDestroyImage(x_image_);
+ x_image_ = NULL;
+ }
+ if (shm_pixmap_) {
+ XFreePixmap(display_, shm_pixmap_);
+ shm_pixmap_ = 0;
+ }
+ if (shm_gc_) {
+ XFreeGC(display_, shm_gc_);
+ shm_gc_ = NULL;
+ }
+ if (shm_segment_info_) {
+ if (shm_segment_info_->shmaddr != reinterpret_cast<char*>(-1))
+ shmdt(shm_segment_info_->shmaddr);
+ if (shm_segment_info_->shmid != -1)
+ shmctl(shm_segment_info_->shmid, IPC_RMID, 0);
+ delete shm_segment_info_;
+ shm_segment_info_ = NULL;
+ }
+ window_ = 0;
+}
+
+bool XServerPixelBuffer::Init(Display* display, Window window) {
+ Release();
+ display_ = display;
+
+ XWindowAttributes attributes;
+ {
+ XErrorTrap error_trap(display_);
+ if (!XGetWindowAttributes(display_, window, &attributes) ||
+ error_trap.GetLastErrorAndDisable() != 0) {
+ return false;
+ }
+ }
+
+ window_size_ = DesktopSize(attributes.width, attributes.height);
+ window_ = window;
+ InitShm(attributes);
+
+ return true;
+}
+
+void XServerPixelBuffer::InitShm(const XWindowAttributes& attributes) {
+ Visual* default_visual = attributes.visual;
+ int default_depth = attributes.depth;
+
+ int major, minor;
+ Bool have_pixmaps;
+ if (!XShmQueryVersion(display_, &major, &minor, &have_pixmaps)) {
+ // Shared memory not supported. CaptureRect will use the XImage API instead.
+ return;
+ }
+
+ bool using_shm = false;
+ shm_segment_info_ = new XShmSegmentInfo;
+ shm_segment_info_->shmid = -1;
+ shm_segment_info_->shmaddr = reinterpret_cast<char*>(-1);
+ shm_segment_info_->readOnly = False;
+ x_image_ = XShmCreateImage(display_, default_visual, default_depth, ZPixmap,
+ 0, shm_segment_info_, window_size_.width(),
+ window_size_.height());
+ if (x_image_) {
+ shm_segment_info_->shmid = shmget(
+ IPC_PRIVATE, x_image_->bytes_per_line * x_image_->height,
+ IPC_CREAT | 0600);
+ if (shm_segment_info_->shmid != -1) {
+ shm_segment_info_->shmaddr = x_image_->data =
+ reinterpret_cast<char*>(shmat(shm_segment_info_->shmid, 0, 0));
+ if (x_image_->data != reinterpret_cast<char*>(-1)) {
+ XErrorTrap error_trap(display_);
+ using_shm = XShmAttach(display_, shm_segment_info_);
+ XSync(display_, False);
+ if (error_trap.GetLastErrorAndDisable() != 0)
+ using_shm = false;
+ if (using_shm) {
+ LOG(LS_VERBOSE) << "Using X shared memory segment "
+ << shm_segment_info_->shmid;
+ }
+ }
+ } else {
+ LOG(LS_WARNING) << "Failed to get shared memory segment. "
+ "Performance may be degraded.";
+ }
+ }
+
+ if (!using_shm) {
+ LOG(LS_WARNING) << "Not using shared memory. Performance may be degraded.";
+ Release();
+ return;
+ }
+
+ if (have_pixmaps)
+ have_pixmaps = InitPixmaps(default_depth);
+
+ shmctl(shm_segment_info_->shmid, IPC_RMID, 0);
+ shm_segment_info_->shmid = -1;
+
+ LOG(LS_VERBOSE) << "Using X shared memory extension v"
+ << major << "." << minor
+ << " with" << (have_pixmaps ? "" : "out") << " pixmaps.";
+}
+
+bool XServerPixelBuffer::InitPixmaps(int depth) {
+ if (XShmPixmapFormat(display_) != ZPixmap)
+ return false;
+
+ {
+ XErrorTrap error_trap(display_);
+ shm_pixmap_ = XShmCreatePixmap(display_, window_,
+ shm_segment_info_->shmaddr,
+ shm_segment_info_,
+ window_size_.width(),
+ window_size_.height(), depth);
+ XSync(display_, False);
+ if (error_trap.GetLastErrorAndDisable() != 0) {
+ // |shm_pixmap_| is not not valid because the request was not processed
+ // by the X Server, so zero it.
+ shm_pixmap_ = 0;
+ return false;
+ }
+ }
+
+ {
+ XErrorTrap error_trap(display_);
+ XGCValues shm_gc_values;
+ shm_gc_values.subwindow_mode = IncludeInferiors;
+ shm_gc_values.graphics_exposures = False;
+ shm_gc_ = XCreateGC(display_, window_,
+ GCSubwindowMode | GCGraphicsExposures,
+ &shm_gc_values);
+ XSync(display_, False);
+ if (error_trap.GetLastErrorAndDisable() != 0) {
+ XFreePixmap(display_, shm_pixmap_);
+ shm_pixmap_ = 0;
+ shm_gc_ = 0; // See shm_pixmap_ comment above.
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool XServerPixelBuffer::IsWindowValid() const {
+ XWindowAttributes attributes;
+ {
+ XErrorTrap error_trap(display_);
+ if (!XGetWindowAttributes(display_, window_, &attributes) ||
+ error_trap.GetLastErrorAndDisable() != 0) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void XServerPixelBuffer::Synchronize() {
+ if (shm_segment_info_ && !shm_pixmap_) {
+ // XShmGetImage can fail if the display is being reconfigured.
+ XErrorTrap error_trap(display_);
+ XShmGetImage(display_, window_, x_image_, 0, 0, AllPlanes);
+ }
+}
+
+void XServerPixelBuffer::CaptureRect(const DesktopRect& rect,
+ DesktopFrame* frame) {
+ assert(rect.right() <= window_size_.width());
+ assert(rect.bottom() <= window_size_.height());
+
+ uint8_t* data;
+
+ if (shm_segment_info_) {
+ if (shm_pixmap_) {
+ XCopyArea(display_, window_, shm_pixmap_, shm_gc_,
+ rect.left(), rect.top(), rect.width(), rect.height(),
+ rect.left(), rect.top());
+ XSync(display_, False);
+ }
+ data = reinterpret_cast<uint8_t*>(x_image_->data) +
+ rect.top() * x_image_->bytes_per_line +
+ rect.left() * x_image_->bits_per_pixel / 8;
+ } else {
+ if (x_image_)
+ XDestroyImage(x_image_);
+ x_image_ = XGetImage(display_, window_, rect.left(), rect.top(),
+ rect.width(), rect.height(), AllPlanes, ZPixmap);
+ data = reinterpret_cast<uint8_t*>(x_image_->data);
+ }
+
+ if (IsXImageRGBFormat(x_image_)) {
+ FastBlit(data, rect, frame);
+ } else {
+ SlowBlit(data, rect, frame);
+ }
+}
+
+void XServerPixelBuffer::FastBlit(uint8_t* image,
+ const DesktopRect& rect,
+ DesktopFrame* frame) {
+ uint8_t* src_pos = image;
+ int src_stride = x_image_->bytes_per_line;
+ int dst_x = rect.left(), dst_y = rect.top();
+
+ uint8_t* dst_pos = frame->data() + frame->stride() * dst_y;
+ dst_pos += dst_x * DesktopFrame::kBytesPerPixel;
+
+ int height = rect.height();
+ int row_bytes = rect.width() * DesktopFrame::kBytesPerPixel;
+ for (int y = 0; y < height; ++y) {
+ memcpy(dst_pos, src_pos, row_bytes);
+ src_pos += src_stride;
+ dst_pos += frame->stride();
+ }
+}
+
+void XServerPixelBuffer::SlowBlit(uint8_t* image,
+ const DesktopRect& rect,
+ DesktopFrame* frame) {
+ int src_stride = x_image_->bytes_per_line;
+ int dst_x = rect.left(), dst_y = rect.top();
+ int width = rect.width(), height = rect.height();
+
+ uint32_t red_mask = x_image_->red_mask;
+ uint32_t green_mask = x_image_->red_mask;
+ uint32_t blue_mask = x_image_->blue_mask;
+
+ uint32_t red_shift = MaskToShift(red_mask);
+ uint32_t green_shift = MaskToShift(green_mask);
+ uint32_t blue_shift = MaskToShift(blue_mask);
+
+ int bits_per_pixel = x_image_->bits_per_pixel;
+
+ uint8_t* dst_pos = frame->data() + frame->stride() * dst_y;
+ uint8_t* src_pos = image;
+ dst_pos += dst_x * DesktopFrame::kBytesPerPixel;
+ // TODO(hclam): Optimize, perhaps using MMX code or by converting to
+ // YUV directly.
+ // TODO(sergeyu): This code doesn't handle XImage byte order properly and
+ // won't work with 24bpp images. Fix it.
+ for (int y = 0; y < height; y++) {
+ uint32_t* dst_pos_32 = reinterpret_cast<uint32_t*>(dst_pos);
+ uint32_t* src_pos_32 = reinterpret_cast<uint32_t*>(src_pos);
+ uint16_t* src_pos_16 = reinterpret_cast<uint16_t*>(src_pos);
+ for (int x = 0; x < width; x++) {
+ // Dereference through an appropriately-aligned pointer.
+ uint32_t pixel;
+ if (bits_per_pixel == 32) {
+ pixel = src_pos_32[x];
+ } else if (bits_per_pixel == 16) {
+ pixel = src_pos_16[x];
+ } else {
+ pixel = src_pos[x];
+ }
+ uint32_t r = (pixel & red_mask) << red_shift;
+ uint32_t g = (pixel & green_mask) << green_shift;
+ uint32_t b = (pixel & blue_mask) << blue_shift;
+ // Write as 32-bit RGB.
+ dst_pos_32[x] = ((r >> 8) & 0xff0000) | ((g >> 16) & 0xff00) |
+ ((b >> 24) & 0xff);
+ }
+ dst_pos += frame->stride();
+ src_pos += src_stride;
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.h b/webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.h
new file mode 100644
index 0000000000..d1e6632f08
--- /dev/null
+++ b/webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+// Don't include this file in any .h files because it pulls in some X headers.
+
+#ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_X11_X_SERVER_PIXEL_BUFFER_H_
+#define WEBRTC_MODULES_DESKTOP_CAPTURE_X11_X_SERVER_PIXEL_BUFFER_H_
+
+#include "webrtc/modules/desktop_capture/desktop_geometry.h"
+
+#include <X11/Xutil.h>
+#include <X11/extensions/XShm.h>
+
+namespace webrtc {
+
+class DesktopFrame;
+
+// A class to allow the X server's pixel buffer to be accessed as efficiently
+// as possible.
+class XServerPixelBuffer {
+ public:
+ XServerPixelBuffer();
+ ~XServerPixelBuffer();
+
+ void Release();
+
+ // Allocate (or reallocate) the pixel buffer for |window|. Returns false in
+ // case of an error (e.g. window doesn't exist).
+ bool Init(Display* display, Window window);
+
+ bool is_initialized() { return window_ != 0; }
+
+ // Returns the size of the window the buffer was initialized for.
+ const DesktopSize& window_size() { return window_size_; }
+
+ // Returns true if the window can be found.
+ bool IsWindowValid() const;
+
+ // If shared memory is being used without pixmaps, synchronize this pixel
+ // buffer with the root window contents (otherwise, this is a no-op).
+ // This is to avoid doing a full-screen capture for each individual
+ // rectangle in the capture list, when it only needs to be done once at the
+ // beginning.
+ void Synchronize();
+
+ // Capture the specified rectangle and stores it in the |frame|. In the case
+ // where the full-screen data is captured by Synchronize(), this simply
+ // returns the pointer without doing any more work. The caller must ensure
+ // that |rect| is not larger than window_size().
+ void CaptureRect(const DesktopRect& rect, DesktopFrame* frame);
+
+ private:
+ void InitShm(const XWindowAttributes& attributes);
+ bool InitPixmaps(int depth);
+
+ // We expose two forms of blitting to handle variations in the pixel format.
+ // In FastBlit(), the operation is effectively a memcpy.
+ void FastBlit(uint8_t* image,
+ const DesktopRect& rect,
+ DesktopFrame* frame);
+ void SlowBlit(uint8_t* image,
+ const DesktopRect& rect,
+ DesktopFrame* frame);
+
+ Display* display_;
+ Window window_;
+ DesktopSize window_size_;
+ XImage* x_image_;
+ XShmSegmentInfo* shm_segment_info_;
+ Pixmap shm_pixmap_;
+ GC shm_gc_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(XServerPixelBuffer);
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_X11_X_SERVER_PIXEL_BUFFER_H_