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