d3d11screencapture: Subclassing capture implementation
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / sys / d3d11 / gstd3d11screencapture.cpp
1 /*
2  * GStreamer
3  * Copyright (C) 2022 Seungha Yang <seungha@centricular.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "gstd3d11screencapture.h"
26 #include "gstd3d11pluginutils.h"
27 #include <string.h>
28
29 #include <wrl.h>
30
31 GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_screen_capture_debug);
32 #define GST_CAT_DEFAULT gst_d3d11_screen_capture_debug
33
34 /* *INDENT-OFF* */
35 using namespace Microsoft::WRL;
36 /* *INDENT-ON* */
37
38 #define gst_d3d11_screen_capture_parent_class parent_class
39 G_DEFINE_ABSTRACT_TYPE (GstD3D11ScreenCapture, gst_d3d11_screen_capture,
40     GST_TYPE_OBJECT);
41
42 static void
43 gst_d3d11_screen_capture_class_init (GstD3D11ScreenCaptureClass * klass)
44 {
45 }
46
47 static void
48 gst_d3d11_screen_capture_init (GstD3D11ScreenCapture * self)
49 {
50 }
51
52 GstFlowReturn
53 gst_d3d11_screen_capture_prepare (GstD3D11ScreenCapture * capture)
54 {
55   GstD3D11ScreenCaptureClass *klass;
56
57   g_return_val_if_fail (GST_IS_D3D11_SCREEN_CAPTURE (capture), GST_FLOW_ERROR);
58
59   klass = GST_D3D11_SCREEN_CAPTURE_GET_CLASS (capture);
60   g_assert (klass->prepare);
61
62   return klass->prepare (capture);
63 }
64
65 gboolean
66 gst_d3d11_screen_capture_get_size (GstD3D11ScreenCapture * capture,
67     guint * width, guint * height)
68 {
69   GstD3D11ScreenCaptureClass *klass;
70
71   g_return_val_if_fail (GST_IS_D3D11_SCREEN_CAPTURE (capture), FALSE);
72   g_return_val_if_fail (width != nullptr, FALSE);
73   g_return_val_if_fail (height != nullptr, FALSE);
74
75   klass = GST_D3D11_SCREEN_CAPTURE_GET_CLASS (capture);
76   g_assert (klass->get_size);
77
78   return klass->get_size (capture, width, height);
79 }
80
81 gboolean
82 gst_d3d11_screen_capture_get_colorimetry (GstD3D11ScreenCapture * capture,
83     GstVideoColorimetry * colorimetry)
84 {
85   GstD3D11ScreenCaptureClass *klass;
86
87   g_return_val_if_fail (GST_IS_D3D11_SCREEN_CAPTURE (capture), FALSE);
88   g_return_val_if_fail (colorimetry != nullptr, FALSE);
89
90   klass = GST_D3D11_SCREEN_CAPTURE_GET_CLASS (capture);
91   g_assert (klass->get_colorimetry);
92
93   return klass->get_colorimetry (capture, colorimetry);
94 }
95
96 GstFlowReturn
97 gst_d3d11_screen_capture_do_capture (GstD3D11ScreenCapture * capture,
98     GstD3D11Device * device, ID3D11Texture2D * texture,
99     ID3D11RenderTargetView * rtv, ID3D11VertexShader * vs,
100     ID3D11PixelShader * ps, ID3D11InputLayout * layout,
101     ID3D11SamplerState * sampler, ID3D11BlendState * blend,
102     D3D11_BOX * crop_box, gboolean draw_mouse)
103 {
104   GstD3D11ScreenCaptureClass *klass;
105
106   g_return_val_if_fail (GST_IS_D3D11_SCREEN_CAPTURE (capture), GST_FLOW_ERROR);
107   g_return_val_if_fail (texture != nullptr, GST_FLOW_ERROR);
108
109   klass = GST_D3D11_SCREEN_CAPTURE_GET_CLASS (capture);
110   g_assert (klass->do_capture);
111
112   return klass->do_capture (capture, device, texture, rtv,
113       vs, ps, layout, sampler, blend, crop_box, draw_mouse);
114 }
115
116 HRESULT
117 gst_d3d11_screen_capture_find_output_for_monitor (HMONITOR monitor,
118     IDXGIAdapter1 ** adapter, IDXGIOutput ** output)
119 {
120   ComPtr < IDXGIFactory1 > factory;
121   HRESULT hr = S_OK;
122
123   g_return_val_if_fail (monitor != nullptr, E_INVALIDARG);
124
125   hr = CreateDXGIFactory1 (IID_PPV_ARGS (&factory));
126   if (FAILED (hr))
127     return hr;
128
129   for (UINT adapter_idx = 0;; adapter_idx++) {
130     ComPtr < IDXGIAdapter1 > adapter_tmp;
131
132     hr = factory->EnumAdapters1 (adapter_idx, &adapter_tmp);
133     if (FAILED (hr))
134       break;
135
136     for (UINT output_idx = 0;; output_idx++) {
137       ComPtr < IDXGIOutput > output_tmp;
138       DXGI_OUTPUT_DESC desc;
139
140       hr = adapter_tmp->EnumOutputs (output_idx, &output_tmp);
141       if (FAILED (hr))
142         break;
143
144       hr = output_tmp->GetDesc (&desc);
145       if (FAILED (hr))
146         continue;
147
148       if (desc.Monitor == monitor) {
149         if (adapter)
150           *adapter = adapter_tmp.Detach ();
151         if (output)
152           *output = output_tmp.Detach ();
153
154         return S_OK;
155       }
156     }
157   }
158
159   return E_FAIL;
160 }
161
162 HRESULT
163 gst_d3d11_screen_capture_find_primary_monitor (HMONITOR * monitor,
164     IDXGIAdapter1 ** adapter, IDXGIOutput ** output)
165 {
166   ComPtr < IDXGIFactory1 > factory;
167   HRESULT hr = S_OK;
168
169   hr = CreateDXGIFactory1 (IID_PPV_ARGS (&factory));
170   if (FAILED (hr))
171     return hr;
172
173   for (UINT adapter_idx = 0;; adapter_idx++) {
174     ComPtr < IDXGIAdapter1 > adapter_tmp;
175
176     hr = factory->EnumAdapters1 (adapter_idx, &adapter_tmp);
177     if (FAILED (hr))
178       break;
179
180     for (UINT output_idx = 0;; output_idx++) {
181       ComPtr < IDXGIOutput > output_tmp;
182       DXGI_OUTPUT_DESC desc;
183       MONITORINFOEXW minfo;
184
185       hr = adapter_tmp->EnumOutputs (output_idx, &output_tmp);
186       if (FAILED (hr))
187         break;
188
189       hr = output_tmp->GetDesc (&desc);
190       if (FAILED (hr))
191         continue;
192
193       minfo.cbSize = sizeof (MONITORINFOEXW);
194       if (!GetMonitorInfoW (desc.Monitor, &minfo))
195         continue;
196
197       if ((minfo.dwFlags & MONITORINFOF_PRIMARY) != 0) {
198         if (monitor)
199           *monitor = desc.Monitor;
200         if (adapter)
201           *adapter = adapter_tmp.Detach ();
202         if (output)
203           *output = output_tmp.Detach ();
204
205         return S_OK;
206       }
207     }
208   }
209
210   return E_FAIL;
211 }
212
213 HRESULT
214 gst_d3d11_screen_capture_find_nth_monitor (guint index, HMONITOR * monitor,
215     IDXGIAdapter1 ** adapter, IDXGIOutput ** output)
216 {
217   ComPtr < IDXGIFactory1 > factory;
218   HRESULT hr = S_OK;
219   guint num_found = 0;
220
221   hr = CreateDXGIFactory1 (IID_PPV_ARGS (&factory));
222   if (FAILED (hr))
223     return hr;
224
225   for (UINT adapter_idx = 0;; adapter_idx++) {
226     ComPtr < IDXGIAdapter1 > adapter_tmp;
227
228     hr = factory->EnumAdapters1 (adapter_idx, &adapter_tmp);
229     if (FAILED (hr))
230       break;
231
232     for (UINT output_idx = 0;; output_idx++) {
233       ComPtr < IDXGIOutput > output_tmp;
234       DXGI_OUTPUT_DESC desc;
235       MONITORINFOEXW minfo;
236
237       hr = adapter_tmp->EnumOutputs (output_idx, &output_tmp);
238       if (FAILED (hr))
239         break;
240
241       hr = output_tmp->GetDesc (&desc);
242       if (FAILED (hr))
243         continue;
244
245       minfo.cbSize = sizeof (MONITORINFOEXW);
246       if (!GetMonitorInfoW (desc.Monitor, &minfo))
247         continue;
248
249       if (num_found == index) {
250         if (monitor)
251           *monitor = desc.Monitor;
252         if (adapter)
253           *adapter = adapter_tmp.Detach ();
254         if (output)
255           *output = output_tmp.Detach ();
256
257         return S_OK;
258       }
259
260       num_found++;
261     }
262   }
263
264   return E_FAIL;
265 }