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

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

Issue 13983010: Use webrtc::DesktopCapturer for screen capturer implementation. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 7 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
« no previous file with comments | « media/video/capture/screen/screen_capturer_win.cc ('k') | media/video/capture/screen/shared_buffer.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
index f9da3b3533e4e1ede7054ba59da750c3187e43ab..7d1ee7867e4b83290820f863b31f895f0e2a32d0 100644
--- a/media/video/capture/screen/screen_capturer_x11.cc
+++ b/media/video/capture/screen/screen_capturer_x11.cc
@@ -15,32 +15,17 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/stl_util.h"
-#include "base/time.h"
#include "media/video/capture/screen/differ.h"
#include "media/video/capture/screen/mouse_cursor_shape.h"
-#include "media/video/capture/screen/screen_capture_data.h"
-#include "media/video/capture/screen/screen_capture_frame.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 representing a full-frame pixel buffer.
-class ScreenCaptureFrameLinux : public ScreenCaptureFrame {
- public:
- explicit ScreenCaptureFrameLinux(const SkISize& window_size);
- virtual ~ScreenCaptureFrameLinux();
-
- private:
- // Allocated pixel buffer.
- scoped_ptr<uint8[]> data_;
-
- DISALLOW_COPY_AND_ASSIGN(ScreenCaptureFrameLinux);
-};
-
// A class to perform video frame capturing for Linux.
class ScreenCapturerLinux : public ScreenCapturer {
public:
@@ -50,9 +35,13 @@ class ScreenCapturerLinux : public ScreenCapturer {
// TODO(ajwong): Do we really want this to be synchronous?
bool Init(bool use_x_damage);
- // Capturer interface.
- virtual void Start(Delegate* delegate) OVERRIDE;
- virtual void CaptureFrame() OVERRIDE;
+ // 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();
@@ -67,17 +56,16 @@ class ScreenCapturerLinux : public ScreenCapturer {
// Capture the cursor image and notify the delegate if it was captured.
void CaptureCursor();
- // Capture screen pixels, and return the data in a new ScreenCaptureData
- // object, to be freed by the caller. 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
+ // 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.
- scoped_refptr<ScreenCaptureData> CaptureScreen();
+ 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 SkISize& root_window_size);
+ 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|.
@@ -89,24 +77,26 @@ class ScreenCapturerLinux : public ScreenCapturer {
void DeinitXlib();
// Capture a rectangle from |x_server_pixel_buffer_|, and copy the data into
- // |capture_data|.
- void CaptureRect(const SkIRect& rect, ScreenCaptureData* capture_data);
+ // |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 SkIRect& rect,
- ScreenCaptureData* capture_data);
+ const webrtc::DesktopRect& rect,
+ webrtc::DesktopFrame* frame);
void SlowBlit(uint8* image,
- const SkIRect& rect,
- ScreenCaptureData* capture_data);
+ 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);
- Delegate* delegate_;
+ Callback* callback_;
+ MouseShapeObserver* mouse_shape_observer_;
// X11 graphics context.
Display* display_;
@@ -114,7 +104,7 @@ class ScreenCapturerLinux : public ScreenCapturer {
Window root_window_;
// Last known dimensions of the root window.
- SkISize root_window_size_;
+ webrtc::DesktopSize root_window_size_;
// XFixes.
bool has_xfixes_;
@@ -140,7 +130,7 @@ class ScreenCapturerLinux : public ScreenCapturer {
// Invalid region from the previous capture. This is used to synchronize the
// current with the last buffer used.
- SkRegion last_invalid_region_;
+ webrtc::DesktopRegion last_invalid_region_;
// |Differ| for use when polling for changes.
scoped_ptr<Differ> differ_;
@@ -148,24 +138,12 @@ class ScreenCapturerLinux : public ScreenCapturer {
DISALLOW_COPY_AND_ASSIGN(ScreenCapturerLinux);
};
-ScreenCaptureFrameLinux::ScreenCaptureFrameLinux(const SkISize& window_size) {
- set_bytes_per_row(window_size.width() * ScreenCaptureData::kBytesPerPixel);
- set_dimensions(window_size);
-
- size_t buffer_size = bytes_per_row() * window_size.height();
- data_.reset(new uint8[buffer_size]);
- set_pixels(data_.get());
-}
-
-ScreenCaptureFrameLinux::~ScreenCaptureFrameLinux() {
-}
-
ScreenCapturerLinux::ScreenCapturerLinux()
- : delegate_(NULL),
+ : callback_(NULL),
+ mouse_shape_observer_(NULL),
display_(NULL),
gc_(NULL),
root_window_(BadValue),
- root_window_size_(SkISize::Make(0, 0)),
has_xfixes_(false),
xfixes_event_base_(-1),
xfixes_error_base_(-1),
@@ -270,50 +248,55 @@ void ScreenCapturerLinux::InitXDamage() {
LOG(INFO) << "Using XDamage extension.";
}
-void ScreenCapturerLinux::Start(Delegate* delegate) {
- DCHECK(delegate_ == NULL);
+void ScreenCapturerLinux::Start(Callback* callback) {
+ DCHECK(!callback_);
+ DCHECK(callback);
- delegate_ = delegate;
+ callback_ = callback;
}
-void ScreenCapturerLinux::CaptureFrame() {
+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 buffer is from an older generation then allocate a new one.
+ // 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_needs_update()) {
- scoped_ptr<ScreenCaptureFrameLinux> buffer(new ScreenCaptureFrameLinux(
- root_window_size_));
- queue_.ReplaceCurrentFrame(buffer.PassAs<ScreenCaptureFrame>());
+ 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.
- const ScreenCaptureFrame* current_buffer = queue_.current_frame();
+ webrtc::DesktopFrame* frame = queue_.current_frame();
if (!use_damage_ && (
!differ_.get() ||
- (differ_->width() != current_buffer->dimensions().width()) ||
- (differ_->height() != current_buffer->dimensions().height()) ||
- (differ_->bytes_per_row() != current_buffer->bytes_per_row()))) {
- differ_.reset(new Differ(current_buffer->dimensions().width(),
- current_buffer->dimensions().height(),
- ScreenCaptureData::kBytesPerPixel,
- current_buffer->bytes_per_row()));
+ (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()));
}
- scoped_refptr<ScreenCaptureData> capture_data(CaptureScreen());
-
- // Swap the current & previous buffers ready for the next capture.
- last_invalid_region_ = capture_data->dirty_region();
+ 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);
+}
- queue_.DoneWithCurrentFrame();
+void ScreenCapturerLinux::SetMouseShapeObserver(
+ MouseShapeObserver* mouse_shape_observer) {
+ DCHECK(!mouse_shape_observer_);
+ DCHECK(mouse_shape_observer);
- capture_data->set_capture_time_ms(
- (base::Time::Now() - capture_start_time).InMillisecondsRoundedUp());
- delegate_->OnCaptureCompleted(capture_data);
+ mouse_shape_observer_ = mouse_shape_observer;
}
void ScreenCapturerLinux::ProcessPendingXEvents() {
@@ -329,7 +312,8 @@ void ScreenCapturerLinux::ProcessPendingXEvents() {
DCHECK(event->level == XDamageReportNonEmpty);
} else if (e.type == ConfigureNotify) {
const XConfigureEvent& event = e.xconfigure;
- ScreenConfigurationChanged(SkISize::Make(event.width, event.height));
+ ScreenConfigurationChanged(
+ webrtc::DesktopSize(event.width, event.height));
} else if (has_xfixes_ &&
e.type == xfixes_event_base_ + XFixesCursorNotify) {
XFixesCursorNotifyEvent* cne;
@@ -352,11 +336,11 @@ void ScreenCapturerLinux::CaptureCursor() {
}
scoped_ptr<MouseCursorShape> cursor(new MouseCursorShape());
- cursor->size.set(img->width, img->height);
- cursor->hotspot.set(img->xhot, img->yhot);
+ 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() *
- ScreenCaptureData::kBytesPerPixel;
+ 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.
@@ -368,17 +352,16 @@ void ScreenCapturerLinux::CaptureCursor() {
}
XFree(img);
- delegate_->OnCursorShapeChanged(cursor.Pass());
+ if (mouse_shape_observer_)
+ mouse_shape_observer_->OnCursorShapeChanged(cursor.Pass());
}
-scoped_refptr<ScreenCaptureData> ScreenCapturerLinux::CaptureScreen() {
- ScreenCaptureFrame* frame = queue_.current_frame();
- scoped_refptr<ScreenCaptureData> capture_data(new ScreenCaptureData(
- frame->pixels(), frame->bytes_per_row(), frame->dimensions()));
+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(capture_data->size());
+ 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
@@ -387,67 +370,67 @@ scoped_refptr<ScreenCaptureData> ScreenCapturerLinux::CaptureScreen() {
if (use_damage_ && queue_.previous_frame())
SynchronizeFrame();
- SkRegion invalid_region;
+ 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 nRects = 0;
+ int rects_num = 0;
XRectangle bounds;
XRectangle* rects = XFixesFetchRegionAndBounds(display_, damage_region_,
- &nRects, &bounds);
- for (int i=0; i<nRects; ++i) {
- invalid_region.op(SkIRect::MakeXYWH(rects[i].x, rects[i].y,
- rects[i].width, rects[i].height),
- SkRegion::kUnion_Op);
+ &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(invalid_region);
+ helper_.InvalidateRegion(*updated_region);
// Capture the damaged portions of the desktop.
- helper_.SwapInvalidRegion(&invalid_region);
+ 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.
- invalid_region.op(SkIRect::MakeSize(root_window_size_),
- SkRegion::kIntersect_Op);
- for (SkRegion::Iterator it(invalid_region); !it.done(); it.next()) {
- CaptureRect(it.rect(), capture_data);
+ 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.
- SkIRect screen_rect = SkIRect::MakeWH(frame->dimensions().width(),
- frame->dimensions().height());
- CaptureRect(screen_rect, capture_data);
+ 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);
- differ_->CalcDirtyRegion(queue_.previous_frame()->pixels(),
- frame->pixels(), &invalid_region);
+ 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.
- invalid_region.op(screen_rect, SkRegion::kUnion_Op);
+ updated_region->SetRect(screen_rect);
}
}
- capture_data->mutable_dirty_region() = invalid_region;
- return capture_data;
+ return frame;
}
void ScreenCapturerLinux::ScreenConfigurationChanged(
- const SkISize& root_window_size) {
+ const webrtc::DesktopSize& root_window_size) {
root_window_size_ = root_window_size;
// Make sure the frame buffers will be reallocated.
- queue_.SetAllFramesNeedUpdate();
+ queue_.Reset();
helper_.ClearInvalidRegion();
x_server_pixel_buffer_.Init(display_, root_window_size_);
@@ -464,18 +447,18 @@ void ScreenCapturerLinux::SynchronizeFrame() {
// http://crbug.com/92354
DCHECK(queue_.previous_frame());
- ScreenCaptureFrame* current = queue_.current_frame();
- ScreenCaptureFrame* last = queue_.previous_frame();
+ webrtc::DesktopFrame* current = queue_.current_frame();
+ webrtc::DesktopFrame* last = queue_.previous_frame();
DCHECK_NE(current, last);
- for (SkRegion::Iterator it(last_invalid_region_); !it.done(); it.next()) {
- const SkIRect& r = it.rect();
- int offset = r.fTop * current->bytes_per_row() +
- r.fLeft * ScreenCaptureData::kBytesPerPixel;
+ 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->pixels() + offset, last->pixels() + offset,
- r.width() * ScreenCaptureData::kBytesPerPixel);
- offset += current->dimensions().width() *
- ScreenCaptureData::kBytesPerPixel;
+ memcpy(current->data() + offset, last->data() + offset,
+ r.width() * webrtc::DesktopFrame::kBytesPerPixel);
+ offset += current->size().width() * webrtc::DesktopFrame::kBytesPerPixel;
}
}
}
@@ -500,8 +483,8 @@ void ScreenCapturerLinux::DeinitXlib() {
}
}
-void ScreenCapturerLinux::CaptureRect(const SkIRect& rect,
- ScreenCaptureData* capture_data) {
+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) &&
@@ -510,35 +493,37 @@ void ScreenCapturerLinux::CaptureRect(const SkIRect& rect,
x_server_pixel_buffer_.GetGreenMask() == 0xff00 &&
x_server_pixel_buffer_.GetBlueMask() == 0xff) {
DVLOG(3) << "Fast blitting";
- FastBlit(image, rect, capture_data);
+ FastBlit(image, rect, frame);
} else {
DVLOG(3) << "Slow blitting";
- SlowBlit(image, rect, capture_data);
+ SlowBlit(image, rect, frame);
}
}
-void ScreenCapturerLinux::FastBlit(uint8* image, const SkIRect& rect,
- ScreenCaptureData* capture_data) {
+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.fLeft, dst_y = rect.fTop;
+ int dst_x = rect.left(), dst_y = rect.top();
- uint8* dst_pos = capture_data->data() + capture_data->stride() * dst_y;
- dst_pos += dst_x * ScreenCaptureData::kBytesPerPixel;
+ 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() * ScreenCaptureData::kBytesPerPixel;
+ 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 += capture_data->stride();
+ dst_pos += frame->stride();
}
}
-void ScreenCapturerLinux::SlowBlit(uint8* image, const SkIRect& rect,
- ScreenCaptureData* capture_data) {
+void ScreenCapturerLinux::SlowBlit(uint8* image,
+ const webrtc::DesktopRect& rect,
+ webrtc::DesktopFrame* frame) {
int src_stride = x_server_pixel_buffer_.GetStride();
- int dst_x = rect.fLeft, dst_y = rect.fTop;
+ int dst_x = rect.left(), dst_y = rect.top();
int width = rect.width(), height = rect.height();
uint32 red_mask = x_server_pixel_buffer_.GetRedMask();
@@ -551,9 +536,9 @@ void ScreenCapturerLinux::SlowBlit(uint8* image, const SkIRect& rect,
unsigned int bits_per_pixel = x_server_pixel_buffer_.GetBitsPerPixel();
- uint8* dst_pos = capture_data->data() + capture_data->stride() * dst_y;
+ uint8* dst_pos = frame->data() + frame->stride() * dst_y;
uint8* src_pos = image;
- dst_pos += dst_x * ScreenCaptureData::kBytesPerPixel;
+ 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++) {
@@ -577,7 +562,7 @@ void ScreenCapturerLinux::SlowBlit(uint8* image, const SkIRect& rect,
dst_pos_32[x] = ((r >> 8) & 0xff0000) | ((g >> 16) & 0xff00) |
((b >> 24) & 0xff);
}
- dst_pos += capture_data->stride();
+ dst_pos += frame->stride();
src_pos += src_stride;
}
}
@@ -609,15 +594,6 @@ uint32 ScreenCapturerLinux::GetRgbShift(uint32 mask) {
} // namespace
-scoped_refptr<SharedBuffer> ScreenCapturer::Delegate::CreateSharedBuffer(
- uint32 size) {
- return scoped_refptr<SharedBuffer>();
-}
-
-void ScreenCapturer::Delegate::ReleaseSharedBuffer(
- scoped_refptr<SharedBuffer> buffer) {
-}
-
// static
scoped_ptr<ScreenCapturer> ScreenCapturer::Create() {
scoped_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux());
« no previous file with comments | « media/video/capture/screen/screen_capturer_win.cc ('k') | media/video/capture/screen/shared_buffer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698