1/* 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11#include "webrtc/modules/desktop_capture/desktop_and_cursor_composer.h" 12 13#include <string.h> 14 15#include "webrtc/modules/desktop_capture/desktop_capturer.h" 16#include "webrtc/modules/desktop_capture/desktop_frame.h" 17#include "webrtc/modules/desktop_capture/mouse_cursor.h" 18 19namespace webrtc { 20 21namespace { 22 23// Helper function that blends one image into another. Source image must be 24// pre-multiplied with the alpha channel. Destination is assumed to be opaque. 25void AlphaBlend(uint8_t* dest, int dest_stride, 26 const uint8_t* src, int src_stride, 27 const DesktopSize& size) { 28 for (int y = 0; y < size.height(); ++y) { 29 for (int x = 0; x < size.width(); ++x) { 30 uint32_t base_alpha = 255 - src[x * DesktopFrame::kBytesPerPixel + 3]; 31 if (base_alpha == 255) { 32 continue; 33 } else if (base_alpha == 0) { 34 memcpy(dest + x * DesktopFrame::kBytesPerPixel, 35 src + x * DesktopFrame::kBytesPerPixel, 36 DesktopFrame::kBytesPerPixel); 37 } else { 38 dest[x * DesktopFrame::kBytesPerPixel] = 39 dest[x * DesktopFrame::kBytesPerPixel] * base_alpha / 255 + 40 src[x * DesktopFrame::kBytesPerPixel]; 41 dest[x * DesktopFrame::kBytesPerPixel + 1] = 42 dest[x * DesktopFrame::kBytesPerPixel + 1] * base_alpha / 255 + 43 src[x * DesktopFrame::kBytesPerPixel + 1]; 44 dest[x * DesktopFrame::kBytesPerPixel + 2] = 45 dest[x * DesktopFrame::kBytesPerPixel + 2] * base_alpha / 255 + 46 src[x * DesktopFrame::kBytesPerPixel + 2]; 47 } 48 } 49 src += src_stride; 50 dest += dest_stride; 51 } 52} 53 54// DesktopFrame wrapper that draws mouse on a frame and restores original 55// content before releasing the underlying frame. 56class DesktopFrameWithCursor : public DesktopFrame { 57 public: 58 // Takes ownership of |frame|. 59 DesktopFrameWithCursor(DesktopFrame* frame, 60 const MouseCursor& cursor, 61 const DesktopVector& position); 62 virtual ~DesktopFrameWithCursor(); 63 64 private: 65 scoped_ptr<DesktopFrame> original_frame_; 66 67 DesktopVector restore_position_; 68 scoped_ptr<DesktopFrame> restore_frame_; 69 70 DISALLOW_COPY_AND_ASSIGN(DesktopFrameWithCursor); 71}; 72 73DesktopFrameWithCursor::DesktopFrameWithCursor(DesktopFrame* frame, 74 const MouseCursor& cursor, 75 const DesktopVector& position) 76 : DesktopFrame(frame->size(), frame->stride(), 77 frame->data(), frame->shared_memory()), 78 original_frame_(frame) { 79 set_dpi(frame->dpi()); 80 set_capture_time_ms(frame->capture_time_ms()); 81 mutable_updated_region()->Swap(frame->mutable_updated_region()); 82 83 DesktopVector image_pos = position.subtract(cursor.hotspot()); 84 DesktopRect target_rect = DesktopRect::MakeSize(cursor.image()->size()); 85 target_rect.Translate(image_pos); 86 DesktopVector target_origin = target_rect.top_left(); 87 target_rect.IntersectWith(DesktopRect::MakeSize(size())); 88 89 if (target_rect.is_empty()) 90 return; 91 92 // Copy original screen content under cursor to |restore_frame_|. 93 restore_position_ = target_rect.top_left(); 94 restore_frame_.reset(new BasicDesktopFrame(target_rect.size())); 95 restore_frame_->CopyPixelsFrom(*this, target_rect.top_left(), 96 DesktopRect::MakeSize(restore_frame_->size())); 97 98 // Blit the cursor. 99 uint8_t* target_rect_data = reinterpret_cast<uint8_t*>(data()) + 100 target_rect.top() * stride() + 101 target_rect.left() * DesktopFrame::kBytesPerPixel; 102 DesktopVector origin_shift = target_rect.top_left().subtract(target_origin); 103 AlphaBlend(target_rect_data, stride(), 104 cursor.image()->data() + 105 origin_shift.y() * cursor.image()->stride() + 106 origin_shift.x() * DesktopFrame::kBytesPerPixel, 107 cursor.image()->stride(), 108 target_rect.size()); 109} 110 111DesktopFrameWithCursor::~DesktopFrameWithCursor() { 112 // Restore original content of the frame. 113 if (restore_frame_.get()) { 114 DesktopRect target_rect = DesktopRect::MakeSize(restore_frame_->size()); 115 target_rect.Translate(restore_position_); 116 CopyPixelsFrom(restore_frame_->data(), restore_frame_->stride(), 117 target_rect); 118 } 119} 120 121} // namespace 122 123DesktopAndCursorComposer::DesktopAndCursorComposer( 124 DesktopCapturer* desktop_capturer, 125 MouseCursorMonitor* mouse_monitor) 126 : desktop_capturer_(desktop_capturer), 127 mouse_monitor_(mouse_monitor) { 128} 129 130DesktopAndCursorComposer::~DesktopAndCursorComposer() {} 131 132void DesktopAndCursorComposer::Start(DesktopCapturer::Callback* callback) { 133 callback_ = callback; 134 if (mouse_monitor_.get()) 135 mouse_monitor_->Init(this, MouseCursorMonitor::SHAPE_AND_POSITION); 136 desktop_capturer_->Start(this); 137} 138 139void DesktopAndCursorComposer::Capture(const DesktopRegion& region) { 140 if (mouse_monitor_.get()) 141 mouse_monitor_->Capture(); 142 desktop_capturer_->Capture(region); 143} 144 145void DesktopAndCursorComposer::SetExcludedWindow(WindowId window) { 146 desktop_capturer_->SetExcludedWindow(window); 147} 148 149SharedMemory* DesktopAndCursorComposer::CreateSharedMemory(size_t size) { 150 return callback_->CreateSharedMemory(size); 151} 152 153void DesktopAndCursorComposer::OnCaptureCompleted(DesktopFrame* frame) { 154 if (frame && cursor_.get() && cursor_state_ == MouseCursorMonitor::INSIDE) { 155 DesktopFrameWithCursor* frame_with_cursor = 156 new DesktopFrameWithCursor(frame, *cursor_, cursor_position_); 157 frame = frame_with_cursor; 158 } 159 160 callback_->OnCaptureCompleted(frame); 161} 162 163void DesktopAndCursorComposer::OnMouseCursor(MouseCursor* cursor) { 164 cursor_.reset(cursor); 165} 166 167void DesktopAndCursorComposer::OnMouseCursorPosition( 168 MouseCursorMonitor::CursorState state, 169 const DesktopVector& position) { 170 cursor_state_ = state; 171 cursor_position_ = position; 172} 173 174} // namespace webrtc 175