diff options
author | dmaclach@chromium.org <dmaclach@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-01 15:02:53 +0000 |
---|---|---|
committer | dmaclach@chromium.org <dmaclach@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-01 15:02:53 +0000 |
commit | 804c99625cc375da683a6c1a681178b0014e02fe (patch) | |
tree | 444c6deffd05f7744f0d2b50077aeabde0cc7170 /remoting/host/capturer_mac.cc | |
parent | 9da1cedf45ee5bb54cc5558ca044dc24b999b8d9 (diff) | |
download | chromium_src-804c99625cc375da683a6c1a681178b0014e02fe.zip chromium_src-804c99625cc375da683a6c1a681178b0014e02fe.tar.gz chromium_src-804c99625cc375da683a6c1a681178b0014e02fe.tar.bz2 |
Revamp capturer to clean up the interface, and to keep data as atomic as possible when making calls across threads.
TEST=build remoting
BUG=none
Review URL: http://codereview.chromium.org/2805025
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@51363 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting/host/capturer_mac.cc')
-rw-r--r-- | remoting/host/capturer_mac.cc | 154 |
1 files changed, 130 insertions, 24 deletions
diff --git a/remoting/host/capturer_mac.cc b/remoting/host/capturer_mac.cc index 08f39c7..52d58c3 100644 --- a/remoting/host/capturer_mac.cc +++ b/remoting/host/capturer_mac.cc @@ -4,51 +4,157 @@ #include "remoting/host/capturer_mac.h" +#include <stddef.h> + +#include <OpenGL/CGLMacro.h> + namespace remoting { -// TODO(dmaclach): Implement this class. -CapturerMac::CapturerMac() { +CapturerMac::CapturerMac() : cgl_context_(NULL) { + // TODO(dmaclach): move this initialization out into session_manager, + // or at least have session_manager call into here to initialize it. + CGError err + = CGRegisterScreenRefreshCallback(CapturerMac::ScreenRefreshCallback, + this); + DCHECK_EQ(err, kCGErrorSuccess); + err = CGScreenRegisterMoveCallback(CapturerMac::ScreenUpdateMoveCallback, + this); + DCHECK_EQ(err, kCGErrorSuccess); + err = CGDisplayRegisterReconfigurationCallback( + CapturerMac::DisplaysReconfiguredCallback, this); + DCHECK_EQ(err, kCGErrorSuccess); } CapturerMac::~CapturerMac() { + ReleaseBuffers(); + CGUnregisterScreenRefreshCallback(CapturerMac::ScreenRefreshCallback, this); + CGScreenUnregisterMoveCallback(CapturerMac::ScreenUpdateMoveCallback, this); + CGDisplayRemoveReconfigurationCallback( + CapturerMac::DisplaysReconfiguredCallback, this); } -void CapturerMac::CaptureFullScreen(Task* done_task) { - dirty_rects_.clear(); +void CapturerMac::ReleaseBuffers() { + if (cgl_context_) { + CGLDestroyContext(cgl_context_); + cgl_context_ = NULL; + } +} - CaptureImage(); - dirty_rects_.push_back(gfx::Rect(width_, height_)); +void CapturerMac::ScreenConfigurationChanged() { + ReleaseBuffers(); + CGDirectDisplayID mainDevice = CGMainDisplayID(); + + width_ = CGDisplayPixelsWide(mainDevice); + height_ = CGDisplayPixelsHigh(mainDevice); + bytes_per_row_ = width_ * sizeof(uint32_t); + pixel_format_ = PixelFormatRgb32; + size_t buffer_size = height() * bytes_per_row_; + for (int i = 0; i < kNumBuffers; ++i) { + buffers_[i].reset(new uint8[buffer_size]); + } + CGLPixelFormatAttribute attributes[] = { + kCGLPFAFullScreen, + kCGLPFADisplayMask, + (CGLPixelFormatAttribute)CGDisplayIDToOpenGLDisplayMask(mainDevice), + (CGLPixelFormatAttribute)0 + }; + CGLPixelFormatObj pixel_format = NULL; + GLint matching_pixel_format_count = 0; + CGLError err = CGLChoosePixelFormat(attributes, + &pixel_format, + &matching_pixel_format_count); + DCHECK_EQ(err, kCGLNoError); + err = CGLCreateContext(pixel_format, NULL, &cgl_context_); + DCHECK_EQ(err, kCGLNoError); + CGLDestroyPixelFormat(pixel_format); + CGLSetFullScreen(cgl_context_); + CGLSetCurrentContext(cgl_context_); +} - FinishCapture(done_task); +void CapturerMac::CaptureRects(const RectVector& rects, + CaptureCompletedCallback* callback) { + // TODO(dmaclach): something smarter here in the future. + gfx::Rect dirtyRect; + for (RectVector::const_iterator i = rects.begin(); i < rects.end(); ++i) { + dirtyRect = dirtyRect.Union(*i); + } + + CGLContextObj CGL_MACRO_CONTEXT = cgl_context_; + glReadBuffer(GL_FRONT); + glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); + + glPixelStorei(GL_PACK_ALIGNMENT, 4); // Force 4-byte alignment. + glPixelStorei(GL_PACK_ROW_LENGTH, 0); + glPixelStorei(GL_PACK_SKIP_ROWS, 0); + glPixelStorei(GL_PACK_SKIP_PIXELS, 0); + + // Read a block of pixels from the frame buffer. + glReadPixels(0, 0, width(), height(), GL_BGRA, GL_UNSIGNED_BYTE, + buffers_[current_buffer_].get()); + glPopClientAttrib(); + + Capturer::DataPlanes planes; + planes.data[0] = buffers_[current_buffer_].get(); + planes.strides[0] = bytes_per_row_; + + scoped_refptr<CaptureData> data(new CaptureData(planes, + width(), + height(), + pixel_format())); + data->mutable_dirty_rects().assign(1, dirtyRect); + FinishCapture(data, callback); } -void CapturerMac::CaptureDirtyRects(Task* done_task) { - dirty_rects_.clear(); - CaptureImage(); - // TODO(garykac): Diff old/new images and generate |dirty_rects_|. - // Currently, this just marks the entire screen as dirty. - dirty_rects_.push_back(gfx::Rect(width_, height_)); +void CapturerMac::ScreenRefresh(CGRectCount count, const CGRect *rect_array) { + RectVector rects; + for (CGRectCount i = 0; i < count; ++i) { + CGRect rect = rect_array[i]; + rect.origin.y = height() - rect.size.height; + rects.push_back(gfx::Rect(rect)); + } + InvalidateRects(rects); - FinishCapture(done_task); } -void CapturerMac::CaptureRect(const gfx::Rect& rect, Task* done_task) { - dirty_rects_.clear(); - - CaptureImage(); - dirty_rects_.push_back(rect); - - FinishCapture(done_task); +void CapturerMac::ScreenUpdateMove(CGScreenUpdateMoveDelta delta, + size_t count, + const CGRect *rect_array) { + RectVector rects; + for (CGRectCount i = 0; i < count; ++i) { + CGRect rect = rect_array[i]; + rect.origin.y = height() - rect.size.height; + rects.push_back(gfx::Rect(rect)); + rect = CGRectOffset(rect, delta.dX, delta.dY); + rects.push_back(gfx::Rect(rect)); + } + InvalidateRects(rects); } -void CapturerMac::GetData(const uint8* planes[]) const { +void CapturerMac::ScreenRefreshCallback(CGRectCount count, + const CGRect *rect_array, + void *user_parameter) { + CapturerMac *capturer = reinterpret_cast<CapturerMac *>(user_parameter); + capturer->ScreenRefresh(count, rect_array); } -void CapturerMac::GetDataStride(int strides[]) const { +void CapturerMac::ScreenUpdateMoveCallback(CGScreenUpdateMoveDelta delta, + size_t count, + const CGRect *rect_array, + void *user_parameter) { + CapturerMac *capturer = reinterpret_cast<CapturerMac *>(user_parameter); + capturer->ScreenUpdateMove(delta, count, rect_array); } -void CapturerMac::CaptureImage() { +void CapturerMac::DisplaysReconfiguredCallback( + CGDirectDisplayID display, + CGDisplayChangeSummaryFlags flags, + void *user_parameter) { + if ((display == CGMainDisplayID()) && + !(flags & kCGDisplayBeginConfigurationFlag)) { + CapturerMac *capturer = reinterpret_cast<CapturerMac *>(user_parameter); + capturer->ScreenConfigurationChanged(); + } } } // namespace remoting |