tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

wgc_capture_source.cc (6659B)


      1 /*
      2 *  Copyright (c) 2020 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 "modules/desktop_capture/win/wgc_capture_source.h"
     12 
     13 #include <dwmapi.h>
     14 #include <windows.graphics.capture.interop.h>
     15 #include <windows.h>
     16 
     17 #include <memory>
     18 #include <utility>
     19 
     20 #include "modules/desktop_capture/desktop_capturer.h"
     21 #include "modules/desktop_capture/desktop_geometry.h"
     22 #include "modules/desktop_capture/win/screen_capture_utils.h"
     23 #include "modules/desktop_capture/win/window_capture_utils.h"
     24 #include "rtc_base/win/get_activation_factory.h"
     25 
     26 using Microsoft::WRL::ComPtr;
     27 namespace WGC = ABI::Windows::Graphics::Capture;
     28 
     29 namespace webrtc {
     30 
     31 WgcCaptureSource::WgcCaptureSource(DesktopCapturer::SourceId source_id)
     32    : source_id_(source_id) {}
     33 WgcCaptureSource::~WgcCaptureSource() = default;
     34 
     35 bool WgcCaptureSource::ShouldBeCapturable() {
     36  return true;
     37 }
     38 
     39 bool WgcCaptureSource::IsCapturable() {
     40  // If we can create a capture item, then we can capture it. Unfortunately,
     41  // we can't cache this item because it may be created in a different COM
     42  // apartment than where capture will eventually start from.
     43  ComPtr<WGC::IGraphicsCaptureItem> item;
     44  return SUCCEEDED(CreateCaptureItem(&item));
     45 }
     46 
     47 bool WgcCaptureSource::FocusOnSource() {
     48  return false;
     49 }
     50 
     51 ABI::Windows::Graphics::SizeInt32 WgcCaptureSource::GetSize() {
     52  if (!item_)
     53    return {0, 0};
     54 
     55  ABI::Windows::Graphics::SizeInt32 item_size;
     56  HRESULT hr = item_->get_Size(&item_size);
     57  if (FAILED(hr))
     58    return {0, 0};
     59 
     60  return item_size;
     61 }
     62 
     63 HRESULT WgcCaptureSource::GetCaptureItem(
     64    ComPtr<WGC::IGraphicsCaptureItem>* result) {
     65  HRESULT hr = S_OK;
     66  if (!item_)
     67    hr = CreateCaptureItem(&item_);
     68 
     69  *result = item_;
     70  return hr;
     71 }
     72 
     73 WgcCaptureSourceFactory::~WgcCaptureSourceFactory() = default;
     74 
     75 WgcWindowSourceFactory::WgcWindowSourceFactory() = default;
     76 WgcWindowSourceFactory::~WgcWindowSourceFactory() = default;
     77 
     78 std::unique_ptr<WgcCaptureSource> WgcWindowSourceFactory::CreateCaptureSource(
     79    DesktopCapturer::SourceId source_id) {
     80  return std::make_unique<WgcWindowSource>(source_id);
     81 }
     82 
     83 WgcScreenSourceFactory::WgcScreenSourceFactory() = default;
     84 WgcScreenSourceFactory::~WgcScreenSourceFactory() = default;
     85 
     86 std::unique_ptr<WgcCaptureSource> WgcScreenSourceFactory::CreateCaptureSource(
     87    DesktopCapturer::SourceId source_id) {
     88  return std::make_unique<WgcScreenSource>(source_id);
     89 }
     90 
     91 WgcWindowSource::WgcWindowSource(DesktopCapturer::SourceId source_id)
     92    : WgcCaptureSource(source_id) {}
     93 WgcWindowSource::~WgcWindowSource() = default;
     94 
     95 DesktopVector WgcWindowSource::GetTopLeft() {
     96  DesktopRect window_rect;
     97  if (!GetWindowRect(reinterpret_cast<HWND>(GetSourceId()), &window_rect))
     98    return DesktopVector();
     99 
    100  return window_rect.top_left();
    101 }
    102 
    103 ABI::Windows::Graphics::SizeInt32 WgcWindowSource::GetSize() {
    104  RECT window_rect;
    105  HRESULT hr = ::DwmGetWindowAttribute(
    106      reinterpret_cast<HWND>(GetSourceId()), DWMWA_EXTENDED_FRAME_BOUNDS,
    107      reinterpret_cast<void*>(&window_rect), sizeof(window_rect));
    108  if (FAILED(hr))
    109    return WgcCaptureSource::GetSize();
    110 
    111  return {window_rect.right - window_rect.left,
    112          window_rect.bottom - window_rect.top};
    113 }
    114 
    115 bool WgcWindowSource::ShouldBeCapturable() {
    116  return IsWindowValidAndVisible(reinterpret_cast<HWND>(GetSourceId()));
    117 }
    118 
    119 bool WgcWindowSource::IsCapturable() {
    120  if (!ShouldBeCapturable()) {
    121    return false;
    122  }
    123 
    124  return WgcCaptureSource::IsCapturable();
    125 }
    126 
    127 bool WgcWindowSource::FocusOnSource() {
    128  if (!IsWindowValidAndVisible(reinterpret_cast<HWND>(GetSourceId())))
    129    return false;
    130 
    131  return ::BringWindowToTop(reinterpret_cast<HWND>(GetSourceId())) &&
    132         ::SetForegroundWindow(reinterpret_cast<HWND>(GetSourceId()));
    133 }
    134 
    135 HRESULT WgcWindowSource::CreateCaptureItem(
    136    ComPtr<WGC::IGraphicsCaptureItem>* result) {
    137  if (!ResolveCoreWinRTDelayload())
    138    return E_FAIL;
    139 
    140  ComPtr<IGraphicsCaptureItemInterop> interop;
    141  HRESULT hr = GetActivationFactory<
    142      IGraphicsCaptureItemInterop,
    143      RuntimeClass_Windows_Graphics_Capture_GraphicsCaptureItem>(&interop);
    144  if (FAILED(hr))
    145    return hr;
    146 
    147  ComPtr<WGC::IGraphicsCaptureItem> item;
    148  hr = interop->CreateForWindow(reinterpret_cast<HWND>(GetSourceId()),
    149                                IID_PPV_ARGS(&item));
    150  if (FAILED(hr))
    151    return hr;
    152 
    153  if (!item)
    154    return E_HANDLE;
    155 
    156  *result = std::move(item);
    157  return hr;
    158 }
    159 
    160 WgcScreenSource::WgcScreenSource(DesktopCapturer::SourceId source_id)
    161    : WgcCaptureSource(source_id) {
    162  // Getting the HMONITOR could fail if the source_id is invalid. In that case,
    163  // we leave hmonitor_ uninitialized and `IsCapturable()` will fail.
    164  HMONITOR hmon;
    165  if (GetHmonitorFromDeviceIndex(GetSourceId(), &hmon))
    166    hmonitor_ = hmon;
    167 }
    168 
    169 WgcScreenSource::~WgcScreenSource() = default;
    170 
    171 DesktopVector WgcScreenSource::GetTopLeft() {
    172  if (!hmonitor_)
    173    return DesktopVector();
    174 
    175  return GetMonitorRect(*hmonitor_).top_left();
    176 }
    177 
    178 ABI::Windows::Graphics::SizeInt32 WgcScreenSource::GetSize() {
    179  ABI::Windows::Graphics::SizeInt32 size = WgcCaptureSource::GetSize();
    180  if (!hmonitor_ || (size.Width != 0 && size.Height != 0))
    181    return size;
    182 
    183  DesktopRect rect = GetMonitorRect(*hmonitor_);
    184  return {rect.width(), rect.height()};
    185 }
    186 
    187 bool WgcScreenSource::IsCapturable() {
    188  if (!hmonitor_)
    189    return false;
    190 
    191  if (!IsMonitorValid(*hmonitor_))
    192    return false;
    193 
    194  return WgcCaptureSource::IsCapturable();
    195 }
    196 
    197 HRESULT WgcScreenSource::CreateCaptureItem(
    198    ComPtr<WGC::IGraphicsCaptureItem>* result) {
    199  if (!hmonitor_)
    200    return E_ABORT;
    201 
    202  if (!ResolveCoreWinRTDelayload())
    203    return E_FAIL;
    204 
    205  ComPtr<IGraphicsCaptureItemInterop> interop;
    206  HRESULT hr = GetActivationFactory<
    207      IGraphicsCaptureItemInterop,
    208      RuntimeClass_Windows_Graphics_Capture_GraphicsCaptureItem>(&interop);
    209  if (FAILED(hr))
    210    return hr;
    211 
    212  // Ensure the monitor is still valid (hasn't disconnected) before trying to
    213  // create the item. On versions of Windows before Win11, `CreateForMonitor`
    214  // will crash if no displays are connected.
    215  if (!IsMonitorValid(hmonitor_.value()))
    216    return E_ABORT;
    217 
    218  ComPtr<WGC::IGraphicsCaptureItem> item;
    219  hr = interop->CreateForMonitor(*hmonitor_, IID_PPV_ARGS(&item));
    220  if (FAILED(hr))
    221    return hr;
    222 
    223  if (!item)
    224    return E_HANDLE;
    225 
    226  *result = std::move(item);
    227  return hr;
    228 }
    229 
    230 }  // namespace webrtc