| OLD | NEW | 
|---|
| 1 /* | 1 /* | 
| 2  *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | 2  *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | 
| 3  * | 3  * | 
| 4  *  Use of this source code is governed by a BSD-style license | 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 | 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 | 6  *  tree. An additional intellectual property rights grant can be found | 
| 7  *  in the file PATENTS.  All contributing project authors may | 7  *  in the file PATENTS.  All contributing project authors may | 
| 8  *  be found in the AUTHORS file in the root of the source tree. | 8  *  be found in the AUTHORS file in the root of the source tree. | 
| 9  */ | 9  */ | 
| 10 | 10 | 
| 11 #ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_DXGI_DUPLICATOR_CONTROLLER_H_ | 11 #ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_DXGI_DUPLICATOR_CONTROLLER_H_ | 
| 12 #define WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_DXGI_DUPLICATOR_CONTROLLER_H_ | 12 #define WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_DXGI_DUPLICATOR_CONTROLLER_H_ | 
| 13 | 13 | 
| 14 #include <D3DCommon.h> | 14 #include <D3DCommon.h> | 
| 15 | 15 | 
| 16 #include <memory> | 16 #include <memory> | 
| 17 #include <vector> | 17 #include <vector> | 
| 18 | 18 | 
| 19 #include "webrtc/base/criticalsection.h" | 19 #include "webrtc/base/criticalsection.h" | 
| 20 #include "webrtc/modules/desktop_capture/desktop_geometry.h" | 20 #include "webrtc/modules/desktop_capture/desktop_geometry.h" | 
| 21 #include "webrtc/modules/desktop_capture/desktop_region.h" |  | 
| 22 #include "webrtc/modules/desktop_capture/resolution_change_detector.h" | 21 #include "webrtc/modules/desktop_capture/resolution_change_detector.h" | 
| 23 #include "webrtc/modules/desktop_capture/shared_desktop_frame.h" | 22 #include "webrtc/modules/desktop_capture/shared_desktop_frame.h" | 
| 24 #include "webrtc/modules/desktop_capture/win/d3d_device.h" | 23 #include "webrtc/modules/desktop_capture/win/d3d_device.h" | 
| 25 #include "webrtc/modules/desktop_capture/win/dxgi_adapter_duplicator.h" | 24 #include "webrtc/modules/desktop_capture/win/dxgi_adapter_duplicator.h" | 
|  | 25 #include "webrtc/modules/desktop_capture/win/dxgi_context.h" | 
|  | 26 #include "webrtc/modules/desktop_capture/win/dxgi_frame.h" | 
| 26 | 27 | 
| 27 namespace webrtc { | 28 namespace webrtc { | 
| 28 | 29 | 
| 29 // A controller for all the objects we need to call Windows DirectX capture APIs | 30 // A controller for all the objects we need to call Windows DirectX capture APIs | 
| 30 // It's a singleton because only one IDXGIOutputDuplication instance per monitor | 31 // It's a singleton because only one IDXGIOutputDuplication instance per monitor | 
| 31 // is allowed per application. | 32 // is allowed per application. | 
| 32 // | 33 // | 
| 33 // Consumers should create a DxgiDuplicatorController::Context and keep it | 34 // Consumers should create a DxgiDuplicatorController::Context and keep it | 
| 34 // throughout their lifetime, and pass it when calling Duplicate(). Consumers | 35 // throughout their lifetime, and pass it when calling Duplicate(). Consumers | 
| 35 // can also call IsSupported() to determine whether the system supports DXGI | 36 // can also call IsSupported() to determine whether the system supports DXGI | 
| 36 // duplicator or not. If a previous IsSupported() function call returns true, | 37 // duplicator or not. If a previous IsSupported() function call returns true, | 
| 37 // but a later Duplicate() returns false, this usually means the display mode is | 38 // but a later Duplicate() returns false, this usually means the display mode is | 
| 38 // changing. Consumers should retry after a while. (Typically 50 milliseconds, | 39 // changing. Consumers should retry after a while. (Typically 50 milliseconds, | 
| 39 // but according to hardware performance, this time may vary.) | 40 // but according to hardware performance, this time may vary.) | 
| 40 class DxgiDuplicatorController { | 41 class DxgiDuplicatorController { | 
| 41  public: | 42  public: | 
| 42   // A context to store the status of a single consumer of | 43   using Context = DxgiFrameContext; | 
| 43   // DxgiDuplicatorController. |  | 
| 44   class Context { |  | 
| 45    public: |  | 
| 46     Context(); |  | 
| 47     // Unregister this Context instance from all Dxgi duplicators during |  | 
| 48     // destructing. |  | 
| 49     ~Context(); |  | 
| 50 |  | 
| 51     // Reset current Context, so it will be reinitialized next time. |  | 
| 52     void Reset(); |  | 
| 53 |  | 
| 54    private: |  | 
| 55     friend class DxgiDuplicatorController; |  | 
| 56 |  | 
| 57     // A Context will have an exactly same |identity_| as |  | 
| 58     // DxgiDuplicatorController, to ensure it has been correctly setted up after |  | 
| 59     // each DxgiDuplicatorController::Initialize(). |  | 
| 60     int identity_ = 0; |  | 
| 61 |  | 
| 62     // Child DxgiAdapterDuplicator::Context belongs to this Context. |  | 
| 63     std::vector<DxgiAdapterDuplicator::Context> contexts_; |  | 
| 64   }; |  | 
| 65 | 44 | 
| 66   // A collection of D3d information we are interested on, which may impact | 45   // A collection of D3d information we are interested on, which may impact | 
| 67   // capturer performance or reliability. | 46   // capturer performance or reliability. | 
| 68   struct D3dInfo { | 47   struct D3dInfo { | 
| 69     // Each video adapter has its own D3D_FEATURE_LEVEL, so this structure | 48     // Each video adapter has its own D3D_FEATURE_LEVEL, so this structure | 
| 70     // contains the minimum and maximium D3D_FEATURE_LEVELs current system | 49     // contains the minimum and maximium D3D_FEATURE_LEVELs current system | 
| 71     // supports. | 50     // supports. | 
| 72     // Both fields can be 0, which is the default value to indicate no valid | 51     // Both fields can be 0, which is the default value to indicate no valid | 
| 73     // D3D_FEATURE_LEVEL has been retrieved from underlying OS APIs. | 52     // D3D_FEATURE_LEVEL has been retrieved from underlying OS APIs. | 
| 74     D3D_FEATURE_LEVEL min_feature_level; | 53     D3D_FEATURE_LEVEL min_feature_level; | 
| 75     D3D_FEATURE_LEVEL max_feature_level; | 54     D3D_FEATURE_LEVEL max_feature_level; | 
| 76 | 55 | 
| 77     // TODO(zijiehe): Add more fields, such as manufacturer name, mode, driver | 56     // TODO(zijiehe): Add more fields, such as manufacturer name, mode, driver | 
| 78     // version. | 57     // version. | 
| 79   }; | 58   }; | 
| 80 | 59 | 
|  | 60   enum class Result { | 
|  | 61     SUCCEEDED, | 
|  | 62     FRAME_PREPARE_FAILED, | 
|  | 63     INITIALIZATION_FAILED, | 
|  | 64     DUPLICATION_FAILED, | 
|  | 65     INVALID_MONITOR_ID, | 
|  | 66   }; | 
|  | 67 | 
| 81   // Returns the singleton instance of DxgiDuplicatorController. | 68   // Returns the singleton instance of DxgiDuplicatorController. | 
| 82   static DxgiDuplicatorController* Instance(); | 69   static DxgiDuplicatorController* Instance(); | 
| 83 | 70 | 
| 84   // Destructs current instance. We need to make sure COM components and their | 71   // Destructs current instance. We need to make sure COM components and their | 
| 85   // containers are destructed in correct order. | 72   // containers are destructed in correct order. This function calls | 
|  | 73   // Deinitialize() to do the real work. | 
| 86   ~DxgiDuplicatorController(); | 74   ~DxgiDuplicatorController(); | 
| 87 | 75 | 
| 88   // All the following functions implicitly call Initialize() function if | 76   // All the following public functions implicitly call Initialize() function. | 
| 89   // current instance has not been initialized. |  | 
| 90 | 77 | 
| 91   // Detects whether the system supports DXGI based capturer. | 78   // Detects whether the system supports DXGI based capturer. | 
| 92   bool IsSupported(); | 79   bool IsSupported(); | 
| 93 | 80 | 
| 94   // Calls Deinitialize() function with lock. Consumers can call this function |  | 
| 95   // to force the DxgiDuplicatorController to be reinitialized to avoid an |  | 
| 96   // expected failure in next Duplicate() call. |  | 
| 97   void Reset(); |  | 
| 98 |  | 
| 99   // Returns a copy of D3dInfo composed by last Initialize() function call. | 81   // Returns a copy of D3dInfo composed by last Initialize() function call. | 
| 100   bool RetrieveD3dInfo(D3dInfo* info); | 82   bool RetrieveD3dInfo(D3dInfo* info); | 
| 101 | 83 | 
| 102   // Captures current screen and writes into target. Since we are using double | 84   // Captures current screen and writes into |frame|. | 
| 103   // buffering, |last_frame|.updated_region() is used to represent the not |  | 
| 104   // updated regions in current |target| frame, which should also be copied this |  | 
| 105   // time. |  | 
| 106   // TODO(zijiehe): Windows cannot guarantee the frames returned by each | 85   // TODO(zijiehe): Windows cannot guarantee the frames returned by each | 
| 107   // IDXGIOutputDuplication are synchronized. But we are using a totally | 86   // IDXGIOutputDuplication are synchronized. But we are using a totally | 
| 108   // different threading model than the way Windows suggested, it's hard to | 87   // different threading model than the way Windows suggested, it's hard to | 
| 109   // synchronize them manually. We should find a way to do it. | 88   // synchronize them manually. We should find a way to do it. | 
| 110   bool Duplicate(Context* context, SharedDesktopFrame* target); | 89   Result Duplicate(DxgiFrame* frame); | 
| 111 | 90 | 
| 112   // Captures one monitor and writes into target. |monitor_id| should >= 0. If | 91   // Captures one monitor and writes into target. |monitor_id| should >= 0. If | 
| 113   // |monitor_id| is greater than the total screen count of all the Duplicators, | 92   // |monitor_id| is greater than the total screen count of all the Duplicators, | 
| 114   // this function returns false. | 93   // this function returns false. | 
| 115   bool DuplicateMonitor(Context* context, | 94   Result DuplicateMonitor(DxgiFrame* frame, int monitor_id); | 
| 116                         int monitor_id, |  | 
| 117                         SharedDesktopFrame* target); |  | 
| 118 | 95 | 
| 119   // Returns dpi of current system. Returns an empty DesktopVector if system | 96   // Returns dpi of current system. Returns an empty DesktopVector if system | 
| 120   // does not support DXGI based capturer. | 97   // does not support DXGI based capturer. | 
| 121   DesktopVector dpi(); | 98   DesktopVector dpi(); | 
| 122 | 99 | 
| 123   // Returns entire desktop size. Returns an empty DesktopRect if system does |  | 
| 124   // not support DXGI based capturer. |  | 
| 125   DesktopRect desktop_rect(); |  | 
| 126 |  | 
| 127   // Returns a DesktopSize to cover entire desktop_rect. This may be different |  | 
| 128   // than desktop_rect().size(), since top-left screen does not need to start |  | 
| 129   // from (0, 0). |  | 
| 130   DesktopSize desktop_size(); |  | 
| 131 |  | 
| 132   // Returns the size of one screen. |monitor_id| should be >= 0. If system does |  | 
| 133   // not support DXGI based capturer, or |monitor_id| is greater than the total |  | 
| 134   // screen count of all the Duplicators, this function returns an empty |  | 
| 135   // DesktopRect. |  | 
| 136   DesktopRect ScreenRect(int id); |  | 
| 137 |  | 
| 138   // Returns the count of screens on the system. These screens can be retrieved | 100   // Returns the count of screens on the system. These screens can be retrieved | 
| 139   // by an integer in the range of [0, ScreenCount()). If system does not | 101   // by an integer in the range of [0, ScreenCount()). If system does not | 
| 140   // support DXGI based capturer, this function returns 0. | 102   // support DXGI based capturer, this function returns 0. | 
| 141   int ScreenCount(); | 103   int ScreenCount(); | 
| 142 | 104 | 
| 143  private: | 105  private: | 
| 144   // Context calls private Unregister(Context*) function during | 106   // DxgiFrameContext calls private Unregister(Context*) function during | 
| 145   // destructing. | 107   // destructing. | 
| 146   friend class Context; | 108   friend DxgiFrameContext::~DxgiFrameContext(); | 
| 147 | 109 | 
| 148   // A private constructor to ensure consumers to use | 110   // A private constructor to ensure consumers to use | 
| 149   // DxgiDuplicatorController::Instance(). | 111   // DxgiDuplicatorController::Instance(). | 
| 150   DxgiDuplicatorController(); | 112   DxgiDuplicatorController(); | 
| 151 | 113 | 
|  | 114   // Does the real duplication work. Setting |monitor_id| < 0 to capture entire | 
|  | 115   // screen. This function calls Initialize(). And if the duplication failed, | 
|  | 116   // this function calls Deinitialize() to ensure the Dxgi components can be | 
|  | 117   // reinitialized next time. | 
|  | 118   Result DoDuplicate(DxgiFrame* frame, int monitor_id); | 
|  | 119 | 
| 152   // Unregisters Context from this instance and all DxgiAdapterDuplicator(s) | 120   // Unregisters Context from this instance and all DxgiAdapterDuplicator(s) | 
| 153   // it owns. | 121   // it owns. | 
| 154   void Unregister(const Context* const context); | 122   void Unregister(const Context* const context); | 
| 155 | 123 | 
| 156   // All functions below should be called in |lock_| locked scope. | 124   // All functions below should be called in |lock_| locked scope and should be | 
|  | 125   // after a successful Initialize(). | 
| 157 | 126 | 
| 158   // If current instance has not been initialized, executes DoInitialize | 127   // If current instance has not been initialized, executes DoInitialize() | 
| 159   // function, and returns initialize result. Otherwise directly returns true. | 128   // function, and returns initialize result. Otherwise directly returns true. | 
|  | 129   // This function may calls Deinitialize() if initialization failed. | 
| 160   bool Initialize(); | 130   bool Initialize(); | 
| 161 | 131 | 
|  | 132   // Does the real initialization work, this function should only be called in | 
|  | 133   // Initialize(). | 
| 162   bool DoInitialize(); | 134   bool DoInitialize(); | 
| 163 | 135 | 
| 164   // Clears all COM components referred by this instance. So next Duplicate() | 136   // Clears all COM components referred by this instance. So next Duplicate() | 
| 165   // call will eventually initialize this instance again. | 137   // call will eventually initialize this instance again. | 
| 166   void Deinitialize(); | 138   void Deinitialize(); | 
| 167 | 139 | 
| 168   // A helper function to check whether a Context has been expired. | 140   // A helper function to check whether a Context has been expired. | 
| 169   bool ContextExpired(const Context* const context) const; | 141   bool ContextExpired(const Context* const context) const; | 
| 170 | 142 | 
| 171   // Updates Context if needed. | 143   // Updates Context if needed. | 
| 172   void Setup(Context* context); | 144   void Setup(Context* context); | 
| 173 | 145 | 
| 174   // Does the real duplication work. |monitor_id < 0| to capture entire screen. |  | 
| 175   bool DoDuplicate(Context* context, |  | 
| 176                    int monitor_id, |  | 
| 177                    SharedDesktopFrame* target); |  | 
| 178 |  | 
| 179   bool DoDuplicateUnlocked(Context* context, | 146   bool DoDuplicateUnlocked(Context* context, | 
| 180                            int monitor_id, | 147                            int monitor_id, | 
| 181                            SharedDesktopFrame* target); | 148                            SharedDesktopFrame* target); | 
| 182 | 149 | 
| 183   // Captures all monitors. | 150   // Captures all monitors. | 
| 184   bool DoDuplicateAll(Context* context, SharedDesktopFrame* target); | 151   bool DoDuplicateAll(Context* context, SharedDesktopFrame* target); | 
| 185 | 152 | 
| 186   // Captures one monitor. | 153   // Captures one monitor. | 
| 187   bool DoDuplicateOne(Context* context, | 154   bool DoDuplicateOne(Context* context, | 
| 188                       int monitor_id, | 155                       int monitor_id, | 
| 189                       SharedDesktopFrame* target); | 156                       SharedDesktopFrame* target); | 
| 190 | 157 | 
| 191   // The minimum GetNumFramesCaptured() returned by |duplicators_|. | 158   // The minimum GetNumFramesCaptured() returned by |duplicators_|. | 
| 192   int64_t GetNumFramesCaptured() const; | 159   int64_t GetNumFramesCaptured() const; | 
| 193 | 160 | 
| 194   int ScreenCountUnlocked(); | 161   // Returns a DesktopSize to cover entire desktop_rect. This may be different | 
|  | 162   // than desktop_rect().size(), since top-left of the screen does not need to | 
|  | 163   // be started from (0, 0). | 
|  | 164   DesktopSize desktop_size() const; | 
|  | 165 | 
|  | 166   // Returns the size of one screen. |id| should be >= 0. If system does not | 
|  | 167   // support DXGI based capturer, or |id| is greater than the total screen count | 
|  | 168   // of all the Duplicators, this function returns an empty DesktopRect. | 
|  | 169   DesktopRect ScreenRect(int id) const; | 
|  | 170 | 
|  | 171   int ScreenCountUnlocked() const; | 
|  | 172 | 
|  | 173   // Returns the desktop size of the selected screen |monitor_id|. Setting | 
|  | 174   // |monitor_id| < 0 to return the entire screen size. | 
|  | 175   DesktopSize SelectedDesktopSize(int monitor_id) const; | 
| 195 | 176 | 
| 196   // Retries DoDuplicateAll() for several times until GetNumFramesCaptured() is | 177   // Retries DoDuplicateAll() for several times until GetNumFramesCaptured() is | 
| 197   // large enough. Returns false if DoDuplicateAll() returns false, or | 178   // large enough. Returns false if DoDuplicateAll() returns false, or | 
| 198   // GetNumFramesCaptured() has never reached the requirement. | 179   // GetNumFramesCaptured() has never reached the requirement. | 
| 199   // According to http://crbug.com/682112, dxgi capturer returns a black frame | 180   // According to http://crbug.com/682112, dxgi capturer returns a black frame | 
| 200   // during first several capture attempts. | 181   // during first several capture attempts. | 
| 201   bool EnsureFrameCaptured(Context* context, SharedDesktopFrame* target); | 182   bool EnsureFrameCaptured(Context* context, SharedDesktopFrame* target); | 
| 202 | 183 | 
| 203   // This lock must be locked whenever accessing any of the following objects. | 184   // This lock must be locked whenever accessing any of the following objects. | 
| 204   rtc::CriticalSection lock_; | 185   rtc::CriticalSection lock_; | 
| 205 | 186 | 
| 206   // A self-incremented integer to compare with the one in Context, to | 187   // A self-incremented integer to compare with the one in Context. It ensures | 
| 207   // ensure a Context has been initialized after DxgiDuplicatorController. | 188   // a Context instance is always initialized after DxgiDuplicatorController. | 
| 208   int identity_ = 0; | 189   int identity_ = 0; | 
| 209   DesktopRect desktop_rect_; | 190   DesktopRect desktop_rect_; | 
| 210   DesktopVector dpi_; | 191   DesktopVector dpi_; | 
| 211   std::vector<DxgiAdapterDuplicator> duplicators_; | 192   std::vector<DxgiAdapterDuplicator> duplicators_; | 
| 212   D3dInfo d3d_info_; | 193   D3dInfo d3d_info_; | 
| 213   ResolutionChangeDetector resolution_change_detector_; | 194   ResolutionChangeDetector resolution_change_detector_; | 
| 214 }; | 195 }; | 
| 215 | 196 | 
| 216 }  // namespace webrtc | 197 }  // namespace webrtc | 
| 217 | 198 | 
| 218 #endif  // WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_DXGI_DUPLICATOR_CONTROLLER_H_ | 199 #endif  // WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_DXGI_DUPLICATOR_CONTROLLER_H_ | 
| OLD | NEW | 
|---|