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 bool Duplicate(Context* context, 65 DesktopVector offset, 66 SharedDesktopFrame* target); 67 68 // Returns the desktop rect covered by this DxgiOutputDuplicator. desktop_rect()69 DesktopRect desktop_rect() const { return desktop_rect_; } 70 71 // Returns the device name from DXGI_OUTPUT_DESC in utf8 encoding. device_name()72 const std::string& device_name() const { return device_name_; } 73 74 void Setup(Context* context); 75 76 void Unregister(const Context* const context); 77 78 // How many frames have been captured by this DxigOutputDuplicator. 79 int64_t num_frames_captured() const; 80 81 // Moves |desktop_rect_|. See DxgiDuplicatorController::TranslateRect(). 82 void TranslateRect(const DesktopVector& position); 83 84 private: 85 // Calls DoDetectUpdatedRegion(). If it fails, this function sets the 86 // |updated_region| as entire UntranslatedDesktopRect(). 87 void DetectUpdatedRegion(const DXGI_OUTDUPL_FRAME_INFO& frame_info, 88 DesktopRegion* updated_region); 89 90 // Returns untranslated updated region, which are directly returned by Windows 91 // APIs. Returns false in case of a failure. 92 bool DoDetectUpdatedRegion(const DXGI_OUTDUPL_FRAME_INFO& frame_info, 93 DesktopRegion* updated_region); 94 95 bool ReleaseFrame(); 96 97 // Initializes duplication_ instance. Expects duplication_ is in empty status. 98 // Returns false if system does not support IDXGIOutputDuplication. 99 bool DuplicateOutput(); 100 101 // Returns a DesktopRect with the same size of desktop_size(), but translated 102 // by offset. 103 DesktopRect GetTranslatedDesktopRect(DesktopVector offset) const; 104 105 // Returns a DesktopRect with the same size of desktop_size(), but starts from 106 // (0, 0). 107 DesktopRect GetUntranslatedDesktopRect() const; 108 109 // Spreads changes from |context| to other registered Context(s) in 110 // contexts_. 111 void SpreadContextChange(const Context* const context); 112 113 // Returns the size of desktop rectangle current instance representing. 114 DesktopSize desktop_size() const; 115 116 const D3dDevice device_; 117 const Microsoft::WRL::ComPtr<IDXGIOutput1> output_; 118 const std::string device_name_; 119 DesktopRect desktop_rect_; 120 Microsoft::WRL::ComPtr<IDXGIOutputDuplication> duplication_; 121 DXGI_OUTDUPL_DESC desc_; 122 std::vector<uint8_t> metadata_; 123 std::unique_ptr<DxgiTexture> texture_; 124 Rotation rotation_; 125 DesktopSize unrotated_size_; 126 127 // After each AcquireNextFrame() function call, updated_region_(s) of all 128 // active Context(s) need to be updated. Since they have missed the 129 // change this time. And during next Duplicate() function call, their 130 // updated_region_ will be merged and copied. 131 std::vector<Context*> contexts_; 132 133 // The last full frame of this output and its offset. If on AcquireNextFrame() 134 // failed because of timeout, i.e. no update, we can copy content from 135 // |last_frame_|. 136 std::unique_ptr<SharedDesktopFrame> last_frame_; 137 DesktopVector last_frame_offset_; 138 139 int64_t num_frames_captured_ = 0; 140 }; 141 142 } // namespace webrtc 143 144 #endif // MODULES_DESKTOP_CAPTURE_WIN_DXGI_OUTPUT_DUPLICATOR_H_ 145