xref: /aosp_15_r20/external/webrtc/modules/desktop_capture/win/dxgi_output_duplicator.h (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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