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