16b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org/*
26b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
36b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org *
46b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org *  Use of this source code is governed by a BSD-style license
56b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org *  that can be found in the LICENSE file in the root of the source
66b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org *  tree. An additional intellectual property rights grant can be found
76b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org *  in the file PATENTS.  All contributing project authors may
86b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
96b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org */
106b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
116b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org#include "webrtc/modules/desktop_capture/win/screen_capturer_win_magnifier.h"
126b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
13e38123c801909a3e357f317a6811748aaf81c0ebhenrike@webrtc.org#include <assert.h>
14e38123c801909a3e357f317a6811748aaf81c0ebhenrike@webrtc.org
156b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org#include "webrtc/modules/desktop_capture/desktop_capture_options.h"
166b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org#include "webrtc/modules/desktop_capture/desktop_frame.h"
176b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org#include "webrtc/modules/desktop_capture/desktop_frame_win.h"
186b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org#include "webrtc/modules/desktop_capture/desktop_region.h"
196b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org#include "webrtc/modules/desktop_capture/differ.h"
206b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org#include "webrtc/modules/desktop_capture/mouse_cursor.h"
216b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org#include "webrtc/modules/desktop_capture/win/cursor.h"
226b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org#include "webrtc/modules/desktop_capture/win/desktop.h"
236b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org#include "webrtc/modules/desktop_capture/win/screen_capture_utils.h"
246b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org#include "webrtc/system_wrappers/interface/logging.h"
256b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org#include "webrtc/system_wrappers/interface/tick_util.h"
266b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
276b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.orgnamespace webrtc {
286b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
296b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org// kMagnifierWindowClass has to be "Magnifier" according to the Magnification
306b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org// API. The other strings can be anything.
316b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.orgstatic LPCTSTR kMagnifierHostClass = L"ScreenCapturerWinMagnifierHost";
326b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.orgstatic LPCTSTR kHostWindowName = L"MagnifierHost";
336b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.orgstatic LPCTSTR kMagnifierWindowClass = L"Magnifier";
346b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.orgstatic LPCTSTR kMagnifierWindowName = L"MagnifierWindow";
356b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
366b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.orgAtomic32 ScreenCapturerWinMagnifier::tls_index_(TLS_OUT_OF_INDEXES);
376b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
386b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.orgScreenCapturerWinMagnifier::ScreenCapturerWinMagnifier(
396b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    scoped_ptr<ScreenCapturer> fallback_capturer)
406b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    : fallback_capturer_(fallback_capturer.Pass()),
416b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      fallback_capturer_started_(false),
426b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      callback_(NULL),
436b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      current_screen_id_(kFullDesktopScreenId),
446b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      excluded_window_(NULL),
456b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      set_thread_execution_state_failed_(false),
466b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      desktop_dc_(NULL),
476b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      mag_lib_handle_(NULL),
486b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      mag_initialize_func_(NULL),
496b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      mag_uninitialize_func_(NULL),
506b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      set_window_source_func_(NULL),
516b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      set_window_filter_list_func_(NULL),
526b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      set_image_scaling_callback_func_(NULL),
536b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      host_window_(NULL),
546b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      magnifier_window_(NULL),
556b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      magnifier_initialized_(false),
566b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      magnifier_capture_succeeded_(true) {
576b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org}
586b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
596b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.orgScreenCapturerWinMagnifier::~ScreenCapturerWinMagnifier() {
606b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  // DestroyWindow must be called before MagUninitialize. magnifier_window_ is
616b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  // destroyed automatically when host_window_ is destroyed.
626b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  if (host_window_)
636b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    DestroyWindow(host_window_);
646b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
656b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  if (magnifier_initialized_)
666b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    mag_uninitialize_func_();
676b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
686b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  if (mag_lib_handle_)
696b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    FreeLibrary(mag_lib_handle_);
706b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
716b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  if (desktop_dc_)
726b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    ReleaseDC(NULL, desktop_dc_);
736b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org}
746b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
756b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.orgvoid ScreenCapturerWinMagnifier::Start(Callback* callback) {
766b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  assert(!callback_);
776b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  assert(callback);
786b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  callback_ = callback;
796b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
806b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  InitializeMagnifier();
816b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org}
826b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
836b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.orgvoid ScreenCapturerWinMagnifier::Capture(const DesktopRegion& region) {
846b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  TickTime capture_start_time = TickTime::Now();
856b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
866b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  queue_.MoveToNextFrame();
876b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
886b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  // Request that the system not power-down the system, or the display hardware.
896b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  if (!SetThreadExecutionState(ES_DISPLAY_REQUIRED | ES_SYSTEM_REQUIRED)) {
906b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    if (!set_thread_execution_state_failed_) {
916b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      set_thread_execution_state_failed_ = true;
926b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      LOG_F(LS_WARNING) << "Failed to make system & display power assertion: "
936b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                        << GetLastError();
946b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    }
956b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  }
966b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  // Switch to the desktop receiving user input if different from the current
976b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  // one.
986b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  scoped_ptr<Desktop> input_desktop(Desktop::GetInputDesktop());
996b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  if (input_desktop.get() != NULL && !desktop_.IsSame(*input_desktop)) {
1006b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    // Release GDI resources otherwise SetThreadDesktop will fail.
1016b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    if (desktop_dc_) {
1026b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      ReleaseDC(NULL, desktop_dc_);
1036b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      desktop_dc_ = NULL;
1046b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    }
1056b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    // If SetThreadDesktop() fails, the thread is still assigned a desktop.
1066b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    // So we can continue capture screen bits, just from the wrong desktop.
1076b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    desktop_.SetThreadDesktop(input_desktop.release());
1086b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  }
1096b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
1106b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  bool succeeded = false;
1116b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
1126b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  // Do not try to use the magnfiier if it's capturing non-primary screen, or it
1136b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  // failed before.
1146b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  if (magnifier_initialized_ && IsCapturingPrimaryScreenOnly() &&
1156b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      magnifier_capture_succeeded_) {
1166b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    DesktopRect rect = GetScreenRect(current_screen_id_, current_device_key_);
1176b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    CreateCurrentFrameIfNecessary(rect.size());
1186b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
1196b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    // CaptureImage may fail in some situations, e.g. windows8 metro mode.
1206b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    succeeded = CaptureImage(rect);
1216b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  }
1226b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
1236b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  // Defer to the fallback capturer if magnifier capturer did not work.
1246b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  if (!succeeded) {
1256b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    LOG_F(LS_WARNING) << "Switching to the fallback screen capturer.";
1266b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    StartFallbackCapturer();
1276b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    fallback_capturer_->Capture(region);
1286b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    return;
1296b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  }
1306b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
1316b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  const DesktopFrame* current_frame = queue_.current_frame();
1326b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  const DesktopFrame* last_frame = queue_.previous_frame();
1336b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  if (last_frame && last_frame->size().equals(current_frame->size())) {
1346b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    // Make sure the differencer is set up correctly for these previous and
1356b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    // current screens.
1366b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    if (!differ_.get() || (differ_->width() != current_frame->size().width()) ||
1376b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org        (differ_->height() != current_frame->size().height()) ||
1386b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org        (differ_->bytes_per_row() != current_frame->stride())) {
1396b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      differ_.reset(new Differ(current_frame->size().width(),
1406b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                               current_frame->size().height(),
1416b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                               DesktopFrame::kBytesPerPixel,
1426b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                               current_frame->stride()));
1436b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    }
1446b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
1456b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    // Calculate difference between the two last captured frames.
1466b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    DesktopRegion region;
1476b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    differ_->CalcDirtyRegion(
1486b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org        last_frame->data(), current_frame->data(), &region);
1496b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    helper_.InvalidateRegion(region);
1506b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  } else {
1516b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    // No previous frame is available, or the screen is resized. Invalidate the
1526b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    // whole screen.
1536b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    helper_.InvalidateScreen(current_frame->size());
1546b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  }
1556b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
1566b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  helper_.set_size_most_recent(current_frame->size());
1576b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
1586b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  // Emit the current frame.
1596b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  DesktopFrame* frame = queue_.current_frame()->Share();
1606b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  frame->set_dpi(DesktopVector(GetDeviceCaps(desktop_dc_, LOGPIXELSX),
1616b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                               GetDeviceCaps(desktop_dc_, LOGPIXELSY)));
1626b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  frame->mutable_updated_region()->Clear();
1636b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  helper_.TakeInvalidRegion(frame->mutable_updated_region());
1646b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  frame->set_capture_time_ms(
1656b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      (TickTime::Now() - capture_start_time).Milliseconds());
1666b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  callback_->OnCaptureCompleted(frame);
1676b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org}
1686b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
1696b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.orgvoid ScreenCapturerWinMagnifier::SetMouseShapeObserver(
1706b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    MouseShapeObserver* mouse_shape_observer) {
1716b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  assert(false);  // NOTREACHED();
1726b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org}
1736b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
1746b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.orgbool ScreenCapturerWinMagnifier::GetScreenList(ScreenList* screens) {
1756b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  return webrtc::GetScreenList(screens);
1766b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org}
1776b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
1786b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.orgbool ScreenCapturerWinMagnifier::SelectScreen(ScreenId id) {
1796b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  bool valid = IsScreenValid(id, &current_device_key_);
1806b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
1816b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  // Set current_screen_id_ even if the fallback capturer is being used, so we
1826b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  // can switch back to the magnifier when possible.
1836b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  if (valid)
1846b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    current_screen_id_ = id;
1856b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
1866b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  if (fallback_capturer_started_)
1876b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    fallback_capturer_->SelectScreen(id);
1886b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
1896b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  return valid;
1906b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org}
1916b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
1926b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.orgvoid ScreenCapturerWinMagnifier::SetExcludedWindow(WindowId excluded_window) {
1936b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  excluded_window_ = (HWND)excluded_window;
1946b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  if (excluded_window_ && magnifier_initialized_) {
1956b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    set_window_filter_list_func_(
1966b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org        magnifier_window_, MW_FILTERMODE_EXCLUDE, 1, &excluded_window_);
1976b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  }
1986b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org}
1996b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
2006b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.orgbool ScreenCapturerWinMagnifier::CaptureImage(const DesktopRect& rect) {
2016b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  assert(magnifier_initialized_);
2026b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
2036b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  // Set the magnifier control to cover the captured rect. The content of the
2046b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  // magnifier control will be the captured image.
2056b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  BOOL result = SetWindowPos(magnifier_window_,
2066b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                             NULL,
2076b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                             rect.left(), rect.top(),
2086b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                             rect.width(), rect.height(),
2096b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                             0);
2106b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  if (!result) {
2116b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    LOG_F(LS_WARNING) << "Failed to call SetWindowPos: " << GetLastError()
2126b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                      << ". Rect = {" << rect.left() << ", " << rect.top()
2136b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                      << ", " << rect.right() << ", " << rect.bottom() << "}";
2146b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    return false;
2156b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  }
2166b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
2176b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  magnifier_capture_succeeded_ = false;
2186b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
2196b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  RECT native_rect = {rect.left(), rect.top(), rect.right(), rect.bottom()};
2206b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
2216b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  // OnCaptured will be called via OnMagImageScalingCallback and fill in the
2226b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  // frame before set_window_source_func_ returns.
2236b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  result = set_window_source_func_(magnifier_window_, native_rect);
2246b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
2256b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  if (!result) {
2266b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    LOG_F(LS_WARNING) << "Failed to call MagSetWindowSource: " << GetLastError()
2276b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                      << ". Rect = {" << rect.left() << ", " << rect.top()
2286b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                      << ", " << rect.right() << ", " << rect.bottom() << "}";
2296b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    return false;
2306b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  }
2316b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
2326b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  return magnifier_capture_succeeded_;
2336b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org}
2346b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
2356b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.orgBOOL ScreenCapturerWinMagnifier::OnMagImageScalingCallback(
2366b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    HWND hwnd,
2376b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    void* srcdata,
2386b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    MAGIMAGEHEADER srcheader,
2396b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    void* destdata,
2406b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    MAGIMAGEHEADER destheader,
2416b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    RECT unclipped,
2426b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    RECT clipped,
2436b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    HRGN dirty) {
2446b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  assert(tls_index_.Value() != TLS_OUT_OF_INDEXES);
2456b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
2466b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  ScreenCapturerWinMagnifier* owner =
2476b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      reinterpret_cast<ScreenCapturerWinMagnifier*>(
2486b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org          TlsGetValue(tls_index_.Value()));
2496b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
2506b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  owner->OnCaptured(srcdata, srcheader);
2516b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
2526b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  return TRUE;
2536b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org}
2546b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
2556b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.orgbool ScreenCapturerWinMagnifier::InitializeMagnifier() {
2566b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  assert(!magnifier_initialized_);
2576b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
2586b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  desktop_dc_ = GetDC(NULL);
2596b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
2606b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  mag_lib_handle_ = LoadLibrary(L"Magnification.dll");
2616b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  if (!mag_lib_handle_)
2626b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    return false;
2636b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
2646b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  // Initialize Magnification API function pointers.
2656b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  mag_initialize_func_ = reinterpret_cast<MagInitializeFunc>(
2666b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      GetProcAddress(mag_lib_handle_, "MagInitialize"));
2676b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  mag_uninitialize_func_ = reinterpret_cast<MagUninitializeFunc>(
2686b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      GetProcAddress(mag_lib_handle_, "MagUninitialize"));
2696b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  set_window_source_func_ = reinterpret_cast<MagSetWindowSourceFunc>(
2706b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      GetProcAddress(mag_lib_handle_, "MagSetWindowSource"));
2716b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  set_window_filter_list_func_ = reinterpret_cast<MagSetWindowFilterListFunc>(
2726b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      GetProcAddress(mag_lib_handle_, "MagSetWindowFilterList"));
2736b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  set_image_scaling_callback_func_ =
2746b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      reinterpret_cast<MagSetImageScalingCallbackFunc>(
2756b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org          GetProcAddress(mag_lib_handle_, "MagSetImageScalingCallback"));
2766b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
2776b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  if (!mag_initialize_func_ || !mag_uninitialize_func_ ||
2786b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      !set_window_source_func_ || !set_window_filter_list_func_ ||
2796b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      !set_image_scaling_callback_func_) {
2806b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    LOG_F(LS_WARNING) << "Failed to initialize ScreenCapturerWinMagnifier: "
2816b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                      << "library functions missing.";
2826b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    return false;
2836b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  }
2846b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
2856b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  BOOL result = mag_initialize_func_();
2866b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  if (!result) {
2876b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    LOG_F(LS_WARNING) << "Failed to initialize ScreenCapturerWinMagnifier: "
2886b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                      << "error from MagInitialize " << GetLastError();
2896b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    return false;
2906b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  }
2916b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
2926b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  HMODULE hInstance = NULL;
2936b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  result = GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
2946b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                                  GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
2956b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                              reinterpret_cast<char*>(&DefWindowProc),
2966b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                              &hInstance);
2976b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  if (!result) {
2986b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    mag_uninitialize_func_();
2996b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    LOG_F(LS_WARNING) << "Failed to initialize ScreenCapturerWinMagnifier: "
3006b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                      << "error from GetModulehandleExA " << GetLastError();
3016b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    return false;
3026b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  }
3036b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
3046b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  // Register the host window class. See the MSDN documentation of the
3056b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  // Magnification API for more infomation.
3066b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  WNDCLASSEX wcex = {};
3076b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  wcex.cbSize = sizeof(WNDCLASSEX);
3086b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  wcex.lpfnWndProc = &DefWindowProc;
3096b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  wcex.hInstance = hInstance;
3106b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
3116b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  wcex.lpszClassName = kMagnifierHostClass;
3126b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
3136b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  // Ignore the error which may happen when the class is already registered.
3146b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  RegisterClassEx(&wcex);
3156b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
3166b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  // Create the host window.
3176b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  host_window_ = CreateWindowEx(WS_EX_LAYERED,
3186b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                                kMagnifierHostClass,
3196b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                                kHostWindowName,
3206b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                                0,
3216b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                                0, 0, 0, 0,
3226b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                                NULL,
3236b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                                NULL,
3246b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                                hInstance,
3256b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                                NULL);
3266b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  if (!host_window_) {
3276b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    mag_uninitialize_func_();
3286b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    LOG_F(LS_WARNING) << "Failed to initialize ScreenCapturerWinMagnifier: "
3296b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                      << "error from creating host window " << GetLastError();
3306b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    return false;
3316b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  }
3326b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
3336b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  // Create the magnifier control.
3346b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  magnifier_window_ = CreateWindow(kMagnifierWindowClass,
3356b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                                   kMagnifierWindowName,
3366b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                                   WS_CHILD | WS_VISIBLE,
3376b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                                   0, 0, 0, 0,
3386b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                                   host_window_,
3396b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                                   NULL,
3406b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                                   hInstance,
3416b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                                   NULL);
3426b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  if (!magnifier_window_) {
3436b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    mag_uninitialize_func_();
3446b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    LOG_F(LS_WARNING) << "Failed to initialize ScreenCapturerWinMagnifier: "
3456b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                      << "error from creating magnifier window "
3466b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                      << GetLastError();
3476b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    return false;
3486b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  }
3496b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
3506b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  // Hide the host window.
3516b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  ShowWindow(host_window_, SW_HIDE);
3526b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
3536b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  // Set the scaling callback to receive captured image.
3546b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  result = set_image_scaling_callback_func_(
3556b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      magnifier_window_,
3566b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      &ScreenCapturerWinMagnifier::OnMagImageScalingCallback);
3576b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  if (!result) {
3586b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    mag_uninitialize_func_();
3596b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    LOG_F(LS_WARNING) << "Failed to initialize ScreenCapturerWinMagnifier: "
3606b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                      << "error from MagSetImageScalingCallback "
3616b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                      << GetLastError();
3626b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    return false;
3636b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  }
3646b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
3656b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  if (excluded_window_) {
3666b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    result = set_window_filter_list_func_(
3676b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org        magnifier_window_, MW_FILTERMODE_EXCLUDE, 1, &excluded_window_);
3686b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    if (!result) {
3696b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      mag_uninitialize_func_();
3706b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      LOG_F(LS_WARNING) << "Failed to initialize ScreenCapturerWinMagnifier: "
3716b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                        << "error from MagSetWindowFilterList "
3726b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                        << GetLastError();
3736b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      return false;
3746b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    }
3756b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  }
3766b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
3776b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  if (tls_index_.Value() == TLS_OUT_OF_INDEXES) {
3786b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    // More than one threads may get here at the same time, but only one will
3796b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    // write to tls_index_ using CompareExchange.
3806b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    DWORD new_tls_index = TlsAlloc();
3816b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    if (!tls_index_.CompareExchange(new_tls_index, TLS_OUT_OF_INDEXES))
3826b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      TlsFree(new_tls_index);
3836b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  }
3846b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
3856b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  assert(tls_index_.Value() != TLS_OUT_OF_INDEXES);
3866b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  TlsSetValue(tls_index_.Value(), this);
3876b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
3886b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  magnifier_initialized_ = true;
3896b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  return true;
3906b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org}
3916b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
3926b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.orgvoid ScreenCapturerWinMagnifier::OnCaptured(void* data,
3936b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                                            const MAGIMAGEHEADER& header) {
3946b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  DesktopFrame* current_frame = queue_.current_frame();
3956b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
3966b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  // Verify the format.
3976b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  // TODO(jiayl): support capturing sources with pixel formats other than RGBA.
3986b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  int captured_bytes_per_pixel = header.cbSize / header.width / header.height;
3996b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  if (header.format != GUID_WICPixelFormat32bppRGBA ||
4006b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      header.width != static_cast<UINT>(current_frame->size().width()) ||
4016b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      header.height != static_cast<UINT>(current_frame->size().height()) ||
4026b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      header.stride != static_cast<UINT>(current_frame->stride()) ||
4036b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      captured_bytes_per_pixel != DesktopFrame::kBytesPerPixel) {
4046b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    LOG_F(LS_WARNING) << "Output format does not match the captured format: "
4056b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                      << "width = " << header.width << ", "
4066b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                      << "height = " << header.height << ", "
4076b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                      << "stride = " << header.stride << ", "
4086b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                      << "bpp = " << captured_bytes_per_pixel << ", "
4096b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                      << "pixel format RGBA ? "
4106b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org                      << (header.format == GUID_WICPixelFormat32bppRGBA) << ".";
4116b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    return;
4126b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  }
4136b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
4146b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  // Copy the data into the frame.
4156b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  current_frame->CopyPixelsFrom(
4166b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      reinterpret_cast<uint8_t*>(data),
4176b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      header.stride,
4186b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      DesktopRect::MakeXYWH(0, 0, header.width, header.height));
4196b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
4206b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  magnifier_capture_succeeded_ = true;
4216b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org}
4226b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
4236b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.orgvoid ScreenCapturerWinMagnifier::CreateCurrentFrameIfNecessary(
4246b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    const DesktopSize& size) {
4256b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  // If the current buffer is from an older generation then allocate a new one.
4266b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  // Note that we can't reallocate other buffers at this point, since the caller
4276b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  // may still be reading from them.
4286b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  if (!queue_.current_frame() || !queue_.current_frame()->size().equals(size)) {
4296b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    size_t buffer_size =
4306b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org        size.width() * size.height() * DesktopFrame::kBytesPerPixel;
4316b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    SharedMemory* shared_memory = callback_->CreateSharedMemory(buffer_size);
4326b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
4336b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    scoped_ptr<DesktopFrame> buffer;
4346b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    if (shared_memory) {
4356b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      buffer.reset(new SharedMemoryDesktopFrame(
4366b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org          size, size.width() * DesktopFrame::kBytesPerPixel, shared_memory));
4376b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    } else {
4386b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org      buffer.reset(new BasicDesktopFrame(size));
4396b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    }
4406b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    queue_.ReplaceCurrentFrame(buffer.release());
4416b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  }
4426b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org}
4436b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
4446b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.orgbool ScreenCapturerWinMagnifier::IsCapturingPrimaryScreenOnly() const {
4456b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  if (current_screen_id_ != kFullDesktopScreenId)
4466b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    return current_screen_id_ == 0;  // the primary screen is always '0'.
4476b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
4486b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  return GetSystemMetrics(SM_CMONITORS) == 1;
4496b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org}
4506b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
4516b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.orgvoid ScreenCapturerWinMagnifier::StartFallbackCapturer() {
4526b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  assert(fallback_capturer_);
4536b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  if (!fallback_capturer_started_) {
4546b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    fallback_capturer_started_ = true;
4556b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
4566b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    fallback_capturer_->Start(callback_);
4576b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org    fallback_capturer_->SelectScreen(current_screen_id_);
4586b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org  }
4596b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org}
4606b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org
4616b6e3eacfd0ba5d01fb391e72ff2bbf630f231e2jiayl@webrtc.org}  // namespace webrtc
462