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

Unified Diff: media/video/capture/screen/screen_capturer_x11.cc

Issue 15692018: Remove screen capturers from media/video/capture/screen. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: media/video/capture/screen/screen_capturer_x11.cc
diff --git a/media/video/capture/screen/screen_capturer_x11.cc b/media/video/capture/screen/screen_capturer_x11.cc
deleted file mode 100644
index 775151c0236eb1bce6dd1f21ac4d333a5befdeea..0000000000000000000000000000000000000000
--- a/media/video/capture/screen/screen_capturer_x11.cc
+++ /dev/null
@@ -1,613 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/video/capture/screen/screen_capturer.h"
-
-#include <X11/extensions/Xdamage.h>
-#include <X11/extensions/Xfixes.h>
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-
-#include <set>
-
-#include "base/basictypes.h"
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "media/video/capture/screen/differ.h"
-#include "media/video/capture/screen/mouse_cursor_shape.h"
-#include "media/video/capture/screen/screen_capture_frame_queue.h"
-#include "media/video/capture/screen/screen_capturer_helper.h"
-#include "media/video/capture/screen/x11/x_server_pixel_buffer.h"
-#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
-
-namespace media {
-
-namespace {
-
-// A class to perform video frame capturing for Linux.
-class ScreenCapturerLinux : public ScreenCapturer {
- public:
- ScreenCapturerLinux();
- virtual ~ScreenCapturerLinux();
-
- // TODO(ajwong): Do we really want this to be synchronous?
- bool Init(bool use_x_damage);
-
- // DesktopCapturer interface.
- virtual void Start(Callback* delegate) OVERRIDE;
- virtual void Capture(const webrtc::DesktopRegion& region) OVERRIDE;
-
- // ScreenCapturer interface.
- virtual void SetMouseShapeObserver(
- MouseShapeObserver* mouse_shape_observer) OVERRIDE;
-
- private:
- void InitXDamage();
-
- // Read and handle all currently-pending XEvents.
- // In the DAMAGE case, process the XDamage events and store the resulting
- // damage rectangles in the ScreenCapturerHelper.
- // In all cases, call ScreenConfigurationChanged() in response to any
- // ConfigNotify events.
- void ProcessPendingXEvents();
-
- // Capture the cursor image and notify the delegate if it was captured.
- void CaptureCursor();
-
- // Capture screen pixels to the current buffer in the queue. In the DAMAGE
- // case, the ScreenCapturerHelper already holds the list of invalid rectangles
- // from ProcessPendingXEvents(). In the non-DAMAGE case, this captures the
- // whole screen, then calculates some invalid rectangles that include any
- // differences between this and the previous capture.
- webrtc::DesktopFrame* CaptureScreen();
-
- // Called when the screen configuration is changed. |root_window_size|
- // specifies the most recent size of the root window.
- void ScreenConfigurationChanged(const webrtc::DesktopSize& root_window_size);
-
- // Synchronize the current buffer with |last_buffer_|, by copying pixels from
- // the area of |last_invalid_rects|.
- // Note this only works on the assumption that kNumBuffers == 2, as
- // |last_invalid_rects| holds the differences from the previous buffer and
- // the one prior to that (which will then be the current buffer).
- void SynchronizeFrame();
-
- void DeinitXlib();
-
- // Capture a rectangle from |x_server_pixel_buffer_|, and copy the data into
- // |frame|.
- void CaptureRect(const webrtc::DesktopRect& rect,
- webrtc::DesktopFrame* frame);
-
- // We expose two forms of blitting to handle variations in the pixel format.
- // In FastBlit, the operation is effectively a memcpy.
- void FastBlit(uint8* image,
- const webrtc::DesktopRect& rect,
- webrtc::DesktopFrame* frame);
- void SlowBlit(uint8* image,
- const webrtc::DesktopRect& rect,
- webrtc::DesktopFrame* frame);
-
- // 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.
- static uint32 GetRgbShift(uint32 mask);
-
- Callback* callback_;
- MouseShapeObserver* mouse_shape_observer_;
-
- // X11 graphics context.
- Display* display_;
- GC gc_;
- Window root_window_;
-
- // Last known dimensions of the root window.
- webrtc::DesktopSize root_window_size_;
-
- // XFixes.
- bool has_xfixes_;
- int xfixes_event_base_;
- int xfixes_error_base_;
-
- // XDamage information.
- bool use_damage_;
- Damage damage_handle_;
- int damage_event_base_;
- int damage_error_base_;
- XserverRegion damage_region_;
-
- // Access to the X Server's pixel buffer.
- XServerPixelBuffer x_server_pixel_buffer_;
-
- // A thread-safe list of invalid rectangles, and the size of the most
- // recently captured screen.
- ScreenCapturerHelper helper_;
-
- // Queue of the frames buffers.
- ScreenCaptureFrameQueue queue_;
-
- // Invalid region from the previous capture. This is used to synchronize the
- // current with the last buffer used.
- webrtc::DesktopRegion last_invalid_region_;
-
- // |Differ| for use when polling for changes.
- scoped_ptr<Differ> differ_;
-
- DISALLOW_COPY_AND_ASSIGN(ScreenCapturerLinux);
-};
-
-ScreenCapturerLinux::ScreenCapturerLinux()
- : callback_(NULL),
- mouse_shape_observer_(NULL),
- display_(NULL),
- gc_(NULL),
- root_window_(BadValue),
- has_xfixes_(false),
- xfixes_event_base_(-1),
- xfixes_error_base_(-1),
- use_damage_(false),
- damage_handle_(0),
- damage_event_base_(-1),
- damage_error_base_(-1),
- damage_region_(0) {
- helper_.SetLogGridSize(4);
-}
-
-ScreenCapturerLinux::~ScreenCapturerLinux() {
- DeinitXlib();
-}
-
-bool ScreenCapturerLinux::Init(bool use_x_damage) {
- // TODO(ajwong): We should specify the display string we are attaching to
- // in the constructor.
- display_ = XOpenDisplay(NULL);
- if (!display_) {
- LOG(ERROR) << "Unable to open display";
- return false;
- }
-
- root_window_ = RootWindow(display_, DefaultScreen(display_));
- if (root_window_ == BadValue) {
- LOG(ERROR) << "Unable to get the root window";
- DeinitXlib();
- return false;
- }
-
- gc_ = XCreateGC(display_, root_window_, 0, NULL);
- if (gc_ == NULL) {
- LOG(ERROR) << "Unable to get graphics context";
- DeinitXlib();
- return false;
- }
-
- // Check for XFixes extension. This is required for cursor shape
- // notifications, and for our use of XDamage.
- if (XFixesQueryExtension(display_, &xfixes_event_base_,
- &xfixes_error_base_)) {
- has_xfixes_ = true;
- } else {
- LOG(INFO) << "X server does not support XFixes.";
- }
-
- // Register for changes to the dimensions of the root window.
- XSelectInput(display_, root_window_, StructureNotifyMask);
-
- root_window_size_ = XServerPixelBuffer::GetRootWindowSize(display_);
- x_server_pixel_buffer_.Init(display_, root_window_size_);
-
- if (has_xfixes_) {
- // Register for changes to the cursor shape.
- XFixesSelectCursorInput(display_, root_window_,
- XFixesDisplayCursorNotifyMask);
- }
-
- if (use_x_damage) {
- InitXDamage();
- }
-
- return true;
-}
-
-void ScreenCapturerLinux::InitXDamage() {
- // Our use of XDamage requires XFixes.
- if (!has_xfixes_) {
- return;
- }
-
- // Check for XDamage extension.
- if (!XDamageQueryExtension(display_, &damage_event_base_,
- &damage_error_base_)) {
- LOG(INFO) << "X server does not support XDamage.";
- return;
- }
-
- // TODO(lambroslambrou): Disable DAMAGE in situations where it is known
- // to fail, such as when Desktop Effects are enabled, with graphics
- // drivers (nVidia, ATI) that fail to report DAMAGE notifications
- // properly.
-
- // Request notifications every time the screen becomes damaged.
- damage_handle_ = XDamageCreate(display_, root_window_,
- XDamageReportNonEmpty);
- if (!damage_handle_) {
- LOG(ERROR) << "Unable to initialize XDamage.";
- return;
- }
-
- // Create an XFixes server-side region to collate damage into.
- damage_region_ = XFixesCreateRegion(display_, 0, 0);
- if (!damage_region_) {
- XDamageDestroy(display_, damage_handle_);
- LOG(ERROR) << "Unable to create XFixes region.";
- return;
- }
-
- use_damage_ = true;
- LOG(INFO) << "Using XDamage extension.";
-}
-
-void ScreenCapturerLinux::Start(Callback* callback) {
- DCHECK(!callback_);
- DCHECK(callback);
-
- callback_ = callback;
-}
-
-void ScreenCapturerLinux::Capture(const webrtc::DesktopRegion& region) {
- base::Time capture_start_time = base::Time::Now();
-
- queue_.MoveToNextFrame();
-
- // Process XEvents for XDamage and cursor shape tracking.
- ProcessPendingXEvents();
-
- // If the current frame is from an older generation then allocate a new one.
- // Note that we can't reallocate other buffers at this point, since the caller
- // may still be reading from them.
- if (!queue_.current_frame()) {
- scoped_ptr<webrtc::DesktopFrame> frame(
- new webrtc::BasicDesktopFrame(root_window_size_));
- queue_.ReplaceCurrentFrame(frame.Pass());
- }
-
- // Refresh the Differ helper used by CaptureFrame(), if needed.
- webrtc::DesktopFrame* frame = queue_.current_frame();
- if (!use_damage_ && (
- !differ_.get() ||
- (differ_->width() != frame->size().width()) ||
- (differ_->height() != frame->size().height()) ||
- (differ_->bytes_per_row() != frame->stride()))) {
- differ_.reset(new Differ(frame->size().width(), frame->size().height(),
- webrtc::DesktopFrame::kBytesPerPixel,
- frame->stride()));
- }
-
- webrtc::DesktopFrame* result = CaptureScreen();
- last_invalid_region_ = result->updated_region();
- result->set_capture_time_ms(
- (base::Time::Now() - capture_start_time).InMillisecondsRoundedUp());
- callback_->OnCaptureCompleted(result);
-}
-
-void ScreenCapturerLinux::SetMouseShapeObserver(
- MouseShapeObserver* mouse_shape_observer) {
- DCHECK(!mouse_shape_observer_);
- DCHECK(mouse_shape_observer);
-
- mouse_shape_observer_ = mouse_shape_observer;
-}
-
-void ScreenCapturerLinux::ProcessPendingXEvents() {
- // 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);
- if (use_damage_ && (e.type == damage_event_base_ + XDamageNotify)) {
- XDamageNotifyEvent* event = reinterpret_cast<XDamageNotifyEvent*>(&e);
- DCHECK(event->level == XDamageReportNonEmpty);
- } else if (e.type == ConfigureNotify) {
- const XConfigureEvent& event = e.xconfigure;
- ScreenConfigurationChanged(
- webrtc::DesktopSize(event.width, event.height));
- } else if (has_xfixes_ &&
- e.type == xfixes_event_base_ + XFixesCursorNotify) {
- XFixesCursorNotifyEvent* cne;
- cne = reinterpret_cast<XFixesCursorNotifyEvent*>(&e);
- if (cne->subtype == XFixesDisplayCursorNotify) {
- CaptureCursor();
- }
- } else {
- LOG(WARNING) << "Got unknown event type: " << e.type;
- }
- }
-}
-
-void ScreenCapturerLinux::CaptureCursor() {
- DCHECK(has_xfixes_);
-
- XFixesCursorImage* img = XFixesGetCursorImage(display_);
- if (!img) {
- return;
- }
-
- scoped_ptr<MouseCursorShape> cursor(new MouseCursorShape());
- cursor->size = webrtc::DesktopSize(img->width, img->height);
- cursor->hotspot = webrtc::DesktopVector(img->xhot, img->yhot);
-
- int total_bytes = cursor->size.width ()* cursor->size.height() *
- webrtc::DesktopFrame::kBytesPerPixel;
- cursor->data.resize(total_bytes);
-
- // Xlib stores 32-bit data in longs, even if longs are 64-bits long.
- unsigned long* src = img->pixels;
- uint32* dst = reinterpret_cast<uint32*>(&*(cursor->data.begin()));
- uint32* dst_end = dst + (img->width * img->height);
- while (dst < dst_end) {
- *dst++ = static_cast<uint32>(*src++);
- }
- XFree(img);
-
- if (mouse_shape_observer_)
- mouse_shape_observer_->OnCursorShapeChanged(cursor.Pass());
-}
-
-webrtc::DesktopFrame* ScreenCapturerLinux::CaptureScreen() {
- webrtc::DesktopFrame* frame = queue_.current_frame()->Share();
-
- // Pass the screen size to the helper, so it can clip the invalid region if it
- // expands that region to a grid.
- helper_.set_size_most_recent(frame->size());
-
- // In the DAMAGE case, ensure the frame is up-to-date with the previous frame
- // if any. If there isn't a previous frame, that means a screen-resolution
- // change occurred, and |invalid_rects| will be updated to include the whole
- // screen.
- if (use_damage_ && queue_.previous_frame())
- SynchronizeFrame();
-
- webrtc::DesktopRegion* updated_region = frame->mutable_updated_region();
-
- x_server_pixel_buffer_.Synchronize();
- if (use_damage_ && queue_.previous_frame()) {
- // Atomically fetch and clear the damage region.
- XDamageSubtract(display_, damage_handle_, None, damage_region_);
- int rects_num = 0;
- XRectangle bounds;
- XRectangle* rects = XFixesFetchRegionAndBounds(display_, damage_region_,
- &rects_num, &bounds);
- for (int i = 0; i < rects_num; ++i) {
- updated_region->AddRect(webrtc::DesktopRect::MakeXYWH(
- rects[i].x, rects[i].y, rects[i].width, rects[i].height));
- }
- XFree(rects);
- helper_.InvalidateRegion(*updated_region);
-
- // Capture the damaged portions of the desktop.
- helper_.TakeInvalidRegion(updated_region);
-
- // Clip the damaged portions to the current screen size, just in case some
- // spurious XDamage notifications were received for a previous (larger)
- // screen size.
- updated_region->IntersectWith(
- webrtc::DesktopRect::MakeSize(root_window_size_));
- for (webrtc::DesktopRegion::Iterator it(*updated_region);
- !it.IsAtEnd(); it.Advance()) {
- CaptureRect(it.rect(), frame);
- }
- } else {
- // Doing full-screen polling, or this is the first capture after a
- // screen-resolution change. In either case, need a full-screen capture.
- webrtc::DesktopRect screen_rect =
- webrtc::DesktopRect::MakeSize(frame->size());
- CaptureRect(screen_rect, frame);
-
- if (queue_.previous_frame()) {
- // Full-screen polling, so calculate the invalid rects here, based on the
- // changed pixels between current and previous buffers.
- DCHECK(differ_ != NULL);
- DCHECK(queue_.previous_frame()->data());
- differ_->CalcDirtyRegion(queue_.previous_frame()->data(),
- frame->data(), updated_region);
- } else {
- // No previous buffer, so always invalidate the whole screen, whether
- // or not DAMAGE is being used. DAMAGE doesn't necessarily send a
- // full-screen notification after a screen-resolution change, so
- // this is done here.
- updated_region->SetRect(screen_rect);
- }
- }
-
- return frame;
-}
-
-void ScreenCapturerLinux::ScreenConfigurationChanged(
- const webrtc::DesktopSize& root_window_size) {
- root_window_size_ = root_window_size;
-
- // Make sure the frame buffers will be reallocated.
- queue_.Reset();
-
- helper_.ClearInvalidRegion();
- x_server_pixel_buffer_.Init(display_, root_window_size_);
-}
-
-void ScreenCapturerLinux::SynchronizeFrame() {
- // Synchronize the current buffer with the previous one since we do not
- // capture the entire desktop. Note that encoder may be reading from the
- // previous buffer at this time so thread access complaints are false
- // positives.
-
- // TODO(hclam): We can reduce the amount of copying here by subtracting
- // |capturer_helper_|s region from |last_invalid_region_|.
- // http://crbug.com/92354
- DCHECK(queue_.previous_frame());
-
- webrtc::DesktopFrame* current = queue_.current_frame();
- webrtc::DesktopFrame* last = queue_.previous_frame();
- DCHECK_NE(current, last);
- for (webrtc::DesktopRegion::Iterator it(last_invalid_region_);
- !it.IsAtEnd(); it.Advance()) {
- const webrtc::DesktopRect& r = it.rect();
- int offset = r.top() * current->stride() +
- r.left() * webrtc::DesktopFrame::kBytesPerPixel;
- for (int i = 0; i < r.height(); ++i) {
- memcpy(current->data() + offset, last->data() + offset,
- r.width() * webrtc::DesktopFrame::kBytesPerPixel);
- offset += current->size().width() * webrtc::DesktopFrame::kBytesPerPixel;
- }
- }
-}
-
-void ScreenCapturerLinux::DeinitXlib() {
- if (gc_) {
- XFreeGC(display_, gc_);
- gc_ = NULL;
- }
-
- x_server_pixel_buffer_.Release();
-
- if (display_) {
- if (damage_handle_)
- XDamageDestroy(display_, damage_handle_);
- if (damage_region_)
- XFixesDestroyRegion(display_, damage_region_);
- XCloseDisplay(display_);
- display_ = NULL;
- damage_handle_ = 0;
- damage_region_ = 0;
- }
-}
-
-void ScreenCapturerLinux::CaptureRect(const webrtc::DesktopRect& rect,
- webrtc::DesktopFrame* frame) {
- uint8* image = x_server_pixel_buffer_.CaptureRect(rect);
- int depth = x_server_pixel_buffer_.GetDepth();
- if ((depth == 24 || depth == 32) &&
- x_server_pixel_buffer_.GetBitsPerPixel() == 32 &&
- x_server_pixel_buffer_.GetRedMask() == 0xff0000 &&
- x_server_pixel_buffer_.GetGreenMask() == 0xff00 &&
- x_server_pixel_buffer_.GetBlueMask() == 0xff) {
- DVLOG(3) << "Fast blitting";
- FastBlit(image, rect, frame);
- } else {
- DVLOG(3) << "Slow blitting";
- SlowBlit(image, rect, frame);
- }
-}
-
-void ScreenCapturerLinux::FastBlit(uint8* image,
- const webrtc::DesktopRect& rect,
- webrtc::DesktopFrame* frame) {
- uint8* src_pos = image;
- int src_stride = x_server_pixel_buffer_.GetStride();
- int dst_x = rect.left(), dst_y = rect.top();
-
- uint8* dst_pos = frame->data() + frame->stride() * dst_y;
- dst_pos += dst_x * webrtc::DesktopFrame::kBytesPerPixel;
-
- int height = rect.height();
- int row_bytes = rect.width() * webrtc::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 ScreenCapturerLinux::SlowBlit(uint8* image,
- const webrtc::DesktopRect& rect,
- webrtc::DesktopFrame* frame) {
- int src_stride = x_server_pixel_buffer_.GetStride();
- int dst_x = rect.left(), dst_y = rect.top();
- int width = rect.width(), height = rect.height();
-
- uint32 red_mask = x_server_pixel_buffer_.GetRedMask();
- uint32 green_mask = x_server_pixel_buffer_.GetGreenMask();
- uint32 blue_mask = x_server_pixel_buffer_.GetBlueMask();
-
- uint32 red_shift = GetRgbShift(red_mask);
- uint32 green_shift = GetRgbShift(green_mask);
- uint32 blue_shift = GetRgbShift(blue_mask);
-
- unsigned int bits_per_pixel = x_server_pixel_buffer_.GetBitsPerPixel();
-
- uint8* dst_pos = frame->data() + frame->stride() * dst_y;
- uint8* src_pos = image;
- dst_pos += dst_x * webrtc::DesktopFrame::kBytesPerPixel;
- // TODO(hclam): Optimize, perhaps using MMX code or by converting to
- // YUV directly
- for (int y = 0; y < height; y++) {
- uint32* dst_pos_32 = reinterpret_cast<uint32*>(dst_pos);
- uint32* src_pos_32 = reinterpret_cast<uint32*>(src_pos);
- uint16* src_pos_16 = reinterpret_cast<uint16*>(src_pos);
- for (int x = 0; x < width; x++) {
- // Dereference through an appropriately-aligned pointer.
- uint32 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 r = (pixel & red_mask) << red_shift;
- uint32 g = (pixel & green_mask) << green_shift;
- uint32 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;
- }
-}
-
-// static
-uint32 ScreenCapturerLinux::GetRgbShift(uint32 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;
-}
-
-} // namespace
-
-// static
-scoped_ptr<ScreenCapturer> ScreenCapturer::Create() {
- scoped_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux());
- if (!capturer->Init(false))
- capturer.reset();
- return capturer.PassAs<ScreenCapturer>();
-}
-
-// static
-scoped_ptr<ScreenCapturer> ScreenCapturer::CreateWithXDamage(
- bool use_x_damage) {
- scoped_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux());
- if (!capturer->Init(use_x_damage))
- capturer.reset();
- return capturer.PassAs<ScreenCapturer>();
-}
-
-} // namespace media
« no previous file with comments | « media/video/capture/screen/screen_capturer_win.cc ('k') | media/video/capture/screen/shared_desktop_frame.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698