dxgi_output_duplicator.h (6426B)
1 /* 2 * Copyright (c) 2016 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 #ifndef MODULES_DESKTOP_CAPTURE_WIN_DXGI_OUTPUT_DUPLICATOR_H_ 12 #define MODULES_DESKTOP_CAPTURE_WIN_DXGI_OUTPUT_DUPLICATOR_H_ 13 14 #include <comdef.h> 15 #include <dxgi.h> 16 #include <dxgi1_2.h> 17 #include <shellscalingapi.h> 18 #include <wrl/client.h> 19 20 #include <cstdint> 21 #include <memory> 22 #include <optional> 23 #include <string> 24 #include <vector> 25 26 #include "modules/desktop_capture/desktop_frame_rotation.h" 27 #include "modules/desktop_capture/desktop_geometry.h" 28 #include "modules/desktop_capture/desktop_region.h" 29 #include "modules/desktop_capture/shared_desktop_frame.h" 30 #include "modules/desktop_capture/win/d3d_device.h" 31 #include "modules/desktop_capture/win/dxgi_context.h" 32 #include "modules/desktop_capture/win/dxgi_texture.h" 33 34 namespace webrtc { 35 36 // Duplicates the content on one IDXGIOutput, i.e. one monitor attached to one 37 // video card. None of functions in this class is thread-safe. 38 class DxgiOutputDuplicator { 39 public: 40 using Context = DxgiOutputContext; 41 42 // Creates an instance of DxgiOutputDuplicator from a D3dDevice and one of its 43 // IDXGIOutput1. Caller must maintain the lifetime of device, to make sure it 44 // outlives this instance. Only DxgiAdapterDuplicator can create an instance. 45 DxgiOutputDuplicator(const D3dDevice& device, 46 const Microsoft::WRL::ComPtr<IDXGIOutput1>& output, 47 const DXGI_OUTPUT_DESC& desc); 48 49 // To allow this class to work with vector. 50 DxgiOutputDuplicator(DxgiOutputDuplicator&& other); 51 52 // Destructs this instance. We need to make sure texture_ has been released 53 // before duplication_. 54 ~DxgiOutputDuplicator(); 55 56 // Initializes duplication_ object. 57 bool Initialize(); 58 59 // Copies the content of current IDXGIOutput to the `target`. To improve the 60 // performance, this function copies only regions merged from 61 // `context`->updated_region and DetectUpdatedRegion(). The `offset` decides 62 // the offset in the `target` where the content should be copied to. i.e. this 63 // function copies the content to the rectangle of (offset.x(), offset.y()) to 64 // (offset.x() + desktop_rect_.width(), offset.y() + desktop_rect_.height()). 65 // Returns false in case of a failure. 66 // May retain a reference to `target` so that a "captured" frame can be 67 // returned in the event that a new frame is not ready to be captured yet. 68 // (Or in other words, if the call to IDXGIOutputDuplication::AcquireNextFrame 69 // indicates that there is not yet a new frame, this is usually because no 70 // updates have occurred to the frame). 71 bool Duplicate(Context* context, 72 DesktopVector offset, 73 SharedDesktopFrame* target); 74 75 // Returns the desktop rect covered by this DxgiOutputDuplicator. 76 DesktopRect desktop_rect() const { return desktop_rect_; } 77 78 // Returns the device name from DXGI_OUTPUT_DESC in utf8 encoding. 79 const std::string& device_name() const { return device_name_; } 80 81 void Setup(Context* context); 82 83 void Unregister(const Context* const context); 84 85 // How many frames have been captured by this DxigOutputDuplicator. 86 int64_t num_frames_captured() const; 87 88 // Device scale factor of the monitor associated with this 89 // DxigOutputDuplicator. 90 std::optional<float> device_scale_factor() const; 91 92 // Moves `desktop_rect_`. See DxgiDuplicatorController::TranslateRect(). 93 void TranslateRect(const DesktopVector& position); 94 95 private: 96 // Calls DoDetectUpdatedRegion(). If it fails, this function sets the 97 // `updated_region` as entire UntranslatedDesktopRect(). 98 void DetectUpdatedRegion(const DXGI_OUTDUPL_FRAME_INFO& frame_info, 99 DesktopRegion* updated_region); 100 101 // Returns untranslated updated region, which are directly returned by Windows 102 // APIs. Returns false in case of a failure. 103 bool DoDetectUpdatedRegion(const DXGI_OUTDUPL_FRAME_INFO& frame_info, 104 DesktopRegion* updated_region); 105 106 // Returns true if the mouse cursor is embedded in the captured frame and 107 // false if not. Also logs the same boolean as 108 // WebRTC.DesktopCapture.Win.DirectXCursorEmbedded UMA. 109 bool ContainsMouseCursor(const DXGI_OUTDUPL_FRAME_INFO& frame_info); 110 111 bool ReleaseFrame(); 112 113 // Initializes duplication_ instance. Expects duplication_ is in empty status. 114 // Returns false if system does not support IDXGIOutputDuplication. 115 bool DuplicateOutput(); 116 117 // Returns a DesktopRect with the same size of desktop_size(), but translated 118 // by offset. 119 DesktopRect GetTranslatedDesktopRect(DesktopVector offset) const; 120 121 // Returns a DesktopRect with the same size of desktop_size(), but starts from 122 // (0, 0). 123 DesktopRect GetUntranslatedDesktopRect() const; 124 125 // Spreads changes from `context` to other registered Context(s) in 126 // contexts_. 127 void SpreadContextChange(const Context* const context); 128 129 // Returns the size of desktop rectangle current instance representing. 130 DesktopSize desktop_size() const; 131 132 const D3dDevice device_; 133 const Microsoft::WRL::ComPtr<IDXGIOutput1> output_; 134 const std::string device_name_; 135 DesktopRect desktop_rect_; 136 const HMONITOR monitor_; 137 Microsoft::WRL::ComPtr<IDXGIOutputDuplication> duplication_; 138 DXGI_OUTDUPL_DESC desc_; 139 std::vector<uint8_t> metadata_; 140 std::unique_ptr<DxgiTexture> texture_; 141 Rotation rotation_; 142 DesktopSize unrotated_size_; 143 144 // After each AcquireNextFrame() function call, updated_region_(s) of all 145 // active Context(s) need to be updated. Since they have missed the 146 // change this time. And during next Duplicate() function call, their 147 // updated_region_ will be merged and copied. 148 std::vector<Context*> contexts_; 149 150 // The last full frame of this output and its offset. If on AcquireNextFrame() 151 // failed because of timeout, i.e. no update, we can copy content from 152 // `last_frame_`. 153 std::unique_ptr<SharedDesktopFrame> last_frame_; 154 DesktopVector last_frame_offset_; 155 156 int64_t num_frames_captured_ = 0; 157 }; 158 159 } // namespace webrtc 160 161 #endif // MODULES_DESKTOP_CAPTURE_WIN_DXGI_OUTPUT_DUPLICATOR_H_