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()); |