7a253d4484d47c364cf1d47f5e3507502c7553e2
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / sys / d3d11 / gstd3d11pluginutils.cpp
1 /* GStreamer
2  * Copyright (C) 2019 Seungha Yang <seungha.yang@navercorp.com>
3  * Copyright (C) 2020 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 "gstd3d11pluginutils.h"
26
27 #include <windows.h>
28 #include <versionhelpers.h>
29
30 GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_plugin_utils_debug);
31 #define GST_CAT_DEFAULT gst_d3d11_plugin_utils_debug
32
33 /* Max Texture Dimension for feature level 11_0 ~ 12_1 */
34 static guint _gst_d3d11_texture_max_dimension = 16384;
35
36 void
37 gst_d3d11_plugin_utils_init (D3D_FEATURE_LEVEL feature_level)
38 {
39   static gsize _init_once = 0;
40
41   if (g_once_init_enter (&_init_once)) {
42     /* https://docs.microsoft.com/en-us/windows/win32/direct3d11/overviews-direct3d-11-devices-downlevel-intro */
43     if (feature_level >= D3D_FEATURE_LEVEL_11_0)
44       _gst_d3d11_texture_max_dimension = 16384;
45     else if (feature_level >= D3D_FEATURE_LEVEL_10_0)
46       _gst_d3d11_texture_max_dimension = 8192;
47     else
48       _gst_d3d11_texture_max_dimension = 4096;
49
50     g_once_init_leave (&_init_once, 1);
51   }
52 }
53
54 GstCaps *
55 gst_d3d11_get_updated_template_caps (GstStaticCaps * template_caps)
56 {
57   GstCaps *caps;
58
59   g_return_val_if_fail (template_caps != NULL, NULL);
60
61   caps = gst_static_caps_get (template_caps);
62   if (!caps) {
63     GST_ERROR ("Couldn't get caps from static caps");
64     return NULL;
65   }
66
67   caps = gst_caps_make_writable (caps);
68   gst_caps_set_simple (caps,
69       "width", GST_TYPE_INT_RANGE, 1, _gst_d3d11_texture_max_dimension,
70       "height", GST_TYPE_INT_RANGE, 1, _gst_d3d11_texture_max_dimension, NULL);
71
72   return caps;
73 }
74
75 gboolean
76 gst_d3d11_is_windows_8_or_greater (void)
77 {
78   static gsize version_once = 0;
79   static gboolean ret = FALSE;
80
81   if (g_once_init_enter (&version_once)) {
82 #if (!GST_D3D11_WINAPI_ONLY_APP)
83     if (IsWindows8OrGreater ())
84       ret = TRUE;
85 #else
86     ret = TRUE;
87 #endif
88
89     g_once_init_leave (&version_once, 1);
90   }
91
92   return ret;
93 }
94
95 GstD3D11DeviceVendor
96 gst_d3d11_get_device_vendor (GstD3D11Device * device)
97 {
98   guint device_id = 0;
99   guint vendor_id = 0;
100   gchar *desc = NULL;
101   GstD3D11DeviceVendor vendor = GST_D3D11_DEVICE_VENDOR_UNKNOWN;
102
103   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device),
104       GST_D3D11_DEVICE_VENDOR_UNKNOWN);
105
106   g_object_get (device, "device-id", &device_id, "vendor-id", &vendor_id,
107       "description", &desc, NULL);
108
109   switch (vendor_id) {
110     case 0:
111       if (device_id == 0 && desc && g_strrstr (desc, "SraKmd"))
112         vendor = GST_D3D11_DEVICE_VENDOR_XBOX;
113       break;
114     case 0x1002:
115     case 0x1022:
116       vendor = GST_D3D11_DEVICE_VENDOR_AMD;
117       break;
118     case 0x8086:
119       vendor = GST_D3D11_DEVICE_VENDOR_INTEL;
120       break;
121     case 0x10de:
122       vendor = GST_D3D11_DEVICE_VENDOR_NVIDIA;
123       break;
124     case 0x4d4f4351:
125       vendor = GST_D3D11_DEVICE_VENDOR_QUALCOMM;
126       break;
127     default:
128       break;
129   }
130
131   g_free (desc);
132
133   return vendor;
134 }
135
136 #if (GST_D3D11_DXGI_HEADER_VERSION >= 5)
137 gboolean
138 gst_d3d11_hdr_meta_data_to_dxgi (GstVideoMasteringDisplayInfo * minfo,
139     GstVideoContentLightLevel * cll, DXGI_HDR_METADATA_HDR10 * dxgi_hdr10)
140 {
141   g_return_val_if_fail (dxgi_hdr10 != NULL, FALSE);
142
143   memset (dxgi_hdr10, 0, sizeof (DXGI_HDR_METADATA_HDR10));
144
145   if (minfo) {
146     dxgi_hdr10->RedPrimary[0] = minfo->display_primaries[0].x;
147     dxgi_hdr10->RedPrimary[1] = minfo->display_primaries[0].y;
148     dxgi_hdr10->GreenPrimary[0] = minfo->display_primaries[1].x;
149     dxgi_hdr10->GreenPrimary[1] = minfo->display_primaries[1].y;
150     dxgi_hdr10->BluePrimary[0] = minfo->display_primaries[2].x;
151     dxgi_hdr10->BluePrimary[1] = minfo->display_primaries[2].y;
152
153     dxgi_hdr10->WhitePoint[0] = minfo->white_point.x;
154     dxgi_hdr10->WhitePoint[1] = minfo->white_point.y;
155     dxgi_hdr10->MaxMasteringLuminance = minfo->max_display_mastering_luminance;
156     dxgi_hdr10->MinMasteringLuminance = minfo->min_display_mastering_luminance;
157   }
158
159   if (cll) {
160     dxgi_hdr10->MaxContentLightLevel = cll->max_content_light_level;
161     dxgi_hdr10->MaxFrameAverageLightLevel = cll->max_frame_average_light_level;
162   }
163
164   return TRUE;
165 }
166 #endif
167
168 #if (GST_D3D11_DXGI_HEADER_VERSION >= 4)
169 typedef enum
170 {
171   GST_DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709 = 0,
172   GST_DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709 = 1,
173   GST_DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P709 = 2,
174   GST_DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P2020 = 3,
175   GST_DXGI_COLOR_SPACE_RESERVED = 4,
176   GST_DXGI_COLOR_SPACE_YCBCR_FULL_G22_NONE_P709_X601 = 5,
177   GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P601 = 6,
178   GST_DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P601 = 7,
179   GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709 = 8,
180   GST_DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P709 = 9,
181   GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P2020 = 10,
182   GST_DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P2020 = 11,
183   GST_DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 = 12,
184   GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_LEFT_P2020 = 13,
185   GST_DXGI_COLOR_SPACE_RGB_STUDIO_G2084_NONE_P2020 = 14,
186   GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_TOPLEFT_P2020 = 15,
187   GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_TOPLEFT_P2020 = 16,
188   GST_DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P2020 = 17,
189   GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_GHLG_TOPLEFT_P2020 = 18,
190   GST_DXGI_COLOR_SPACE_YCBCR_FULL_GHLG_TOPLEFT_P2020 = 19,
191   GST_DXGI_COLOR_SPACE_RGB_STUDIO_G24_NONE_P709 = 20,
192   GST_DXGI_COLOR_SPACE_RGB_STUDIO_G24_NONE_P2020 = 21,
193   GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G24_LEFT_P709 = 22,
194   GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G24_LEFT_P2020 = 23,
195   GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G24_TOPLEFT_P2020 = 24,
196   GST_DXGI_COLOR_SPACE_CUSTOM = 0xFFFFFFFF
197 } GST_DXGI_COLOR_SPACE_TYPE;
198
199 /* https://docs.microsoft.com/en-us/windows/win32/api/dxgicommon/ne-dxgicommon-dxgi_color_space_type */
200
201 #define MAKE_COLOR_MAP(d,r,m,t,p) \
202   { GST_DXGI_COLOR_SPACE_ ##d, GST_VIDEO_COLOR_RANGE ##r, \
203     GST_VIDEO_COLOR_MATRIX_ ##m, GST_VIDEO_TRANSFER_ ##t, \
204     GST_VIDEO_COLOR_PRIMARIES_ ##p }
205
206 static const GstDxgiColorSpace rgb_colorspace_map[] = {
207   /* 1) DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709
208    * 2) DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709
209    * 3) DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P709
210    * 4) DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P2020
211    * 5) DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020
212    * 6) DXGI_COLOR_SPACE_RGB_STUDIO_G2084_NONE_P2020
213    * 7) DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P2020
214    * 8) DXGI_COLOR_SPACE_RGB_STUDIO_G24_NONE_P709
215    * 9) DXGI_COLOR_SPACE_RGB_STUDIO_G24_NONE_P2020
216    *
217    * NOTE: if G24 (Gamma 2.4, SRGB) transfer is not defined,
218    * it will be approximated as G22.
219    * NOTE: BT470BG ~= BT709
220    */
221
222   /* 1) RGB_FULL_G22_NONE_P709 */
223   MAKE_COLOR_MAP (RGB_FULL_G22_NONE_P709, _0_255, UNKNOWN, BT709, BT709),
224   MAKE_COLOR_MAP (RGB_FULL_G22_NONE_P709, _0_255, UNKNOWN, BT601, BT709),
225   MAKE_COLOR_MAP (RGB_FULL_G22_NONE_P709, _0_255, UNKNOWN, BT2020_10, BT709),
226   MAKE_COLOR_MAP (RGB_FULL_G22_NONE_P709, _0_255, UNKNOWN, BT2020_12, BT709),
227   MAKE_COLOR_MAP (RGB_FULL_G22_NONE_P709, _0_255, UNKNOWN, BT709, BT470BG),
228   MAKE_COLOR_MAP (RGB_FULL_G22_NONE_P709, _0_255, UNKNOWN, BT601, BT470BG),
229   MAKE_COLOR_MAP (RGB_FULL_G22_NONE_P709, _0_255, UNKNOWN, BT2020_10, BT470BG),
230   MAKE_COLOR_MAP (RGB_FULL_G22_NONE_P709, _0_255, UNKNOWN, BT2020_12, BT470BG),
231
232   /* 1-1) Approximation for RGB_FULL_G22_NONE_P709 */
233   MAKE_COLOR_MAP (RGB_FULL_G22_NONE_P709, _0_255, UNKNOWN, SRGB, BT709),
234   MAKE_COLOR_MAP (RGB_FULL_G22_NONE_P709, _0_255, UNKNOWN, SRGB, BT470BG),
235
236   /* 2) RGB_FULL_G10_NONE_P709 */
237   MAKE_COLOR_MAP (RGB_FULL_G10_NONE_P709, _0_255, UNKNOWN, GAMMA10, BT709),
238   MAKE_COLOR_MAP (RGB_FULL_G10_NONE_P709, _0_255, UNKNOWN, GAMMA10, BT470BG),
239
240   /* 3) RGB_STUDIO_G22_NONE_P709 */
241   MAKE_COLOR_MAP (RGB_STUDIO_G22_NONE_P709, _16_235, UNKNOWN, BT709, BT709),
242   MAKE_COLOR_MAP (RGB_STUDIO_G22_NONE_P709, _16_235, UNKNOWN, BT601, BT709),
243   MAKE_COLOR_MAP (RGB_STUDIO_G22_NONE_P709, _16_235, UNKNOWN, BT2020_10, BT709),
244   MAKE_COLOR_MAP (RGB_STUDIO_G22_NONE_P709, _16_235, UNKNOWN, BT2020_12, BT709),
245   MAKE_COLOR_MAP (RGB_STUDIO_G22_NONE_P709, _16_235, UNKNOWN, BT709, BT470BG),
246   MAKE_COLOR_MAP (RGB_STUDIO_G22_NONE_P709, _16_235, UNKNOWN, BT601, BT470BG),
247   MAKE_COLOR_MAP (RGB_STUDIO_G22_NONE_P709, _16_235, UNKNOWN, BT2020_10,
248       BT470BG),
249   MAKE_COLOR_MAP (RGB_STUDIO_G22_NONE_P709, _16_235, UNKNOWN, BT2020_12,
250       BT470BG),
251
252   /* 3-1) Approximation for RGB_STUDIO_G22_NONE_P709 */
253   MAKE_COLOR_MAP (RGB_STUDIO_G22_NONE_P709, _16_235, UNKNOWN, SRGB, BT709),
254   MAKE_COLOR_MAP (RGB_STUDIO_G22_NONE_P709, _16_235, UNKNOWN, SRGB, BT470BG),
255
256   /* 4) RGB_STUDIO_G22_NONE_P2020 */
257   MAKE_COLOR_MAP (RGB_STUDIO_G22_NONE_P2020, _16_235, UNKNOWN, BT709, BT2020),
258   MAKE_COLOR_MAP (RGB_STUDIO_G22_NONE_P2020, _16_235, UNKNOWN, BT601, BT2020),
259   MAKE_COLOR_MAP (RGB_STUDIO_G22_NONE_P2020, _16_235, UNKNOWN, BT2020_10,
260       BT2020),
261   MAKE_COLOR_MAP (RGB_STUDIO_G22_NONE_P2020, _16_235, UNKNOWN, BT2020_12,
262       BT2020),
263
264   /* 5) RGB_FULL_G2084_NONE_P2020 */
265   MAKE_COLOR_MAP (RGB_FULL_G2084_NONE_P2020, _0_255, UNKNOWN, SMPTE2084,
266       BT2020),
267
268   /* 6) RGB_STUDIO_G2084_NONE_P2020 */
269   MAKE_COLOR_MAP (RGB_STUDIO_G2084_NONE_P2020, _16_235, UNKNOWN, SMPTE2084,
270       BT2020),
271
272   /* 7) RGB_FULL_G22_NONE_P2020 */
273   MAKE_COLOR_MAP (RGB_FULL_G22_NONE_P2020, _0_255, UNKNOWN, BT709, BT2020),
274   MAKE_COLOR_MAP (RGB_FULL_G22_NONE_P2020, _0_255, UNKNOWN, BT601, BT2020),
275   MAKE_COLOR_MAP (RGB_FULL_G22_NONE_P2020, _0_255, UNKNOWN, BT2020_10, BT2020),
276   MAKE_COLOR_MAP (RGB_FULL_G22_NONE_P2020, _0_255, UNKNOWN, BT2020_12, BT2020),
277
278   /* 7-1) Approximation for RGB_FULL_G22_NONE_P2020 */
279   MAKE_COLOR_MAP (RGB_FULL_G22_NONE_P2020, _0_255, UNKNOWN, SRGB, BT2020),
280
281   /* 8) RGB_STUDIO_G24_NONE_P709 */
282   MAKE_COLOR_MAP (RGB_STUDIO_G24_NONE_P709, _16_235, UNKNOWN, SRGB, BT709),
283   MAKE_COLOR_MAP (RGB_STUDIO_G24_NONE_P709, _16_235, UNKNOWN, SRGB, BT470BG),
284
285   /* 9) RGB_STUDIO_G24_NONE_P2020 */
286   MAKE_COLOR_MAP (RGB_STUDIO_G24_NONE_P2020, _16_235, UNKNOWN, SRGB, BT2020),
287 };
288
289 static const GstDxgiColorSpace yuv_colorspace_map[] = {
290   /* 1) YCBCR_FULL_G22_NONE_P709_X601
291    * 2) YCBCR_STUDIO_G22_LEFT_P601
292    * 3) YCBCR_FULL_G22_LEFT_P601
293    * 4) YCBCR_STUDIO_G22_LEFT_P709
294    * 5) YCBCR_FULL_G22_LEFT_P709
295    * 6) YCBCR_STUDIO_G22_LEFT_P2020
296    * 7) YCBCR_FULL_G22_LEFT_P2020
297    * 8) YCBCR_STUDIO_G2084_LEFT_P2020
298    * 9) YCBCR_STUDIO_G22_TOPLEFT_P2020
299    * 10) YCBCR_STUDIO_G2084_TOPLEFT_P2020
300    * 11) YCBCR_STUDIO_GHLG_TOPLEFT_P2020
301    * 12) YCBCR_FULL_GHLG_TOPLEFT_P2020
302    * 13) YCBCR_STUDIO_G24_LEFT_P709
303    * 14) YCBCR_STUDIO_G24_LEFT_P2020
304    * 15) YCBCR_STUDIO_G24_TOPLEFT_P2020
305    *
306    * NOTE: BT470BG ~= BT709
307    */
308
309   /* 1) YCBCR_FULL_G22_NONE_P709_X601 */
310   MAKE_COLOR_MAP (YCBCR_FULL_G22_NONE_P709_X601, _0_255, BT601, BT709, BT709),
311   MAKE_COLOR_MAP (YCBCR_FULL_G22_NONE_P709_X601, _0_255, BT601, BT601, BT709),
312   MAKE_COLOR_MAP (YCBCR_FULL_G22_NONE_P709_X601, _0_255, BT601, BT2020_10,
313       BT709),
314   MAKE_COLOR_MAP (YCBCR_FULL_G22_NONE_P709_X601, _0_255, BT601, BT2020_12,
315       BT709),
316   MAKE_COLOR_MAP (YCBCR_FULL_G22_NONE_P709_X601, _0_255, BT601, BT709, BT470BG),
317   MAKE_COLOR_MAP (YCBCR_FULL_G22_NONE_P709_X601, _0_255, BT601, BT601, BT470BG),
318   MAKE_COLOR_MAP (YCBCR_FULL_G22_NONE_P709_X601, _0_255, BT601, BT2020_10,
319       BT470BG),
320   MAKE_COLOR_MAP (YCBCR_FULL_G22_NONE_P709_X601, _0_255, BT601, BT2020_12,
321       BT470BG),
322
323   /* 2) YCBCR_STUDIO_G22_LEFT_P601 */
324   MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P601, _16_235, BT601, BT601, SMPTE170M),
325   MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P601, _16_235, BT601, BT709, SMPTE170M),
326   MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P601, _16_235, BT601, BT2020_10,
327       SMPTE170M),
328   MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P601, _16_235, BT601, BT2020_12,
329       SMPTE170M),
330   MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P601, _16_235, BT601, BT601, SMPTE240M),
331   MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P601, _16_235, BT601, BT709, SMPTE240M),
332   MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P601, _16_235, BT601, BT2020_10,
333       SMPTE240M),
334   MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P601, _16_235, BT601, BT2020_12,
335       SMPTE240M),
336
337   /* 3) YCBCR_FULL_G22_LEFT_P601 */
338   MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P601, _0_255, BT601, BT601, SMPTE170M),
339   MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P601, _0_255, BT601, BT709, SMPTE170M),
340   MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P601, _0_255, BT601, BT2020_10,
341       SMPTE170M),
342   MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P601, _0_255, BT601, BT2020_12,
343       SMPTE170M),
344   MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P601, _0_255, BT601, BT601, SMPTE240M),
345   MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P601, _0_255, BT601, BT709, SMPTE240M),
346   MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P601, _0_255, BT601, BT2020_10,
347       SMPTE240M),
348   MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P601, _0_255, BT601, BT2020_12,
349       SMPTE240M),
350
351   /* 4) YCBCR_STUDIO_G22_LEFT_P709 */
352   MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P709, _16_235, BT709, BT709, BT709),
353   MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P709, _16_235, BT709, BT601, BT709),
354   MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P709, _16_235, BT709, BT2020_10,
355       BT709),
356   MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P709, _16_235, BT709, BT2020_12,
357       BT709),
358   MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P709, _16_235, BT709, BT709, BT470BG),
359   MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P709, _16_235, BT709, BT601, BT470BG),
360   MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P709, _16_235, BT709, BT2020_10,
361       BT470BG),
362   MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P709, _16_235, BT709, BT2020_12,
363       BT470BG),
364
365   /* 5) YCBCR_FULL_G22_LEFT_P709 */
366   MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P709, _0_255, BT709, BT709, BT709),
367   MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P709, _0_255, BT709, BT601, BT709),
368   MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P709, _0_255, BT709, BT2020_10, BT709),
369   MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P709, _0_255, BT709, BT2020_12, BT709),
370   MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P709, _0_255, BT709, BT709, BT470BG),
371   MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P709, _0_255, BT709, BT601, BT470BG),
372   MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P709, _0_255, BT709, BT2020_10, BT470BG),
373   MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P709, _0_255, BT709, BT2020_12, BT470BG),
374
375   /* 6) YCBCR_STUDIO_G22_LEFT_P2020 */
376   MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P2020, _16_235, BT2020, BT709, BT2020),
377   MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P2020, _16_235, BT2020, BT601, BT2020),
378   MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P2020, _16_235, BT2020, BT2020_10,
379       BT2020),
380   MAKE_COLOR_MAP (YCBCR_STUDIO_G22_LEFT_P2020, _16_235, BT2020, BT2020_12,
381       BT2020),
382
383   /* 7) YCBCR_FULL_G22_LEFT_P2020 */
384   MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P2020, _0_255, BT2020, BT709, BT2020),
385   MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P2020, _0_255, BT2020, BT601, BT2020),
386   MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P2020, _0_255, BT2020, BT2020_10,
387       BT2020),
388   MAKE_COLOR_MAP (YCBCR_FULL_G22_LEFT_P2020, _0_255, BT2020, BT2020_12,
389       BT2020),
390
391   /* 8) YCBCR_STUDIO_G2084_LEFT_P2020 */
392   MAKE_COLOR_MAP (YCBCR_STUDIO_G2084_LEFT_P2020, _16_235, BT2020, SMPTE2084,
393       BT2020),
394
395   /* 9) YCBCR_STUDIO_G22_TOPLEFT_P2020 */
396   MAKE_COLOR_MAP (YCBCR_STUDIO_G22_TOPLEFT_P2020, _16_235, BT2020, BT2020_10,
397       BT2020),
398   MAKE_COLOR_MAP (YCBCR_STUDIO_G22_TOPLEFT_P2020, _16_235, BT2020, BT2020_12,
399       BT2020),
400
401   /* 10) YCBCR_STUDIO_G2084_TOPLEFT_P2020 */
402   /* FIXME: check chroma-site to differentiate this from
403    * YCBCR_STUDIO_G2084_LEFT_P2020 */
404   MAKE_COLOR_MAP (YCBCR_STUDIO_G2084_TOPLEFT_P2020, _16_235, BT2020, SMPTE2084,
405       BT2020),
406
407   /* 11) YCBCR_STUDIO_GHLG_TOPLEFT_P2020 */
408   MAKE_COLOR_MAP (YCBCR_STUDIO_GHLG_TOPLEFT_P2020, _16_235, BT2020,
409       ARIB_STD_B67, BT2020),
410
411   /* 12) YCBCR_FULL_GHLG_TOPLEFT_P2020 */
412   MAKE_COLOR_MAP (YCBCR_FULL_GHLG_TOPLEFT_P2020, _0_255, BT2020, ARIB_STD_B67,
413       BT2020),
414
415   /* 13) YCBCR_STUDIO_G24_LEFT_P709 */
416   MAKE_COLOR_MAP (YCBCR_STUDIO_G24_LEFT_P709, _16_235, BT709, SRGB, BT709),
417
418   /* 14) YCBCR_STUDIO_G24_LEFT_P2020 */
419   MAKE_COLOR_MAP (YCBCR_STUDIO_G24_LEFT_P2020, _16_235, BT2020, SRGB, BT2020),
420
421   /* 15) YCBCR_STUDIO_G24_TOPLEFT_P2020 */
422   /* FIXME: check chroma-site to differentiate this from
423    * YCBCR_STUDIO_G24_LEFT_P2020 */
424   MAKE_COLOR_MAP (YCBCR_STUDIO_G24_TOPLEFT_P2020, _16_235, BT2020, SRGB,
425       BT2020),
426 };
427
428 #define SCORE_RANGE_MISMATCH 5
429 #define SCORE_MATRIX_MISMATCH 5
430 #define SCORE_TRANSFER_MISMATCH 5
431 #define SCORE_PRIMARY_MISMATCH 10
432
433 static gint
434 get_score (GstVideoInfo * info, const GstDxgiColorSpace * color_map,
435     gboolean is_yuv)
436 {
437   gint loss = 0;
438   GstVideoColorimetry *color = &info->colorimetry;
439
440   if (color->range != color_map->range)
441     loss += SCORE_RANGE_MISMATCH;
442
443   if (is_yuv && color->matrix != color_map->matrix)
444     loss += SCORE_MATRIX_MISMATCH;
445
446   if (color->transfer != color_map->transfer)
447     loss += SCORE_TRANSFER_MISMATCH;
448
449   if (color->primaries != color_map->primaries)
450     loss += SCORE_PRIMARY_MISMATCH;
451
452   return loss;
453 }
454
455 static const GstDxgiColorSpace *
456 gst_d3d11_video_info_to_dxgi_color_space_rgb (GstVideoInfo * info)
457 {
458   gint best_score = G_MAXINT;
459   gint score;
460   guint i;
461   const GstDxgiColorSpace *colorspace = NULL;
462
463   for (i = 0; i < G_N_ELEMENTS (rgb_colorspace_map); i++) {
464     score = get_score (info, &rgb_colorspace_map[i], FALSE);
465
466     if (score < best_score) {
467       best_score = score;
468       colorspace = &rgb_colorspace_map[i];
469
470       if (score == 0)
471         break;
472     }
473   }
474
475   return colorspace;
476 }
477
478 static const GstDxgiColorSpace *
479 gst_d3d11_video_info_to_dxgi_color_space_yuv (GstVideoInfo * info)
480 {
481   gint best_score = G_MAXINT;
482   gint score;
483   guint i;
484   const GstDxgiColorSpace *colorspace = NULL;
485
486   for (i = 0; i < G_N_ELEMENTS (yuv_colorspace_map); i++) {
487     score = get_score (info, &yuv_colorspace_map[i], TRUE);
488
489     if (score < best_score) {
490       best_score = score;
491       colorspace = &yuv_colorspace_map[i];
492
493       if (score == 0)
494         break;
495     }
496   }
497
498   return colorspace;
499 }
500
501 const GstDxgiColorSpace *
502 gst_d3d11_video_info_to_dxgi_color_space (GstVideoInfo * info)
503 {
504   g_return_val_if_fail (info != NULL, NULL);
505
506   if (GST_VIDEO_INFO_IS_RGB (info)) {
507     return gst_d3d11_video_info_to_dxgi_color_space_rgb (info);
508   } else if (GST_VIDEO_INFO_IS_YUV (info)) {
509     return gst_d3d11_video_info_to_dxgi_color_space_yuv (info);
510   }
511
512   return NULL;
513 }
514
515 const GstDxgiColorSpace *
516 gst_d3d11_find_swap_chain_color_space (GstVideoInfo * info,
517     IDXGISwapChain3 * swapchain)
518 {
519   const GstDxgiColorSpace *colorspace = NULL;
520   gint best_score = G_MAXINT;
521   guint i;
522   /* list of tested display color spaces */
523   static GST_DXGI_COLOR_SPACE_TYPE whitelist[] = {
524     GST_DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709,
525     GST_DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709,
526     GST_DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020,
527   };
528
529   g_return_val_if_fail (info != NULL, FALSE);
530   g_return_val_if_fail (swapchain != NULL, FALSE);
531
532   if (!GST_VIDEO_INFO_IS_RGB (info)) {
533     GST_WARNING ("Swapchain colorspace should be RGB format");
534     return FALSE;
535   }
536
537   for (i = 0; i < G_N_ELEMENTS (rgb_colorspace_map); i++) {
538     UINT can_support = 0;
539     HRESULT hr;
540     gint score;
541     gboolean valid = FALSE;
542     GST_DXGI_COLOR_SPACE_TYPE cur_type =
543         (GST_DXGI_COLOR_SPACE_TYPE) rgb_colorspace_map[i].dxgi_color_space_type;
544
545     for (guint j = 0; j < G_N_ELEMENTS (whitelist); j++) {
546       if (whitelist[j] == cur_type) {
547         valid = TRUE;
548         break;
549       }
550     }
551
552     if (!valid)
553       continue;
554
555     hr = swapchain->CheckColorSpaceSupport ((DXGI_COLOR_SPACE_TYPE) cur_type,
556         &can_support);
557
558     if (FAILED (hr))
559       continue;
560
561     if ((can_support & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT) ==
562         DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT) {
563       score = get_score (info, &rgb_colorspace_map[i], FALSE);
564
565       GST_DEBUG ("colorspace %d supported, score %d", cur_type, score);
566
567       if (score < best_score) {
568         best_score = score;
569         colorspace = &rgb_colorspace_map[i];
570       }
571     }
572   }
573
574   return colorspace;
575 }
576 #endif
577
578 static void
579 fill_staging_desc (const D3D11_TEXTURE2D_DESC * ref,
580     D3D11_TEXTURE2D_DESC * staging)
581 {
582   memset (staging, 0, sizeof (D3D11_TEXTURE2D_DESC));
583
584   staging->Width = ref->Width;
585   staging->Height = ref->Height;
586   staging->MipLevels = 1;
587   staging->Format = ref->Format;
588   staging->SampleDesc.Count = 1;
589   staging->ArraySize = 1;
590   staging->Usage = D3D11_USAGE_STAGING;
591   staging->CPUAccessFlags = (D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE);
592 }
593
594 GstBuffer *
595 gst_d3d11_allocate_staging_buffer_for (GstBuffer * buffer,
596     const GstVideoInfo * info, gboolean add_videometa)
597 {
598   GstD3D11Memory *dmem;
599   GstD3D11Device *device;
600   GstD3D11Allocator *alloc = NULL;
601   GstBuffer *staging_buffer = NULL;
602   gint stride[GST_VIDEO_MAX_PLANES] = { 0, };
603   gsize offset[GST_VIDEO_MAX_PLANES] = { 0, };
604   guint i;
605   gsize size = 0;
606   const GstD3D11Format *format;
607   D3D11_TEXTURE2D_DESC desc;
608
609   for (i = 0; i < gst_buffer_n_memory (buffer); i++) {
610     GstMemory *mem = gst_buffer_peek_memory (buffer, i);
611
612     if (!gst_is_d3d11_memory (mem)) {
613       GST_DEBUG ("Not a d3d11 memory");
614
615       return NULL;
616     }
617   }
618
619   dmem = (GstD3D11Memory *) gst_buffer_peek_memory (buffer, 0);
620   device = dmem->device;
621   format = gst_d3d11_device_format_from_gst (device,
622       GST_VIDEO_INFO_FORMAT (info));
623   if (!format) {
624     GST_ERROR ("Unknown d3d11 format");
625     return NULL;
626   }
627
628   alloc = (GstD3D11Allocator *) gst_allocator_find (GST_D3D11_MEMORY_NAME);
629   if (!alloc) {
630     GST_ERROR ("D3D11 allocator is not available");
631     return NULL;
632   }
633
634   staging_buffer = gst_buffer_new ();
635   for (i = 0; i < gst_buffer_n_memory (buffer); i++) {
636     D3D11_TEXTURE2D_DESC staging_desc;
637     GstD3D11Memory *mem = (GstD3D11Memory *) gst_buffer_peek_memory (buffer, i);
638     GstD3D11Memory *new_mem;
639
640     guint cur_stride = 0;
641
642     gst_d3d11_memory_get_texture_desc (mem, &desc);
643     fill_staging_desc (&desc, &staging_desc);
644
645     new_mem = (GstD3D11Memory *)
646         gst_d3d11_allocator_alloc (alloc, mem->device, &staging_desc);
647     if (!new_mem) {
648       GST_ERROR ("Failed to allocate memory");
649       goto error;
650     }
651
652     if (!gst_d3d11_memory_get_resource_stride (new_mem, &cur_stride) ||
653         cur_stride < staging_desc.Width) {
654       GST_ERROR ("Failed to calculate memory size");
655       gst_memory_unref (GST_MEMORY_CAST (mem));
656       goto error;
657     }
658
659     offset[i] = size;
660     stride[i] = cur_stride;
661     size += GST_MEMORY_CAST (new_mem)->size;
662
663     gst_buffer_append_memory (staging_buffer, GST_MEMORY_CAST (new_mem));
664   }
665
666   /* single texture semi-planar formats */
667   if (format->dxgi_format != DXGI_FORMAT_UNKNOWN &&
668       GST_VIDEO_INFO_N_PLANES (info) == 2) {
669     stride[1] = stride[0];
670     offset[1] = stride[0] * desc.Height;
671   }
672
673   gst_buffer_add_video_meta_full (staging_buffer, GST_VIDEO_FRAME_FLAG_NONE,
674       GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_WIDTH (info),
675       GST_VIDEO_INFO_HEIGHT (info), GST_VIDEO_INFO_N_PLANES (info),
676       offset, stride);
677
678   if (alloc)
679     gst_object_unref (alloc);
680
681   return staging_buffer;
682
683 error:
684   gst_clear_buffer (&staging_buffer);
685   gst_clear_object (&alloc);
686
687   return NULL;
688 }
689
690 static gboolean
691 gst_d3d11_buffer_copy_into_fallback (GstBuffer * dst, GstBuffer * src,
692     const GstVideoInfo * info)
693 {
694   GstVideoFrame in_frame, out_frame;
695   gboolean ret;
696
697   if (!gst_video_frame_map (&in_frame, (GstVideoInfo *) info, src,
698           (GstMapFlags) (GST_MAP_READ | GST_VIDEO_FRAME_MAP_FLAG_NO_REF)))
699     goto invalid_buffer;
700
701   if (!gst_video_frame_map (&out_frame, (GstVideoInfo *) info, dst,
702           (GstMapFlags) (GST_MAP_WRITE | GST_VIDEO_FRAME_MAP_FLAG_NO_REF))) {
703     gst_video_frame_unmap (&in_frame);
704     goto invalid_buffer;
705   }
706
707   ret = gst_video_frame_copy (&out_frame, &in_frame);
708
709   gst_video_frame_unmap (&in_frame);
710   gst_video_frame_unmap (&out_frame);
711
712   return ret;
713
714   /* ERRORS */
715 invalid_buffer:
716   {
717     GST_ERROR ("Invalid video buffer");
718     return FALSE;
719   }
720 }
721
722 gboolean
723 gst_d3d11_buffer_copy_into (GstBuffer * dst, GstBuffer * src,
724     const GstVideoInfo * info)
725 {
726   guint i;
727
728   g_return_val_if_fail (GST_IS_BUFFER (dst), FALSE);
729   g_return_val_if_fail (GST_IS_BUFFER (src), FALSE);
730   g_return_val_if_fail (info != NULL, FALSE);
731
732   if (gst_buffer_n_memory (dst) != gst_buffer_n_memory (src)) {
733     GST_LOG ("different memory layout, perform fallback copy");
734     return gst_d3d11_buffer_copy_into_fallback (dst, src, info);
735   }
736
737   if (!gst_is_d3d11_buffer (dst) || !gst_is_d3d11_buffer (src)) {
738     GST_LOG ("non-d3d11 memory, perform fallback copy");
739     return gst_d3d11_buffer_copy_into_fallback (dst, src, info);
740   }
741
742   for (i = 0; i < gst_buffer_n_memory (dst); i++) {
743     GstMemory *dst_mem, *src_mem;
744     GstD3D11Memory *dst_dmem, *src_dmem;
745     GstMapInfo dst_info;
746     GstMapInfo src_info;
747     ID3D11Resource *dst_texture, *src_texture;
748     ID3D11DeviceContext *device_context;
749     GstD3D11Device *device;
750     D3D11_BOX src_box = { 0, };
751     D3D11_TEXTURE2D_DESC dst_desc, src_desc;
752     guint dst_subidx, src_subidx;
753
754     dst_mem = gst_buffer_peek_memory (dst, i);
755     src_mem = gst_buffer_peek_memory (src, i);
756
757     dst_dmem = (GstD3D11Memory *) dst_mem;
758     src_dmem = (GstD3D11Memory *) src_mem;
759
760     device = dst_dmem->device;
761     if (device != src_dmem->device) {
762       GST_LOG ("different device, perform fallback copy");
763       return gst_d3d11_buffer_copy_into_fallback (dst, src, info);
764     }
765
766     gst_d3d11_memory_get_texture_desc (dst_dmem, &dst_desc);
767     gst_d3d11_memory_get_texture_desc (src_dmem, &src_desc);
768
769     if (dst_desc.Format != src_desc.Format) {
770       GST_WARNING ("different dxgi format");
771       return FALSE;
772     }
773
774     device_context = gst_d3d11_device_get_device_context_handle (device);
775
776     if (!gst_memory_map (dst_mem, &dst_info,
777             (GstMapFlags) (GST_MAP_WRITE | GST_MAP_D3D11))) {
778       GST_ERROR ("Cannot map dst d3d11 memory");
779       return FALSE;
780     }
781
782     if (!gst_memory_map (src_mem, &src_info,
783             (GstMapFlags) (GST_MAP_READ | GST_MAP_D3D11))) {
784       GST_ERROR ("Cannot map src d3d11 memory");
785       gst_memory_unmap (dst_mem, &dst_info);
786       return FALSE;
787     }
788
789     dst_texture = (ID3D11Resource *) dst_info.data;
790     src_texture = (ID3D11Resource *) src_info.data;
791
792     /* src/dst texture size might be different if padding was used.
793      * select smaller size */
794     src_box.left = 0;
795     src_box.top = 0;
796     src_box.front = 0;
797     src_box.back = 1;
798     src_box.right = MIN (src_desc.Width, dst_desc.Width);
799     src_box.bottom = MIN (src_desc.Height, dst_desc.Height);
800
801     dst_subidx = gst_d3d11_memory_get_subresource_index (dst_dmem);
802     src_subidx = gst_d3d11_memory_get_subresource_index (src_dmem);
803
804     gst_d3d11_device_lock (device);
805     device_context->CopySubresourceRegion (dst_texture, dst_subidx, 0, 0, 0,
806         src_texture, src_subidx, &src_box);
807     gst_d3d11_device_unlock (device);
808
809     gst_memory_unmap (src_mem, &src_info);
810     gst_memory_unmap (dst_mem, &dst_info);
811   }
812
813   return TRUE;
814 }
815
816 gboolean
817 gst_is_d3d11_buffer (GstBuffer * buffer)
818 {
819   guint i;
820   guint size;
821
822   g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
823
824   size = gst_buffer_n_memory (buffer);
825   if (size == 0)
826     return FALSE;
827
828   for (i = 0; i < size; i++) {
829     GstMemory *mem = gst_buffer_peek_memory (buffer, i);
830
831     if (!gst_is_d3d11_memory (mem))
832       return FALSE;
833   }
834
835   return TRUE;
836 }
837
838 gboolean
839 gst_d3d11_buffer_can_access_device (GstBuffer * buffer, ID3D11Device * device)
840 {
841   guint i;
842
843   g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
844   g_return_val_if_fail (device != NULL, FALSE);
845
846   if (!gst_is_d3d11_buffer (buffer)) {
847     GST_LOG ("Not a d3d11 buffer");
848     return FALSE;
849   }
850
851   for (i = 0; i < gst_buffer_n_memory (buffer); i++) {
852     GstD3D11Memory *mem = (GstD3D11Memory *) gst_buffer_peek_memory (buffer, i);
853     ID3D11Device *handle;
854
855     handle = gst_d3d11_device_get_device_handle (mem->device);
856     if (handle != device) {
857       GST_LOG ("D3D11 device is incompatible");
858       return FALSE;
859     }
860   }
861
862   return TRUE;
863 }
864
865 gboolean
866 gst_d3d11_buffer_map (GstBuffer * buffer, ID3D11Device * device,
867     GstMapInfo info[GST_VIDEO_MAX_PLANES], GstMapFlags flags)
868 {
869   GstMapFlags map_flags;
870   guint num_mapped = 0;
871
872   g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
873   g_return_val_if_fail (info != NULL, FALSE);
874
875   if (!gst_d3d11_buffer_can_access_device (buffer, device))
876     return FALSE;
877
878   map_flags = (GstMapFlags) (flags | GST_MAP_D3D11);
879
880   for (num_mapped = 0; num_mapped < gst_buffer_n_memory (buffer); num_mapped++) {
881     GstMemory *mem = gst_buffer_peek_memory (buffer, num_mapped);
882
883     if (!gst_memory_map (mem, &info[num_mapped], map_flags)) {
884       GST_ERROR ("Couldn't map memory");
885       goto error;
886     }
887   }
888
889   return TRUE;
890
891 error:
892   {
893     guint i;
894     for (i = 0; i < num_mapped; i++) {
895       GstMemory *mem = gst_buffer_peek_memory (buffer, i);
896       gst_memory_unmap (mem, &info[i]);
897     }
898
899     return FALSE;
900   }
901 }
902
903 gboolean
904 gst_d3d11_buffer_unmap (GstBuffer * buffer,
905     GstMapInfo info[GST_VIDEO_MAX_PLANES])
906 {
907   guint i;
908
909   g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
910   g_return_val_if_fail (info != NULL, FALSE);
911
912   for (i = 0; i < gst_buffer_n_memory (buffer); i++) {
913     GstMemory *mem = gst_buffer_peek_memory (buffer, i);
914
915     gst_memory_unmap (mem, &info[i]);
916   }
917
918   return TRUE;
919 }
920
921 guint
922 gst_d3d11_buffer_get_shader_resource_view (GstBuffer * buffer,
923     ID3D11ShaderResourceView * view[GST_VIDEO_MAX_PLANES])
924 {
925   guint i;
926   guint num_views = 0;
927
928   g_return_val_if_fail (GST_IS_BUFFER (buffer), 0);
929   g_return_val_if_fail (view != NULL, 0);
930
931   if (!gst_is_d3d11_buffer (buffer)) {
932     GST_ERROR ("Buffer contains non-d3d11 memory");
933     return 0;
934   }
935
936   for (i = 0; i < gst_buffer_n_memory (buffer); i++) {
937     GstD3D11Memory *mem = (GstD3D11Memory *) gst_buffer_peek_memory (buffer, i);
938     guint view_size;
939     guint j;
940
941     view_size = gst_d3d11_memory_get_shader_resource_view_size (mem);
942     if (!view_size) {
943       GST_LOG ("SRV is unavailable for memory index %d", i);
944       return 0;
945     }
946
947     for (j = 0; j < view_size; j++) {
948       if (num_views >= GST_VIDEO_MAX_PLANES) {
949         GST_ERROR ("Too many SRVs");
950         return 0;
951       }
952
953       view[num_views++] = gst_d3d11_memory_get_shader_resource_view (mem, j);
954     }
955   }
956
957   return num_views;
958 }
959
960 guint
961 gst_d3d11_buffer_get_render_target_view (GstBuffer * buffer,
962     ID3D11RenderTargetView * view[GST_VIDEO_MAX_PLANES])
963 {
964   guint i;
965   guint num_views = 0;
966
967   g_return_val_if_fail (GST_IS_BUFFER (buffer), 0);
968   g_return_val_if_fail (view != NULL, 0);
969
970   if (!gst_is_d3d11_buffer (buffer)) {
971     GST_ERROR ("Buffer contains non-d3d11 memory");
972     return 0;
973   }
974
975   for (i = 0; i < gst_buffer_n_memory (buffer); i++) {
976     GstD3D11Memory *mem = (GstD3D11Memory *) gst_buffer_peek_memory (buffer, i);
977     guint view_size;
978     guint j;
979
980     view_size = gst_d3d11_memory_get_render_target_view_size (mem);
981     if (!view_size) {
982       GST_LOG ("RTV is unavailable for memory index %d", i);
983       return 0;
984     }
985
986     for (j = 0; j < view_size; j++) {
987       if (num_views >= GST_VIDEO_MAX_PLANES) {
988         GST_ERROR ("Too many RTVs");
989         return 0;
990       }
991
992       view[num_views++] = gst_d3d11_memory_get_render_target_view (mem, j);
993     }
994   }
995
996   return num_views;
997 }
998
999 GstBufferPool *
1000 gst_d3d11_buffer_pool_new_with_options (GstD3D11Device * device,
1001     GstCaps * caps, GstD3D11AllocationParams * alloc_params,
1002     guint min_buffers, guint max_buffers)
1003 {
1004   GstBufferPool *pool;
1005   GstStructure *config;
1006   GstVideoInfo info;
1007
1008   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
1009   g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
1010   g_return_val_if_fail (alloc_params != NULL, NULL);
1011
1012   if (!gst_video_info_from_caps (&info, caps)) {
1013     GST_ERROR_OBJECT (device, "invalid caps");
1014     return NULL;
1015   }
1016
1017   pool = gst_d3d11_buffer_pool_new (device);
1018   config = gst_buffer_pool_get_config (pool);
1019   gst_buffer_pool_config_set_params (config,
1020       caps, GST_VIDEO_INFO_SIZE (&info), min_buffers, max_buffers);
1021
1022   gst_buffer_pool_config_set_d3d11_allocation_params (config, alloc_params);
1023
1024   gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
1025   if (!gst_buffer_pool_set_config (pool, config)) {
1026     GST_ERROR_OBJECT (pool, "Couldn't set config");
1027     gst_object_unref (pool);
1028     return NULL;
1029   }
1030
1031   return pool;
1032 }