1e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org/* 2e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org * 4e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org * Use of this source code is governed by a BSD-style license 5e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org * that can be found in the LICENSE file in the root of the source 6e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org * tree. An additional intellectual property rights grant can be found 7e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org * in the file PATENTS. All contributing project authors may 8e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org * be found in the AUTHORS file in the root of the source tree. 9e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org */ 10e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org 11e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org#include "webrtc/modules/desktop_capture/desktop_and_cursor_composer.h" 12e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org 13e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org#include <string.h> 14e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org 15e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org#include "webrtc/modules/desktop_capture/desktop_capturer.h" 16e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org#include "webrtc/modules/desktop_capture/desktop_frame.h" 17e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org#include "webrtc/modules/desktop_capture/mouse_cursor.h" 18e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org 19e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.orgnamespace webrtc { 20e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org 21e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.orgnamespace { 22e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org 23e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org// Helper function that blends one image into another. Source image must be 24e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org// pre-multiplied with the alpha channel. Destination is assumed to be opaque. 25e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.orgvoid AlphaBlend(uint8_t* dest, int dest_stride, 26e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org const uint8_t* src, int src_stride, 27e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org const DesktopSize& size) { 28e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org for (int y = 0; y < size.height(); ++y) { 29e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org for (int x = 0; x < size.width(); ++x) { 30e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org uint32_t base_alpha = 255 - src[x * DesktopFrame::kBytesPerPixel + 3]; 31e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org if (base_alpha == 255) { 32e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org continue; 33e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org } else if (base_alpha == 0) { 34e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org memcpy(dest + x * DesktopFrame::kBytesPerPixel, 35e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org src + x * DesktopFrame::kBytesPerPixel, 36e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org DesktopFrame::kBytesPerPixel); 37e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org } else { 38e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org dest[x * DesktopFrame::kBytesPerPixel] = 39e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org dest[x * DesktopFrame::kBytesPerPixel] * base_alpha / 255 + 40e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org src[x * DesktopFrame::kBytesPerPixel]; 41e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org dest[x * DesktopFrame::kBytesPerPixel + 1] = 42e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org dest[x * DesktopFrame::kBytesPerPixel + 1] * base_alpha / 255 + 43e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org src[x * DesktopFrame::kBytesPerPixel + 1]; 44e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org dest[x * DesktopFrame::kBytesPerPixel + 2] = 45e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org dest[x * DesktopFrame::kBytesPerPixel + 2] * base_alpha / 255 + 46e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org src[x * DesktopFrame::kBytesPerPixel + 2]; 47e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org } 48e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org } 49e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org src += src_stride; 50e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org dest += dest_stride; 51e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org } 52e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org} 53e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org 545d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org// DesktopFrame wrapper that draws mouse on a frame and restores original 555d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org// content before releasing the underlying frame. 565d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.orgclass DesktopFrameWithCursor : public DesktopFrame { 575d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org public: 585d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org // Takes ownership of |frame|. 595d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org DesktopFrameWithCursor(DesktopFrame* frame, 605d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org const MouseCursor& cursor, 615d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org const DesktopVector& position); 625d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org virtual ~DesktopFrameWithCursor(); 635d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org 645d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org private: 6500b8f6b3643332cce1ee711715f7fbb824d793cakwiberg@webrtc.org rtc::scoped_ptr<DesktopFrame> original_frame_; 665d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org 675d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org DesktopVector restore_position_; 6800b8f6b3643332cce1ee711715f7fbb824d793cakwiberg@webrtc.org rtc::scoped_ptr<DesktopFrame> restore_frame_; 695d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org 703c089d751ede283e21e186885eaf705c3257ccd2henrikg RTC_DISALLOW_COPY_AND_ASSIGN(DesktopFrameWithCursor); 715d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org}; 725d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org 735d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.orgDesktopFrameWithCursor::DesktopFrameWithCursor(DesktopFrame* frame, 745d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org const MouseCursor& cursor, 755d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org const DesktopVector& position) 765d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org : DesktopFrame(frame->size(), frame->stride(), 775d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org frame->data(), frame->shared_memory()), 785d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org original_frame_(frame) { 795d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org set_dpi(frame->dpi()); 805d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org set_capture_time_ms(frame->capture_time_ms()); 815d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org mutable_updated_region()->Swap(frame->mutable_updated_region()); 825d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org 835d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org DesktopVector image_pos = position.subtract(cursor.hotspot()); 848ae72560dd67a59922a49bfb7808f2290c07991dsergeyu@chromium.org DesktopRect target_rect = DesktopRect::MakeSize(cursor.image()->size()); 855d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org target_rect.Translate(image_pos); 865d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org DesktopVector target_origin = target_rect.top_left(); 875d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org target_rect.IntersectWith(DesktopRect::MakeSize(size())); 885d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org 895d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org if (target_rect.is_empty()) 905d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org return; 915d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org 925d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org // Copy original screen content under cursor to |restore_frame_|. 935d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org restore_position_ = target_rect.top_left(); 945d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org restore_frame_.reset(new BasicDesktopFrame(target_rect.size())); 955d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org restore_frame_->CopyPixelsFrom(*this, target_rect.top_left(), 965d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org DesktopRect::MakeSize(restore_frame_->size())); 975d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org 985d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org // Blit the cursor. 995d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org uint8_t* target_rect_data = reinterpret_cast<uint8_t*>(data()) + 1005d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org target_rect.top() * stride() + 1015d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org target_rect.left() * DesktopFrame::kBytesPerPixel; 1025d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org DesktopVector origin_shift = target_rect.top_left().subtract(target_origin); 1035d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org AlphaBlend(target_rect_data, stride(), 1048ae72560dd67a59922a49bfb7808f2290c07991dsergeyu@chromium.org cursor.image()->data() + 1058ae72560dd67a59922a49bfb7808f2290c07991dsergeyu@chromium.org origin_shift.y() * cursor.image()->stride() + 1065d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org origin_shift.x() * DesktopFrame::kBytesPerPixel, 1078ae72560dd67a59922a49bfb7808f2290c07991dsergeyu@chromium.org cursor.image()->stride(), 1085d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org target_rect.size()); 1095d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org} 1105d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org 1115d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.orgDesktopFrameWithCursor::~DesktopFrameWithCursor() { 1125d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org // Restore original content of the frame. 1135d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org if (restore_frame_.get()) { 1145d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org DesktopRect target_rect = DesktopRect::MakeSize(restore_frame_->size()); 1155d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org target_rect.Translate(restore_position_); 1165d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org CopyPixelsFrom(restore_frame_->data(), restore_frame_->stride(), 1175d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org target_rect); 1185d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org } 1195d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org} 1205d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org 121e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org} // namespace 122e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org 123e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.orgDesktopAndCursorComposer::DesktopAndCursorComposer( 124e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org DesktopCapturer* desktop_capturer, 125e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org MouseCursorMonitor* mouse_monitor) 126e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org : desktop_capturer_(desktop_capturer), 127e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org mouse_monitor_(mouse_monitor) { 128e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org} 129e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org 130e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.orgDesktopAndCursorComposer::~DesktopAndCursorComposer() {} 131e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org 132e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.orgvoid DesktopAndCursorComposer::Start(DesktopCapturer::Callback* callback) { 133e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org callback_ = callback; 134e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org if (mouse_monitor_.get()) 135e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org mouse_monitor_->Init(this, MouseCursorMonitor::SHAPE_AND_POSITION); 136e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org desktop_capturer_->Start(this); 137e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org} 138e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org 139e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.orgvoid DesktopAndCursorComposer::Capture(const DesktopRegion& region) { 140e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org if (mouse_monitor_.get()) 141e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org mouse_monitor_->Capture(); 142e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org desktop_capturer_->Capture(region); 143e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org} 144e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org 1457ee0c16eddb5a9a9de8522784f914f0d46a7ea64jiayl@webrtc.orgvoid DesktopAndCursorComposer::SetExcludedWindow(WindowId window) { 1467ee0c16eddb5a9a9de8522784f914f0d46a7ea64jiayl@webrtc.org desktop_capturer_->SetExcludedWindow(window); 1477ee0c16eddb5a9a9de8522784f914f0d46a7ea64jiayl@webrtc.org} 1487ee0c16eddb5a9a9de8522784f914f0d46a7ea64jiayl@webrtc.org 149e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.orgSharedMemory* DesktopAndCursorComposer::CreateSharedMemory(size_t size) { 150e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org return callback_->CreateSharedMemory(size); 151e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org} 152e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org 153e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.orgvoid DesktopAndCursorComposer::OnCaptureCompleted(DesktopFrame* frame) { 154e3841041665dd55ddeaeb3b0dc415512fc414737sergeyu@chromium.org if (frame && cursor_.get() && cursor_state_ == MouseCursorMonitor::INSIDE) { 1555d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org DesktopFrameWithCursor* frame_with_cursor = 1565d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org new DesktopFrameWithCursor(frame, *cursor_, cursor_position_); 1575d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org frame = frame_with_cursor; 158e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org } 159e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org 160e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org callback_->OnCaptureCompleted(frame); 161e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org} 162e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org 163e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.orgvoid DesktopAndCursorComposer::OnMouseCursor(MouseCursor* cursor) { 164e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org cursor_.reset(cursor); 165e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org} 166e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org 167e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.orgvoid DesktopAndCursorComposer::OnMouseCursorPosition( 168e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org MouseCursorMonitor::CursorState state, 169e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org const DesktopVector& position) { 170e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org cursor_state_ = state; 171e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org cursor_position_ = position; 172e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org} 173e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org 174e6e749da3840e6855bd6fc13172b6589bdc3a973sergeyu@chromium.org} // namespace webrtc 175