d3d11: Update library doc
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / gst-libs / gst / d3d11 / gstd3d11converter.cpp
1 /* GStreamer
2  * Copyright (C) <2019> Seungha Yang <seungha.yang@navercorp.com>
3  * Copyright (C) <2019> Jeongki Kim <jeongki.kim@jeongki.kim>
4  * Copyright (C) <2022> Seungha Yang <seungha@centricular.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #  include <config.h>
24 #endif
25
26 #include "gstd3d11-private.h"
27 #include "gstd3d11converter.h"
28 #include "gstd3d11device.h"
29 #include "gstd3d11utils.h"
30 #include "gstd3d11memory.h"
31 #include "gstd3d11compile.h"
32 #include "gstd3d11bufferpool.h"
33 #include <wrl.h>
34 #include <string.h>
35 #include <math.h>
36
37 /**
38  * SECTION:gstd3d11converter
39  * @title: GstD3D11Converter
40  * @short_description: Direct3D11 video converter object
41  *
42  * This object performs various video conversion operation
43  * via Direct3D11 API
44  *
45  * Since: 1.22
46  */
47
48 GST_DEBUG_CATEGORY_STATIC (gst_d3d11_converter_debug);
49 #define GST_CAT_DEFAULT gst_d3d11_converter_debug
50
51 DEFINE_ENUM_FLAG_OPERATORS (GstD3D11ConverterBackend);
52
53 GType
54 gst_d3d11_converter_backend_get_type (void)
55 {
56   static GType type = 0;
57   static const GFlagsValue values[] = {
58     {GST_D3D11_CONVERTER_BACKEND_SHADER, "GST_D3D11_CONVERTER_BACKEND_SHADER",
59         "shader"},
60     {GST_D3D11_CONVERTER_BACKEND_VIDEO_PROCESSOR,
61         "GST_D3D11_CONVERTER_BACKEND_VIDEO_PROCESSOR", "video-processor"},
62     {0, nullptr, nullptr}
63   };
64
65   GST_D3D11_CALL_ONCE_BEGIN {
66     type = g_flags_register_static ("GstD3D11ConverterBackend", values);
67   } GST_D3D11_CALL_ONCE_END;
68
69   return type;
70 }
71
72 /* *INDENT-OFF* */
73 using namespace Microsoft::WRL;
74 /* *INDENT-ON* */
75
76 #define CONVERTER_MAX_QUADS 2
77 #define GAMMA_LUT_SIZE 4096
78
79 /* undefined symbols in ancient MinGW headers */
80 /* D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_METADATA_HDR10 */
81 #define FEATURE_CAPS_METADATA_HDR10 (0x800)
82 /* D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_ROTATION */
83 #define FEATURE_CAPS_ROTATION (0x40)
84 /* D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_MIRROR */
85 #define PROCESSOR_FEATURE_CAPS_MIRROR (0x200)
86
87 /* *INDENT-OFF* */
88 typedef struct
89 {
90   /* + 1 for 16bytes alignment  */
91   FLOAT coeffX[4];
92   FLOAT coeffY[4];
93   FLOAT coeffZ[4];
94   FLOAT offset[4];
95   FLOAT min[4];
96   FLOAT max[4];
97 } PSColorSpace;
98
99 typedef struct
100 {
101   PSColorSpace to_rgb_buf;
102   PSColorSpace to_yuv_buf;
103   PSColorSpace XYZ_convert_buf;
104   FLOAT alpha;
105   FLOAT padding[3];
106 } PSConstBuffer;
107
108 typedef struct
109 {
110   struct {
111     FLOAT x;
112     FLOAT y;
113     FLOAT z;
114   } position;
115   struct {
116     FLOAT u;
117     FLOAT v;
118   } texture;
119 } VertexData;
120
121 /* output struct */
122 static const gchar templ_OUTPUT_SINGLE_PLANE[] =
123     "struct PS_OUTPUT\n"
124     "{\n"
125     "  float4 Plane_0: SV_TARGET0;\n"
126     "};";
127
128 static const gchar templ_OUTPUT_TWO_PLANES[] =
129     "struct PS_OUTPUT\n"
130     "{\n"
131     "  float4 Plane_0: SV_TARGET0;\n"
132     "  float4 Plane_1: SV_TARGET1;\n"
133     "};";
134
135 static const gchar templ_OUTPUT_THREE_PLANES[] =
136     "struct PS_OUTPUT\n"
137     "{\n"
138     "  float4 Plane_0: SV_TARGET0;\n"
139     "  float4 Plane_1: SV_TARGET1;\n"
140     "  float4 Plane_2: SV_TARGET2;\n"
141     "};";
142
143 typedef struct
144 {
145   const gchar *output_template;
146   guint num_rtv;
147 } PSOutputType;
148
149 enum
150 {
151   OUTPUT_SINGLE_PLANE = 0,
152   OUTPUT_TWO_PLANES,
153   OUTPUT_THREE_PLANES,
154 };
155
156 static const PSOutputType output_types[] = {
157   {templ_OUTPUT_SINGLE_PLANE, 1},
158   {templ_OUTPUT_TWO_PLANES, 2},
159   {templ_OUTPUT_THREE_PLANES, 3},
160 };
161
162 /* colorspace conversion */
163 static const gchar templ_COLOR_SPACE_IDENTITY[] =
164     "{\n"
165     "  return sample;\n"
166     "}";
167
168 static const gchar templ_COLOR_SPACE_CONVERT[] =
169     "{\n"
170     "  float3 out_space;\n"
171     "  out_space.x = dot (coeff.CoeffX, sample);\n"
172     "  out_space.y = dot (coeff.CoeffY, sample);\n"
173     "  out_space.z = dot (coeff.CoeffZ, sample);\n"
174     "  out_space += coeff.Offset;\n"
175     "  return clamp (out_space, coeff.Min, coeff.Max);\n"
176     "}";
177
178 static const gchar templ_COLOR_SPACE_CONVERT_LUMA[] =
179     "{\n"
180     "  float3 out_space;\n"
181     "  out_space.x = dot (coeff.CoeffX, sample) + coeff.Offset.x;\n"
182     "  out_space.x = clamp (out_space.x, coeff.Min.x, coeff.Max.x);\n"
183     "  out_space.y = 0.5;\n"
184     "  out_space.z = 0.5;\n"
185     "  return out_space;\n"
186     "}";
187
188 static const gchar templ_COLOR_SPACE_CONVERT_CHROMA[] =
189     "{\n"
190     "  float3 out_space;\n"
191     "  out_space.x = 0.0;\n"
192     "  out_space.y = dot (coeff.CoeffY, sample) + coeff.Offset.y;\n"
193     "  out_space.z = dot (coeff.CoeffZ, sample) + coeff.Offset.z;\n"
194     "  return clamp (out_space, coeff.Min, coeff.Max);\n"
195     "}";
196
197 static const gchar templ_COLOR_SPACE_GRAY_TO_RGB[] =
198     "{\n"
199     "  return float3 (sample.x, sample.x, sample.x);\n"
200     "}";
201
202 static const gchar templ_COLOR_SPACE_GRAY_TO_RGB_RANGE_ADJUST[] =
203     "{\n"
204     "  float gray;\n"
205     "  gray = coeff.CoeffX.x * sample.x + coeff.Offset.x;\n"
206     "  gray = clamp (gray, coeff.Min.x, coeff.Max.x);\n"
207     "  return float3 (gray, gray, gray);\n"
208     "}";
209
210 /* sampling */
211 static const gchar templ_SAMPLE_DEFAULT[] =
212     "float4 sample_texture (float2 uv)\n"
213     "{\n"
214     "  return shaderTexture[0].Sample(samplerState, uv);\n"
215     "}";
216
217 static const gchar templ_SAMPLE_VUYA[] =
218     "float4 sample_texture (float2 uv)\n"
219     "{\n"
220     "  return shaderTexture[0].Sample(samplerState, uv).%c%c%c%c;\n"
221     "}";
222
223 static const gchar templ_SAMPLE_YUV_LUMA[] =
224     "float4 sample_texture (float2 uv)\n"
225     "{\n"
226     "  float4 sample;\n"
227     "  sample.x = shaderTexture[0].Sample(samplerState, uv).x;\n"
228     "  sample.y = 0.5;\n"
229     "  sample.z = 0.5;\n"
230     "  sample.a = 1.0;\n"
231     "  return sample;\n"
232     "}";
233
234 static const gchar templ_SAMPLE_YUV_LUMA_SCALED[] =
235     "float4 sample_texture (float2 uv)\n"
236     "{\n"
237     "  float4 sample;\n"
238     "  sample.x = saturate (shaderTexture[0].Sample(samplerState, uv).x * %d);\n"
239     "  sample.y = 0.5;\n"
240     "  sample.z = 0.5;\n"
241     "  sample.a = 1.0;\n"
242     "  return sample;\n"
243     "}";
244
245 static const gchar templ_SAMPLE_SEMI_PLANAR[] =
246     "float4 sample_texture (float2 uv)\n"
247     "{\n"
248     "  float4 sample;\n"
249     "  sample.x  = shaderTexture[0].Sample(samplerState, uv).x;\n"
250     "  sample.yz = shaderTexture[1].Sample(samplerState, uv).%c%c;\n"
251     "  sample.a = 1.0;\n"
252     "  return sample;\n"
253     "}";
254
255 static const gchar templ_SAMPLE_SEMI_PLANAR_CHROMA[] =
256     "float4 sample_texture (float2 uv)\n"
257     "{\n"
258     "  float4 sample;\n"
259     "  sample.x = 0.0;\n"
260     "  sample.yz = shaderTexture[1].Sample(samplerState, uv).%c%c;\n"
261     "  sample.a = 1.0;\n"
262     "  return sample;\n"
263     "}";
264
265 static const gchar templ_SAMPLE_PLANAR[] =
266     "float4 sample_texture (float2 uv)\n"
267     "{\n"
268     "  float3 sample;\n"
269     "  sample.x = shaderTexture[0].Sample(samplerState, uv).x;\n"
270     "  sample.%c = shaderTexture[1].Sample(samplerState, uv).x;\n"
271     "  sample.%c = shaderTexture[2].Sample(samplerState, uv).x;\n"
272     "  return float4 (saturate(sample * %d), 1.0);\n"
273     "}";
274
275 static const gchar templ_SAMPLE_PLANAR_CHROMA[] =
276     "float4 sample_texture (float2 uv)\n"
277     "{\n"
278     "  float3 sample;\n"
279     "  sample.x = 0.0;\n"
280     "  sample.%c = shaderTexture[1].Sample(samplerState, uv).x;\n"
281     "  sample.%c = shaderTexture[2].Sample(samplerState, uv).x;\n"
282     "  return float4 (saturate(sample * %d), 1.0);\n"
283     "}";
284
285 static const gchar templ_SAMPLE_YUV_PACKED[] =
286     "float4 sample_texture (float2 uv)\n"
287     "{\n"
288     "  float4 sample;\n"
289     "  sample.xyz = shaderTexture[0].Sample(samplerState, uv).%c%c%c;\n"
290     "  sample.a = 1.0;\n"
291     "  return sample;\n"
292     "}";
293
294 static const gchar templ_SAMPLE_GRAY[] =
295     "float4 sample_texture (float2 uv)\n"
296     "{\n"
297     "  float4 sample;\n"
298     "  sample.x = shaderTexture[0].Sample(samplerState, uv).x;\n"
299     "  sample.y = 0.5;\n"
300     "  sample.z = 0.5;\n"
301     "  sample.a = 1.0;\n"
302     "  return sample;\n"
303     "}";
304
305 static const gchar templ_SAMPLE_GRAY_CHROMA[] =
306     "float4 sample_texture (float2 uv)\n"
307     "{\n"
308     "  return float4 (0.0, 0.5, 0.5, 1.0);\n"
309     "}";
310
311 /* building output */
312 static const gchar templ_OUTPUT_DEFAULT[] =
313     "PS_OUTPUT build_output (float4 sample)\n"
314     "{\n"
315     "  PS_OUTPUT output;\n"
316     "  output.Plane_0 = sample;\n"
317     "  return output;\n"
318     "}";
319
320 static const gchar templ_OUTPUT_VUYA[] =
321     "PS_OUTPUT build_output (float4 sample)\n"
322     "{\n"
323     "  PS_OUTPUT output;\n"
324     "  float4 vuya;\n"
325     "  vuya.%c%c%c = sample.xyz;\n"
326     "  vuya.%c = sample.a;\n"
327     "  output.Plane_0 = vuya;\n"
328     "  return output;\n"
329     "}";
330
331 static const gchar templ_OUTPUT_LUMA[] =
332     "PS_OUTPUT build_output (float4 sample)\n"
333     "{\n"
334     "  PS_OUTPUT output;\n"
335     "  output.Plane_0 = float4 (sample.x, 0.0, 0.0, 1.0);\n"
336     "  return output;\n"
337     "}";
338
339 static const gchar templ_OUTPUT_CHROMA_SEMI_PLANAR[] =
340     "PS_OUTPUT build_output (float4 sample)\n"
341     "{\n"
342     "  PS_OUTPUT output;\n"
343     "  output.Plane_0 = float4 (sample.%c%c, 0.0, 1.0);\n"
344     "  return output;\n"
345     "}";
346
347 static const gchar templ_OUTPUT_LUMA_SCALED[] =
348     "PS_OUTPUT build_output (float4 sample)\n"
349     "{\n"
350     "  PS_OUTPUT output;\n"
351     "  output.Plane_0 = float4 (sample.x / %d, 0.0, 0.0, 1.0);\n"
352     "  return output;\n"
353     "}";
354
355 static const gchar templ_OUTPUT_CHROMA_PLANAR[] =
356     "PS_OUTPUT build_output (float4 sample)\n"
357     "{\n"
358     "  PS_OUTPUT output;\n"
359     "  output.Plane_0 = float4 (sample.%c, 0.0, 0.0, 1.0);\n"
360     "  output.Plane_1 = float4 (sample.%c, 0.0, 0.0, 1.0);\n"
361     "  return output;\n"
362     "}";
363
364 static const gchar templ_OUTPUT_CHROMA_PLANAR_SCALED[] =
365     "PS_OUTPUT build_output (float4 sample)\n"
366     "{\n"
367     "  PS_OUTPUT output;\n"
368     "  output.Plane_0 = float4 (sample.%c / %d, 0.0, 0.0, 1.0);\n"
369     "  output.Plane_1 = float4 (sample.%c / %d, 0.0, 0.0, 1.0);\n"
370     "  return output;\n"
371     "}";
372
373 static const gchar templ_OUTPUT_Y444[] =
374     "PS_OUTPUT build_output (float4 sample)\n"
375     "{\n"
376     "  PS_OUTPUT output;\n"
377     "  output.Plane_0 = float4 (sample.x, 0.0, 0.0, 1.0);\n"
378     "  output.Plane_1 = float4 (sample.y, 0.0, 0.0, 1.0);\n"
379     "  output.Plane_2 = float4 (sample.z, 0.0, 0.0, 1.0);\n"
380     "  return output;\n"
381     "}";
382
383 static const gchar templ_OUTPUT_Y444_SCALED[] =
384     "PS_OUTPUT build_output (float4 sample)\n"
385     "{\n"
386     "  PS_OUTPUT output;\n"
387     "  float3 scaled = sample.xyz / %d;\n"
388     "  output.Plane_0 = float4 (scaled.x, 0.0, 0.0, 1.0);\n"
389     "  output.Plane_1 = float4 (scaled.y, 0.0, 0.0, 1.0);\n"
390     "  output.Plane_2 = float4 (scaled.z, 0.0, 0.0, 1.0);\n"
391     "  return output;\n"
392     "}";
393
394 /* gamma and XYZ convert */
395 static const gchar templ_GAMMA_DECODE_IDENTITY[] =
396     "float3 gamma_decode (float3 sample)\n"
397     "{\n"
398     "  return sample;\n"
399     "}";
400
401 static const gchar templ_GAMMA_DECODE[] =
402     "float3 gamma_decode (float3 sample)\n"
403     "{\n"
404     "  float3 dec;\n"
405     "  dec.x = gammaDecLUT.Sample (samplerState, sample.x);\n"
406     "  dec.y = gammaDecLUT.Sample (samplerState, sample.y);\n"
407     "  dec.z = gammaDecLUT.Sample (samplerState, sample.z);\n"
408     "  return dec;\n"
409     "}";
410
411 static const gchar templ_GAMMA_ENCODE_IDENTITY[] =
412     "float3 gamma_encode (float3 sample)\n"
413     "{\n"
414     "  return sample;\n"
415     "}";
416
417 static const gchar templ_GAMMA_ENCODE[] =
418     "float3 gamma_encode (float3 sample)\n"
419     "{\n"
420     "  float3 enc;\n"
421     "  enc.x = gammaEncLUT.Sample (samplerState, sample.x);\n"
422     "  enc.y = gammaEncLUT.Sample (samplerState, sample.y);\n"
423     "  enc.z = gammaEncLUT.Sample (samplerState, sample.z);\n"
424     "  return enc;\n"
425     "}";
426
427 static const gchar templ_XYZ_CONVERT_IDENTITY[] =
428     "float3 XYZ_convert (float3 sample)\n"
429     "{\n"
430     "  return sample;\n"
431     "}";
432
433 static const gchar templ_XYZ_CONVERT[] =
434     "float3 XYZ_convert (float3 sample)\n"
435     "{\n"
436     "  float3 out_space;\n"
437     "  out_space.x = dot (primariesCoeff.CoeffX, sample);\n"
438     "  out_space.y = dot (primariesCoeff.CoeffY, sample);\n"
439     "  out_space.z = dot (primariesCoeff.CoeffZ, sample);\n"
440     "  return saturate (out_space);\n"
441     "}";
442
443 static const gchar templ_pixel_shader[] =
444     "struct PSColorSpace\n"
445     "{\n"
446     "  float3 CoeffX;\n"
447     "  float3 CoeffY;\n"
448     "  float3 CoeffZ;\n"
449     "  float3 Offset;\n"
450     "  float3 Min;\n"
451     "  float3 Max;\n"
452     "  float padding;\n"
453     "};\n"
454     "cbuffer PsConstBuffer : register(b0)\n"
455     "{\n"
456     /* RGB <-> YUV conversion */
457     "  PSColorSpace toRGBCoeff;\n"
458     "  PSColorSpace toYUVCoeff;\n"
459     "  PSColorSpace primariesCoeff;\n"
460     "  float AlphaMul;\n"
461     "};\n"
462     "Texture2D shaderTexture[4] : register(t0);\n"
463     "Texture1D<float> gammaDecLUT: register(t4);\n"
464     "Texture1D<float> gammaEncLUT: register(t5);\n"
465     "SamplerState samplerState : register(s0);\n"
466     "struct PS_INPUT\n"
467     "{\n"
468     "  float4 Position: SV_POSITION;\n"
469     "  float2 Texture: TEXCOORD;\n"
470     "};\n"
471     /* struct PS_OUTPUT */
472     "%s\n"
473     /* sample_texture() function */
474     "%s\n"
475     "float3 to_rgb (float3 sample, PSColorSpace coeff)\n"
476     "%s\n"
477     "float3 to_yuv (float3 sample, PSColorSpace coeff)\n"
478     "%s\n"
479     /* build_output() function */
480     "%s\n"
481     /* gamma_decode() function */
482     "%s\n"
483     /* gamma_encode() function */
484     "%s\n"
485     /* XYZ_convert() function */
486     "%s\n"
487     "PS_OUTPUT main(PS_INPUT input)\n"
488     "{\n"
489     "  float4 sample;\n"
490     "  sample = sample_texture (input.Texture);\n"
491     "  sample.a = saturate (sample.a * AlphaMul);\n"
492     "  sample.xyz = to_rgb (sample.xyz, toRGBCoeff);\n"
493     "  sample.xyz = gamma_decode (sample.xyz);\n"
494     "  sample.xyz = XYZ_convert (sample.xyz);\n"
495     "  sample.xyz = gamma_encode (sample.xyz);\n"
496     "  sample.xyz = to_yuv (sample.xyz, toYUVCoeff);\n"
497     "  return build_output (sample);\n"
498     "}\n";
499
500 static const gchar templ_vertex_shader[] =
501     "struct VS_INPUT\n"
502     "{\n"
503     "  float4 Position : POSITION;\n"
504     "  float2 Texture : TEXCOORD;\n"
505     "};\n"
506     "\n"
507     "struct VS_OUTPUT\n"
508     "{\n"
509     "  float4 Position: SV_POSITION;\n"
510     "  float2 Texture: TEXCOORD;\n"
511     "};\n"
512     "\n"
513     "VS_OUTPUT main(VS_INPUT input)\n"
514     "{\n"
515     "  return input;\n"
516     "}\n";
517 /* *INDENT-ON* */
518
519 typedef struct
520 {
521   const PSOutputType *ps_output[CONVERTER_MAX_QUADS];
522   gchar *sample_texture_func[CONVERTER_MAX_QUADS];
523   const gchar *to_rgb_func[CONVERTER_MAX_QUADS];
524   const gchar *to_yuv_func[CONVERTER_MAX_QUADS];
525   gchar *build_output_func[CONVERTER_MAX_QUADS];
526   const gchar *gamma_decode_func;
527   const gchar *gamma_encode_func;
528   const gchar *XYZ_convert_func;
529 } ConvertInfo;
530
531 enum
532 {
533   PROP_0,
534   PROP_SRC_X,
535   PROP_SRC_Y,
536   PROP_SRC_WIDTH,
537   PROP_SRC_HEIGHT,
538   PROP_DEST_X,
539   PROP_DEST_Y,
540   PROP_DEST_WIDTH,
541   PROP_DEST_HEIGHT,
542   PROP_ALPHA,
543   PROP_BLEND_STATE,
544   PROP_BLEND_FACTOR_RED,
545   PROP_BLEND_FACTOR_GREEN,
546   PROP_BLEND_FACTOR_BLUE,
547   PROP_BLEND_FACTOR_ALPHA,
548   PROP_BLEND_SAMPLE_MASK,
549   PROP_FILL_BORDER,
550   PROP_BORDER_COLOR,
551   PROP_SRC_MASTERING_DISPLAY_INFO,
552   PROP_SRC_CONTENT_LIGHT_LEVEL,
553   PROP_DEST_MASTERING_DISPLAY_INFO,
554   PROP_DEST_CONTENT_LIGHT_LEVEL,
555   PROP_VIDEO_DIRECTION,
556 };
557
558 struct _GstD3D11ConverterPrivate
559 {
560   GstVideoInfo in_info;
561   GstVideoInfo out_info;
562
563   GstD3D11Format in_d3d11_format;
564   GstD3D11Format out_d3d11_format;
565
566   guint num_input_view;
567   guint num_output_view;
568
569   GstD3D11ConverterBackend supported_backend;
570
571   ID3D11Buffer *vertex_buffer;
572   ID3D11Buffer *index_buffer;
573   ID3D11Buffer *const_buffer;
574   ID3D11VertexShader *vs;
575   ID3D11InputLayout *layout;
576   ID3D11SamplerState *linear_sampler;
577   ID3D11PixelShader *ps[CONVERTER_MAX_QUADS];
578   D3D11_VIEWPORT viewport[GST_VIDEO_MAX_PLANES];
579
580   ID3D11Texture1D *gamma_dec_lut;
581   ID3D11Texture1D *gamma_enc_lut;
582   ID3D11ShaderResourceView *gamma_dec_srv;
583   ID3D11ShaderResourceView *gamma_enc_srv;
584
585   D3D11_BLEND_DESC blend_desc;
586   ID3D11BlendState *blend;
587
588   gboolean fast_path;
589   gboolean do_primaries;
590
591   gint input_texture_width;
592   gint input_texture_height;
593   gboolean update_src_rect;
594   gboolean update_dest_rect;
595   gboolean update_alpha;
596
597   ConvertInfo convert_info;
598   PSConstBuffer const_data;
599
600   gboolean clear_background;
601   FLOAT clear_color[4][4];
602   GstD3D11ColorMatrix clear_color_matrix;
603
604   /* video processor */
605   D3D11_VIDEO_COLOR background_color;
606   ID3D11VideoDevice *video_device;
607   ID3D11VideoContext2 *video_context2;
608   ID3D11VideoContext1 *video_context;
609   ID3D11VideoProcessorEnumerator1 *enumerator;
610   ID3D11VideoProcessor *processor;
611   D3D11_VIDEO_PROCESSOR_CAPS processor_caps;
612   RECT src_rect;
613   RECT dest_rect;
614   RECT dest_full_rect;
615   gboolean processor_in_use;
616   gboolean processor_direction_not_supported;
617   gboolean enable_mirror;
618   gboolean flip_h;
619   gboolean flip_v;
620   gboolean enable_rotation;
621   D3D11_VIDEO_PROCESSOR_ROTATION rotation;
622
623   /* HDR10 */
624   gboolean have_in_hdr10;
625   gboolean have_out_hdr10;
626   gboolean in_hdr10_updated;
627   gboolean out_hdr10_updated;
628   DXGI_HDR_METADATA_HDR10 in_hdr10_meta;
629   DXGI_HDR_METADATA_HDR10 out_hdr10_meta;
630   gchar *in_mdcv_str;
631   gchar *out_mdcv_str;
632   gchar *in_cll_str;
633   gchar *out_cll_str;
634
635   GstVideoInfo fallback_info;
636   GstBuffer *fallback_inbuf;
637
638   GstVideoOrientationMethod video_direction;
639
640   SRWLOCK prop_lock;
641
642   /* properties */
643   gint src_x;
644   gint src_y;
645   gint src_width;
646   gint src_height;
647   gint dest_x;
648   gint dest_y;
649   gint dest_width;
650   gint dest_height;
651   gdouble alpha;
652   gfloat blend_factor[4];
653   guint blend_sample_mask;
654   gboolean fill_border;
655   guint64 border_color;
656 };
657
658 static void gst_d3d11_converter_set_property (GObject * object, guint prop_id,
659     const GValue * value, GParamSpec * pspec);
660 static void gst_d3d11_converter_get_property (GObject * object, guint prop_id,
661     GValue * value, GParamSpec * pspec);
662 static void gst_d3d11_converter_dispose (GObject * object);
663 static void gst_d3d11_converter_finalize (GObject * object);
664 static void
665 gst_d3d11_converter_calculate_border_color (GstD3D11Converter * self);
666
667 #define gst_d3d11_converter_parent_class parent_class
668 G_DEFINE_TYPE_WITH_PRIVATE (GstD3D11Converter, gst_d3d11_converter,
669     GST_TYPE_OBJECT);
670
671 static void
672 gst_d3d11_converter_class_init (GstD3D11ConverterClass * klass)
673 {
674   GObjectClass *object_class = G_OBJECT_CLASS (klass);
675   GParamFlags param_flags =
676       (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
677
678   object_class->set_property = gst_d3d11_converter_set_property;
679   object_class->get_property = gst_d3d11_converter_get_property;
680   object_class->dispose = gst_d3d11_converter_dispose;
681   object_class->finalize = gst_d3d11_converter_finalize;
682
683   g_object_class_install_property (object_class, PROP_SRC_X,
684       g_param_spec_int ("src-x", "Src-X",
685           "Source x poisition to start conversion", G_MININT, G_MAXINT, 0,
686           param_flags));
687   g_object_class_install_property (object_class, PROP_SRC_Y,
688       g_param_spec_int ("src-y", "Src-Y",
689           "Source y poisition to start conversion", G_MININT, G_MAXINT, 0,
690           param_flags));
691   g_object_class_install_property (object_class, PROP_SRC_WIDTH,
692       g_param_spec_int ("src-width", "Src-Width",
693           "Source width to convert", 0, G_MAXINT, 0, param_flags));
694   g_object_class_install_property (object_class, PROP_SRC_HEIGHT,
695       g_param_spec_int ("src-height", "Src-Height",
696           "Source height to convert", 0, G_MAXINT, 0, param_flags));
697   g_object_class_install_property (object_class, PROP_DEST_X,
698       g_param_spec_int ("dest-x", "Dest-X",
699           "x poisition in the destination frame", G_MININT, G_MAXINT, 0,
700           param_flags));
701   g_object_class_install_property (object_class, PROP_DEST_Y,
702       g_param_spec_int ("dest-y", "Dest-Y",
703           "y poisition in the destination frame", G_MININT, G_MAXINT, 0,
704           param_flags));
705   g_object_class_install_property (object_class, PROP_DEST_WIDTH,
706       g_param_spec_int ("dest-width", "Dest-Width",
707           "Width in the destination frame", 0, G_MAXINT, 0, param_flags));
708   g_object_class_install_property (object_class, PROP_DEST_HEIGHT,
709       g_param_spec_int ("dest-height", "Dest-Height",
710           "Height in the destination frame", 0, G_MAXINT, 0, param_flags));
711   g_object_class_install_property (object_class, PROP_ALPHA,
712       g_param_spec_double ("alpha", "Alpha",
713           "The alpha color value to use", 0, 1.0, 1.0, param_flags));
714   g_object_class_install_property (object_class, PROP_BLEND_STATE,
715       g_param_spec_pointer ("blend-state", "Blend State",
716           "ID3D11BlendState object to use", param_flags));
717   g_object_class_install_property (object_class, PROP_BLEND_FACTOR_RED,
718       g_param_spec_float ("blend-factor-red", "Blend Factor Red",
719           "Blend factor for red component", 0, 1.0, 1.0, param_flags));
720   g_object_class_install_property (object_class, PROP_BLEND_FACTOR_GREEN,
721       g_param_spec_float ("blend-factor-green", "Blend Factor Green",
722           "Blend factor for green component", 0, 1.0, 1.0, param_flags));
723   g_object_class_install_property (object_class, PROP_BLEND_FACTOR_BLUE,
724       g_param_spec_float ("blend-factor-blue", "Blend Factor Blue",
725           "Blend factor for blue component", 0, 1.0, 1.0, param_flags));
726   g_object_class_install_property (object_class, PROP_BLEND_FACTOR_ALPHA,
727       g_param_spec_float ("blend-factor-alpha", "Blend Factor Alpha",
728           "Blend factor for alpha component", 0, 1.0, 1.0, param_flags));
729   g_object_class_install_property (object_class, PROP_BLEND_SAMPLE_MASK,
730       g_param_spec_uint ("blend-sample-mask", "Blend Sample Mask",
731           "Blend sample mask", 0, 0xffffffff, 0xffffffff, param_flags));
732   g_object_class_install_property (object_class, PROP_FILL_BORDER,
733       g_param_spec_boolean ("fill-border", "Fill border",
734           "Fill border with \"border-color\" if destination rectangle does not "
735           "fill the complete destination image", FALSE, param_flags));
736   g_object_class_install_property (object_class, PROP_BORDER_COLOR,
737       g_param_spec_uint64 ("border-color", "Border Color",
738           "ARGB representation of the border color to use",
739           0, G_MAXUINT64, 0xffff000000000000, param_flags));
740   g_object_class_install_property (object_class,
741       PROP_SRC_MASTERING_DISPLAY_INFO,
742       g_param_spec_string ("src-mastering-display-info",
743           "Src Mastering Display Info",
744           "String representation of GstVideoMasteringDisplayInfo for source",
745           nullptr, param_flags));
746   g_object_class_install_property (object_class, PROP_SRC_CONTENT_LIGHT_LEVEL,
747       g_param_spec_string ("src-content-light-level",
748           "Src Content Light Level",
749           "String representation of GstVideoContentLightLevel for src",
750           nullptr, param_flags));
751   g_object_class_install_property (object_class,
752       PROP_DEST_MASTERING_DISPLAY_INFO,
753       g_param_spec_string ("dest-mastering-display-info",
754           "Dest Mastering Display Info",
755           "String representation of GstVideoMasteringDisplayInfo for dest",
756           nullptr, param_flags));
757   g_object_class_install_property (object_class, PROP_DEST_CONTENT_LIGHT_LEVEL,
758       g_param_spec_string ("dest-content-light-level",
759           "Src Content Light Level",
760           "String representation of GstVideoContentLightLevel for dest",
761           nullptr, param_flags));
762   g_object_class_install_property (object_class, PROP_VIDEO_DIRECTION,
763       g_param_spec_enum ("video-direction", "Video Direction",
764           "Video direction", GST_TYPE_VIDEO_ORIENTATION_METHOD,
765           GST_VIDEO_ORIENTATION_IDENTITY, param_flags));
766
767   GST_DEBUG_CATEGORY_INIT (gst_d3d11_converter_debug,
768       "d3d11converter", 0, "d3d11converter");
769 }
770
771 static void
772 gst_d3d11_converter_init (GstD3D11Converter * self)
773 {
774   self->priv = (GstD3D11ConverterPrivate *)
775       gst_d3d11_converter_get_instance_private (self);
776 }
777
778 static void
779 gst_d3d11_converter_dispose (GObject * object)
780 {
781   GstD3D11Converter *self = GST_D3D11_CONVERTER (object);
782   GstD3D11ConverterPrivate *priv = self->priv;
783
784   GST_D3D11_CLEAR_COM (priv->vertex_buffer);
785   GST_D3D11_CLEAR_COM (priv->index_buffer);
786   GST_D3D11_CLEAR_COM (priv->const_buffer);
787   GST_D3D11_CLEAR_COM (priv->vs);
788   GST_D3D11_CLEAR_COM (priv->layout);
789   GST_D3D11_CLEAR_COM (priv->linear_sampler);
790   GST_D3D11_CLEAR_COM (priv->gamma_dec_lut);
791   GST_D3D11_CLEAR_COM (priv->gamma_dec_srv);
792   GST_D3D11_CLEAR_COM (priv->gamma_enc_lut);
793   GST_D3D11_CLEAR_COM (priv->gamma_enc_srv);
794   GST_D3D11_CLEAR_COM (priv->video_device);
795   GST_D3D11_CLEAR_COM (priv->video_context2);
796   GST_D3D11_CLEAR_COM (priv->video_context);
797   GST_D3D11_CLEAR_COM (priv->enumerator);
798   GST_D3D11_CLEAR_COM (priv->processor);
799   GST_D3D11_CLEAR_COM (priv->blend);
800
801   for (guint i = 0; i < CONVERTER_MAX_QUADS; i++)
802     GST_D3D11_CLEAR_COM (priv->ps[i]);
803
804   gst_clear_buffer (&priv->fallback_inbuf);
805   gst_clear_object (&self->device);
806
807   G_OBJECT_CLASS (parent_class)->dispose (object);
808 }
809
810 static void
811 gst_d3d11_converter_finalize (GObject * object)
812 {
813   GstD3D11Converter *self = GST_D3D11_CONVERTER (object);
814   GstD3D11ConverterPrivate *priv = self->priv;
815
816   for (guint i = 0; i < CONVERTER_MAX_QUADS; i++) {
817     g_free (priv->convert_info.sample_texture_func[i]);
818     g_free (priv->convert_info.build_output_func[i]);
819   }
820
821   g_free (priv->in_mdcv_str);
822   g_free (priv->out_mdcv_str);
823   g_free (priv->in_cll_str);
824   g_free (priv->out_cll_str);
825
826   G_OBJECT_CLASS (parent_class)->finalize (object);
827 }
828
829 static void
830 update_src_rect (GstD3D11Converter * self, gint * old_val,
831     const GValue * new_val)
832 {
833   GstD3D11ConverterPrivate *priv = self->priv;
834   gint tmp;
835
836   tmp = g_value_get_int (new_val);
837   if (tmp != *old_val) {
838     priv->update_src_rect = TRUE;
839     *old_val = tmp;
840   }
841 }
842
843 static void
844 update_dest_rect (GstD3D11Converter * self, gint * old_val,
845     const GValue * new_val)
846 {
847   GstD3D11ConverterPrivate *priv = self->priv;
848   gint tmp;
849
850   tmp = g_value_get_int (new_val);
851   if (tmp != *old_val) {
852     priv->update_dest_rect = TRUE;
853     *old_val = tmp;
854   }
855 }
856
857 static void
858 update_alpha (GstD3D11Converter * self, gdouble * old_val,
859     const GValue * new_val)
860 {
861   GstD3D11ConverterPrivate *priv = self->priv;
862   gdouble tmp;
863
864   tmp = g_value_get_double (new_val);
865   if (tmp != *old_val) {
866     priv->update_alpha = TRUE;
867     *old_val = tmp;
868   }
869 }
870
871 static void
872 gst_d3d11_converter_set_property (GObject * object, guint prop_id,
873     const GValue * value, GParamSpec * pspec)
874 {
875   GstD3D11Converter *self = GST_D3D11_CONVERTER (object);
876   GstD3D11ConverterPrivate *priv = self->priv;
877
878   GstD3D11SRWLockGuard (&priv->prop_lock);
879   switch (prop_id) {
880     case PROP_SRC_X:
881       update_src_rect (self, &priv->src_x, value);
882       break;
883     case PROP_SRC_Y:
884       update_src_rect (self, &priv->src_y, value);
885       break;
886     case PROP_SRC_WIDTH:
887       update_src_rect (self, &priv->src_width, value);
888       break;
889     case PROP_SRC_HEIGHT:
890       update_src_rect (self, &priv->src_height, value);
891       break;
892     case PROP_DEST_X:
893       update_dest_rect (self, &priv->dest_x, value);
894       break;
895     case PROP_DEST_Y:
896       update_dest_rect (self, &priv->dest_y, value);
897       break;
898     case PROP_DEST_WIDTH:
899       update_dest_rect (self, &priv->dest_width, value);
900       break;
901     case PROP_DEST_HEIGHT:
902       update_dest_rect (self, &priv->dest_height, value);
903       break;
904     case PROP_ALPHA:
905       update_alpha (self, &priv->alpha, value);
906       priv->const_data.alpha = priv->alpha;
907       break;
908     case PROP_BLEND_STATE:{
909       ID3D11BlendState *blend =
910           (ID3D11BlendState *) g_value_get_pointer (value);
911       GST_D3D11_CLEAR_COM (priv->blend);
912       priv->blend = blend;
913       if (priv->blend) {
914         priv->blend->AddRef ();
915         priv->blend->GetDesc (&priv->blend_desc);
916       }
917       break;
918     }
919     case PROP_BLEND_FACTOR_RED:
920       priv->blend_factor[0] = g_value_get_float (value);
921       break;
922     case PROP_BLEND_FACTOR_GREEN:
923       priv->blend_factor[1] = g_value_get_float (value);
924       break;
925     case PROP_BLEND_FACTOR_BLUE:
926       priv->blend_factor[2] = g_value_get_float (value);
927       break;
928     case PROP_BLEND_FACTOR_ALPHA:
929       priv->blend_factor[3] = g_value_get_float (value);
930       break;
931     case PROP_BLEND_SAMPLE_MASK:
932       priv->blend_sample_mask = g_value_get_uint (value);
933       break;
934     case PROP_FILL_BORDER:{
935       gboolean fill_border = g_value_get_boolean (value);
936
937       if (fill_border != priv->fill_border) {
938         priv->update_dest_rect = TRUE;
939         priv->fill_border = fill_border;
940       }
941       break;
942     }
943     case PROP_BORDER_COLOR:{
944       guint64 border_color = g_value_get_uint64 (value);
945
946       if (border_color != priv->border_color) {
947         priv->border_color = border_color;
948         gst_d3d11_converter_calculate_border_color (self);
949       }
950       break;
951     }
952     case PROP_SRC_MASTERING_DISPLAY_INFO:
953       g_clear_pointer (&priv->in_mdcv_str, g_free);
954       priv->in_mdcv_str = g_value_dup_string (value);
955       priv->in_hdr10_updated = TRUE;
956       break;
957     case PROP_SRC_CONTENT_LIGHT_LEVEL:
958       g_clear_pointer (&priv->in_cll_str, g_free);
959       priv->in_cll_str = g_value_dup_string (value);
960       priv->in_hdr10_updated = TRUE;
961       break;
962     case PROP_DEST_MASTERING_DISPLAY_INFO:
963       g_clear_pointer (&priv->out_mdcv_str, g_free);
964       priv->out_mdcv_str = g_value_dup_string (value);
965       priv->out_hdr10_updated = TRUE;
966       break;
967     case PROP_DEST_CONTENT_LIGHT_LEVEL:
968       g_clear_pointer (&priv->out_cll_str, g_free);
969       priv->out_cll_str = g_value_dup_string (value);
970       priv->out_hdr10_updated = TRUE;
971       break;
972     case PROP_VIDEO_DIRECTION:{
973       GstVideoOrientationMethod video_direction =
974           (GstVideoOrientationMethod) g_value_get_enum (value);
975       if (video_direction != priv->video_direction) {
976         priv->video_direction = video_direction;
977         priv->update_src_rect = TRUE;
978       }
979       break;
980     }
981     default:
982       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
983       break;
984   }
985 }
986
987 static void
988 gst_d3d11_converter_get_property (GObject * object, guint prop_id,
989     GValue * value, GParamSpec * pspec)
990 {
991   GstD3D11Converter *self = GST_D3D11_CONVERTER (object);
992   GstD3D11ConverterPrivate *priv = self->priv;
993
994   GstD3D11SRWLockGuard (&priv->prop_lock);
995   switch (prop_id) {
996     case PROP_SRC_X:
997       g_value_set_int (value, priv->src_x);
998       break;
999     case PROP_SRC_Y:
1000       g_value_set_int (value, priv->src_y);
1001       break;
1002     case PROP_SRC_WIDTH:
1003       g_value_set_int (value, priv->src_width);
1004       break;
1005     case PROP_SRC_HEIGHT:
1006       g_value_set_int (value, priv->src_height);
1007       break;
1008     case PROP_DEST_X:
1009       g_value_set_int (value, priv->dest_x);
1010       break;
1011     case PROP_DEST_Y:
1012       g_value_set_int (value, priv->dest_y);
1013       break;
1014     case PROP_DEST_WIDTH:
1015       g_value_set_int (value, priv->dest_width);
1016       break;
1017     case PROP_DEST_HEIGHT:
1018       g_value_set_int (value, priv->dest_height);
1019       break;
1020     case PROP_ALPHA:
1021       g_value_set_double (value, priv->alpha);
1022       break;
1023     case PROP_BLEND_STATE:
1024       g_value_set_pointer (value, priv->blend);
1025       break;
1026     case PROP_BLEND_FACTOR_RED:
1027       g_value_set_float (value, priv->blend_factor[0]);
1028       break;
1029     case PROP_BLEND_FACTOR_GREEN:
1030       g_value_set_float (value, priv->blend_factor[1]);
1031       break;
1032     case PROP_BLEND_FACTOR_BLUE:
1033       g_value_set_float (value, priv->blend_factor[2]);
1034       break;
1035     case PROP_BLEND_FACTOR_ALPHA:
1036       g_value_set_float (value, priv->blend_factor[3]);
1037       break;
1038     case PROP_BLEND_SAMPLE_MASK:
1039       g_value_set_uint (value, priv->blend_sample_mask);
1040       break;
1041     case PROP_FILL_BORDER:
1042       g_value_set_boolean (value, priv->fill_border);
1043       break;
1044     case PROP_BORDER_COLOR:
1045       g_value_set_uint64 (value, priv->border_color);
1046       break;
1047     case PROP_SRC_MASTERING_DISPLAY_INFO:
1048       g_value_set_string (value, priv->in_mdcv_str);
1049       break;
1050     case PROP_SRC_CONTENT_LIGHT_LEVEL:
1051       g_value_set_string (value, priv->in_cll_str);
1052       break;
1053     case PROP_DEST_MASTERING_DISPLAY_INFO:
1054       g_value_set_string (value, priv->out_mdcv_str);
1055       break;
1056     case PROP_DEST_CONTENT_LIGHT_LEVEL:
1057       g_value_set_string (value, priv->out_cll_str);
1058       break;
1059     case PROP_VIDEO_DIRECTION:
1060       g_value_set_enum (value, priv->video_direction);
1061       break;
1062     default:
1063       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1064       break;
1065   }
1066 }
1067
1068 static gboolean
1069 get_packed_yuv_components (GstVideoFormat format, gchar * y, gchar * u,
1070     gchar * v)
1071 {
1072   switch (format) {
1073     case GST_VIDEO_FORMAT_Y410:
1074       *y = 'g';
1075       *u = 'r';
1076       *v = 'b';
1077       break;
1078     default:
1079       g_assert_not_reached ();
1080       return FALSE;
1081   }
1082
1083   return TRUE;
1084 }
1085
1086 static void
1087 get_planar_component (GstVideoFormat format, gchar * u, gchar * v,
1088     guint * scale)
1089 {
1090   switch (format) {
1091     case GST_VIDEO_FORMAT_I420_10LE:
1092     case GST_VIDEO_FORMAT_I422_10LE:
1093     case GST_VIDEO_FORMAT_Y444_10LE:
1094       *scale = (1 << 6);
1095       break;
1096     case GST_VIDEO_FORMAT_I420_12LE:
1097     case GST_VIDEO_FORMAT_I422_12LE:
1098     case GST_VIDEO_FORMAT_Y444_12LE:
1099       *scale = (1 << 4);
1100       break;
1101     default:
1102       *scale = 1;
1103       break;
1104   }
1105
1106   if (format == GST_VIDEO_FORMAT_YV12) {
1107     *u = 'z';
1108     *v = 'y';
1109   } else {
1110     *u = 'y';
1111     *v = 'z';
1112   }
1113 }
1114
1115 static void
1116 get_semi_planar_component (GstVideoFormat format, gchar * u, gchar * v,
1117     gboolean is_sampling)
1118 {
1119   if (format == GST_VIDEO_FORMAT_NV21) {
1120     if (is_sampling) {
1121       *u = 'y';
1122       *v = 'x';
1123     } else {
1124       *u = 'z';
1125       *v = 'y';
1126     }
1127   } else {
1128     if (is_sampling) {
1129       *u = 'x';
1130       *v = 'y';
1131     } else {
1132       *u = 'y';
1133       *v = 'z';
1134     }
1135   }
1136 }
1137
1138 static void
1139 get_vuya_component (GstVideoFormat format, gchar * y, gchar * u,
1140     gchar * v, gchar * a)
1141 {
1142   switch (format) {
1143     case GST_VIDEO_FORMAT_VUYA:
1144       if (y)
1145         *y = 'z';
1146       if (u)
1147         *u = 'y';
1148       if (v)
1149         *v = 'x';
1150       if (a)
1151         *a = 'w';
1152       break;
1153     case GST_VIDEO_FORMAT_AYUV:
1154     case GST_VIDEO_FORMAT_AYUV64:
1155       if (y)
1156         *y = 'g';
1157       if (u)
1158         *u = 'b';
1159       if (v)
1160         *v = 'a';
1161       if (a)
1162         *a = 'r';
1163       break;
1164     default:
1165       g_assert_not_reached ();
1166       break;
1167   }
1168 }
1169
1170 static gboolean
1171 gst_d3d11_color_convert_setup_shader (GstD3D11Converter * self,
1172     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1173 {
1174   GstD3D11ConverterPrivate *priv = self->priv;
1175   GstD3D11Device *device = self->device;
1176   HRESULT hr;
1177   D3D11_SAMPLER_DESC sampler_desc;
1178   D3D11_INPUT_ELEMENT_DESC input_desc[2];
1179   D3D11_BUFFER_DESC buffer_desc;
1180   D3D11_MAPPED_SUBRESOURCE map;
1181   VertexData *vertex_data;
1182   WORD *indices;
1183   ID3D11Device *device_handle;
1184   ID3D11DeviceContext *context_handle;
1185   ConvertInfo *cinfo = &priv->convert_info;
1186   ComPtr < ID3D11PixelShader > ps[CONVERTER_MAX_QUADS];
1187   ComPtr < ID3D11VertexShader > vs;
1188   ComPtr < ID3D11InputLayout > layout;
1189   ComPtr < ID3D11SamplerState > linear_sampler;
1190   ComPtr < ID3D11Buffer > const_buffer;
1191   ComPtr < ID3D11Buffer > vertex_buffer;
1192   ComPtr < ID3D11Buffer > index_buffer;
1193   gint i;
1194
1195   memset (&sampler_desc, 0, sizeof (sampler_desc));
1196   memset (input_desc, 0, sizeof (input_desc));
1197   memset (&buffer_desc, 0, sizeof (buffer_desc));
1198
1199   device_handle = gst_d3d11_device_get_device_handle (device);
1200   context_handle = gst_d3d11_device_get_device_context_handle (device);
1201
1202   /* bilinear filtering */
1203   sampler_desc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
1204   sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
1205   sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
1206   sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
1207   sampler_desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
1208   sampler_desc.MinLOD = 0;
1209   sampler_desc.MaxLOD = D3D11_FLOAT32_MAX;
1210
1211   hr = device_handle->CreateSamplerState (&sampler_desc, &linear_sampler);
1212   if (!gst_d3d11_result (hr, device)) {
1213     GST_ERROR_OBJECT (self,
1214         "Couldn't create samplerState state, hr: 0x%x", (guint) hr);
1215     return FALSE;
1216   }
1217
1218   for (i = 0; i < CONVERTER_MAX_QUADS; i++) {
1219     gchar *shader_code = nullptr;
1220
1221     if (cinfo->sample_texture_func[i]) {
1222       g_assert (cinfo->ps_output[i] != nullptr);
1223
1224       shader_code = g_strdup_printf (templ_pixel_shader,
1225           cinfo->ps_output[i]->output_template, cinfo->sample_texture_func[i],
1226           cinfo->to_rgb_func[i], cinfo->to_yuv_func[i],
1227           cinfo->build_output_func[i], cinfo->gamma_decode_func,
1228           cinfo->gamma_encode_func, cinfo->XYZ_convert_func);
1229
1230       hr = gst_d3d11_create_pixel_shader_simple (device,
1231           shader_code, "main", &ps[i]);
1232       g_free (shader_code);
1233       if (!gst_d3d11_result (hr, device)) {
1234         return FALSE;
1235       }
1236     }
1237   }
1238
1239   input_desc[0].SemanticName = "POSITION";
1240   input_desc[0].SemanticIndex = 0;
1241   input_desc[0].Format = DXGI_FORMAT_R32G32B32_FLOAT;
1242   input_desc[0].InputSlot = 0;
1243   input_desc[0].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
1244   input_desc[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
1245   input_desc[0].InstanceDataStepRate = 0;
1246
1247   input_desc[1].SemanticName = "TEXCOORD";
1248   input_desc[1].SemanticIndex = 0;
1249   input_desc[1].Format = DXGI_FORMAT_R32G32_FLOAT;
1250   input_desc[1].InputSlot = 0;
1251   input_desc[1].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
1252   input_desc[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
1253   input_desc[1].InstanceDataStepRate = 0;
1254
1255   hr = gst_d3d11_create_vertex_shader_simple (device, templ_vertex_shader,
1256       "main", input_desc, G_N_ELEMENTS (input_desc), &vs, &layout);
1257   if (!gst_d3d11_result (hr, device)) {
1258     GST_ERROR_OBJECT (self, "Couldn't vertex pixel shader");
1259     return FALSE;
1260   }
1261
1262   /* const buffer */
1263   G_STATIC_ASSERT (sizeof (PSConstBuffer) % 16 == 0);
1264   buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
1265   buffer_desc.ByteWidth = sizeof (PSConstBuffer);
1266   buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
1267   buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1268
1269   hr = device_handle->CreateBuffer (&buffer_desc, nullptr, &const_buffer);
1270   if (!gst_d3d11_result (hr, device)) {
1271     GST_ERROR_OBJECT (self,
1272         "Couldn't create constant buffer, hr: 0x%x", (guint) hr);
1273     return FALSE;
1274   }
1275
1276   /* setup vertext buffer and index buffer */
1277   buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
1278   buffer_desc.ByteWidth = sizeof (VertexData) * 4;
1279   buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
1280   buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1281
1282   hr = device_handle->CreateBuffer (&buffer_desc, nullptr, &vertex_buffer);
1283   if (!gst_d3d11_result (hr, device)) {
1284     GST_ERROR_OBJECT (self,
1285         "Couldn't create vertex buffer, hr: 0x%x", (guint) hr);
1286     return FALSE;
1287   }
1288
1289   buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
1290   buffer_desc.ByteWidth = sizeof (WORD) * 6;
1291   buffer_desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
1292   buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1293
1294   hr = device_handle->CreateBuffer (&buffer_desc, nullptr, &index_buffer);
1295   if (!gst_d3d11_result (hr, device)) {
1296     GST_ERROR ("Couldn't create index buffer, hr: 0x%x", (guint) hr);
1297     return FALSE;
1298   }
1299
1300   GstD3D11DeviceLockGuard lk (device);
1301   hr = context_handle->Map (const_buffer.Get (), 0, D3D11_MAP_WRITE_DISCARD, 0,
1302       &map);
1303   if (!gst_d3d11_result (hr, device)) {
1304     GST_ERROR_OBJECT (self,
1305         "Couldn't map constant buffer, hr: 0x%x", (guint) hr);
1306     return FALSE;
1307   }
1308
1309   memcpy (map.pData, &priv->const_data, sizeof (PSConstBuffer));
1310   context_handle->Unmap (const_buffer.Get (), 0);
1311
1312   hr = context_handle->Map (vertex_buffer.Get (), 0, D3D11_MAP_WRITE_DISCARD, 0,
1313       &map);
1314   if (!gst_d3d11_result (hr, device)) {
1315     GST_ERROR_OBJECT (self, "Couldn't map vertex buffer, hr: 0x%x", (guint) hr);
1316     return FALSE;
1317   }
1318
1319   vertex_data = (VertexData *) map.pData;
1320
1321   hr = context_handle->Map (index_buffer.Get (), 0, D3D11_MAP_WRITE_DISCARD, 0,
1322       &map);
1323   if (!gst_d3d11_result (hr, device)) {
1324     GST_ERROR_OBJECT (self, "Couldn't map index buffer, hr: 0x%x", (guint) hr);
1325     context_handle->Unmap (vertex_buffer.Get (), 0);
1326     return FALSE;
1327   }
1328
1329   indices = (WORD *) map.pData;
1330
1331   /* bottom left */
1332   vertex_data[0].position.x = -1.0f;
1333   vertex_data[0].position.y = -1.0f;
1334   vertex_data[0].position.z = 0.0f;
1335   vertex_data[0].texture.u = 0.0f;
1336   vertex_data[0].texture.v = 1.0f;
1337
1338   /* top left */
1339   vertex_data[1].position.x = -1.0f;
1340   vertex_data[1].position.y = 1.0f;
1341   vertex_data[1].position.z = 0.0f;
1342   vertex_data[1].texture.u = 0.0f;
1343   vertex_data[1].texture.v = 0.0f;
1344
1345   /* top right */
1346   vertex_data[2].position.x = 1.0f;
1347   vertex_data[2].position.y = 1.0f;
1348   vertex_data[2].position.z = 0.0f;
1349   vertex_data[2].texture.u = 1.0f;
1350   vertex_data[2].texture.v = 0.0f;
1351
1352   /* bottom right */
1353   vertex_data[3].position.x = 1.0f;
1354   vertex_data[3].position.y = -1.0f;
1355   vertex_data[3].position.z = 0.0f;
1356   vertex_data[3].texture.u = 1.0f;
1357   vertex_data[3].texture.v = 1.0f;
1358
1359   /* clockwise indexing */
1360   indices[0] = 0;               /* bottom left */
1361   indices[1] = 1;               /* top left */
1362   indices[2] = 2;               /* top right */
1363
1364   indices[3] = 3;               /* bottom right */
1365   indices[4] = 0;               /* bottom left  */
1366   indices[5] = 2;               /* top right */
1367
1368   context_handle->Unmap (vertex_buffer.Get (), 0);
1369   context_handle->Unmap (index_buffer.Get (), 0);
1370
1371   /* holds vertex buffer for crop rect update */
1372   priv->vertex_buffer = vertex_buffer.Detach ();
1373   priv->index_buffer = index_buffer.Detach ();
1374   priv->const_buffer = const_buffer.Detach ();
1375   priv->vs = vs.Detach ();
1376   priv->layout = layout.Detach ();
1377   priv->linear_sampler = linear_sampler.Detach ();
1378   priv->ps[0] = ps[0].Detach ();
1379   if (ps[1])
1380     priv->ps[1] = ps[1].Detach ();
1381
1382   priv->input_texture_width = GST_VIDEO_INFO_WIDTH (in_info);
1383   priv->input_texture_height = GST_VIDEO_INFO_HEIGHT (in_info);
1384
1385   priv->num_input_view = GST_VIDEO_INFO_N_PLANES (in_info);
1386   priv->num_output_view = GST_VIDEO_INFO_N_PLANES (out_info);
1387
1388   for (guint i = 0; i < GST_VIDEO_INFO_N_PLANES (out_info); i++) {
1389     priv->viewport[i].TopLeftX = 0;
1390     priv->viewport[i].TopLeftY = 0;
1391     priv->viewport[i].Width = GST_VIDEO_INFO_COMP_WIDTH (out_info, i);
1392     priv->viewport[i].Height = GST_VIDEO_INFO_COMP_HEIGHT (out_info, i);
1393     priv->viewport[i].MinDepth = 0.0f;
1394     priv->viewport[i].MaxDepth = 1.0f;
1395   }
1396
1397   return TRUE;
1398 }
1399
1400 static void
1401 gst_d3d11_converter_apply_orientation (GstD3D11Converter * self,
1402     VertexData * vertex_data, gfloat l, gfloat r, gfloat t, gfloat b)
1403 {
1404   GstD3D11ConverterPrivate *priv = self->priv;
1405   gfloat u[4], v[4];
1406
1407   /*
1408    * 1 (l, t) -- 2 (r, t)
1409    *     |            |
1410    * 0 (l, b) -- 3 (r, b)
1411    */
1412   u[0] = l;
1413   u[1] = l;
1414   u[2] = r;
1415   u[3] = r;
1416
1417   v[0] = b;
1418   v[1] = t;
1419   v[2] = t;
1420   v[3] = b;
1421
1422   switch (priv->video_direction) {
1423     case GST_VIDEO_ORIENTATION_IDENTITY:
1424     case GST_VIDEO_ORIENTATION_AUTO:
1425     case GST_VIDEO_ORIENTATION_CUSTOM:
1426     default:
1427       break;
1428     case GST_VIDEO_ORIENTATION_90R:
1429       /*
1430        * 1 (l, t) -- 2 (r, t)    1 (l, b) -- 2 (l, t)
1431        *     |           |    ->      |          |
1432        * 0 (l, b) -- 3 (r, b)    0 (r, b) -- 3 (r, t)
1433        */
1434       u[0] = r;
1435       u[1] = l;
1436       u[2] = l;
1437       u[3] = r;
1438
1439       v[0] = b;
1440       v[1] = b;
1441       v[2] = t;
1442       v[3] = t;
1443       break;
1444     case GST_VIDEO_ORIENTATION_180:
1445       /*
1446        * 1 (l, t) -- 2 (r, t)    1 (r, b) -- 2 (l, b)
1447        *     |           |    ->      |          |
1448        * 0 (l, b) -- 3 (r, b)    0 (r, t) -- 3 (l, t)
1449        */
1450       u[0] = r;
1451       u[1] = r;
1452       u[2] = l;
1453       u[3] = l;
1454
1455       v[0] = t;
1456       v[1] = b;
1457       v[2] = b;
1458       v[3] = t;
1459       break;
1460     case GST_VIDEO_ORIENTATION_90L:
1461       /*
1462        * 1 (l, t) -- 2 (r, t)    1 (r, t) -- 2 (r, b)
1463        *     |           |    ->      |          |
1464        * 0 (l, b) -- 3 (r, b)    0 (l, t) -- 3 (l, b)
1465        */
1466       u[0] = l;
1467       u[1] = r;
1468       u[2] = r;
1469       u[3] = l;
1470
1471       v[0] = t;
1472       v[1] = t;
1473       v[2] = b;
1474       v[3] = b;
1475       break;
1476     case GST_VIDEO_ORIENTATION_HORIZ:
1477       /*
1478        * 1 (l, t) -- 2 (r, t)    1 (r, t) -- 2 (l, t)
1479        *     |           |    ->      |          |
1480        * 0 (l, b) -- 3 (r, b)    0 (r, b) -- 3 (l, b)
1481        */
1482       u[0] = r;
1483       u[1] = r;
1484       u[2] = l;
1485       u[3] = l;
1486
1487       v[0] = b;
1488       v[1] = t;
1489       v[2] = t;
1490       v[3] = b;
1491       break;
1492     case GST_VIDEO_ORIENTATION_VERT:
1493       /*
1494        * 1 (l, t) -- 2 (r, t)    1 (l, b) -- 2 (r, b)
1495        *     |           |    ->      |          |
1496        * 0 (l, b) -- 3 (r, b)    0 (l, t) -- 3 (r, t)
1497        */
1498       u[0] = l;
1499       u[1] = l;
1500       u[2] = r;
1501       u[3] = r;
1502
1503       v[0] = t;
1504       v[1] = b;
1505       v[2] = b;
1506       v[3] = t;
1507       break;
1508     case GST_VIDEO_ORIENTATION_UL_LR:
1509       /*
1510        * 1 (l, t) -- 2 (r, t)    1 (l, t) -- 2 (l, b)
1511        *     |           |    ->      |          |
1512        * 0 (l, b) -- 3 (r, b)    0 (r, t) -- 3 (r, b)
1513        */
1514       u[0] = r;
1515       u[1] = l;
1516       u[2] = l;
1517       u[3] = r;
1518
1519       v[0] = t;
1520       v[1] = t;
1521       v[2] = b;
1522       v[3] = b;
1523       break;
1524     case GST_VIDEO_ORIENTATION_UR_LL:
1525       /*
1526        * 1 (l, t) -- 2 (r, t)    1 (r, b) -- 2 (r, t)
1527        *     |           |    ->      |          |
1528        * 0 (l, b) -- 3 (r, b)    0 (l, b) -- 3 (l, t)
1529        */
1530       u[0] = l;
1531       u[1] = r;
1532       u[2] = r;
1533       u[3] = l;
1534
1535       v[0] = b;
1536       v[1] = b;
1537       v[2] = t;
1538       v[3] = t;
1539       break;
1540   }
1541
1542   for (guint i = 0; i < 4; i++) {
1543     vertex_data[i].texture.u = u[i];
1544     vertex_data[i].texture.v = v[i];
1545   }
1546 }
1547
1548 static gboolean
1549 gst_d3d11_converter_update_src_rect (GstD3D11Converter * self)
1550 {
1551   GstD3D11ConverterPrivate *priv = self->priv;
1552   D3D11_MAPPED_SUBRESOURCE map;
1553   VertexData *vertex_data;
1554   ID3D11DeviceContext *context_handle;
1555   HRESULT hr;
1556   FLOAT u0, u1, v0, v1, off_u, off_v;
1557   gint texture_width = priv->input_texture_width;
1558   gint texture_height = priv->input_texture_height;
1559
1560   priv->update_src_rect = FALSE;
1561
1562   priv->src_rect.left = priv->src_x;
1563   priv->src_rect.top = priv->src_y;
1564   priv->src_rect.right = priv->src_x + priv->src_width;
1565   priv->src_rect.bottom = priv->src_y + priv->src_height;
1566
1567   if ((priv->supported_backend & GST_D3D11_CONVERTER_BACKEND_VIDEO_PROCESSOR)) {
1568     priv->processor_direction_not_supported = FALSE;
1569     priv->enable_mirror = FALSE;
1570     priv->flip_h = FALSE;
1571     priv->flip_v = FALSE;
1572     priv->enable_rotation = FALSE;
1573     priv->rotation = D3D11_VIDEO_PROCESSOR_ROTATION_IDENTITY;
1574
1575     /* filtering order is rotation -> mirror */
1576     switch (priv->video_direction) {
1577       case GST_VIDEO_ORIENTATION_IDENTITY:
1578       case GST_VIDEO_ORIENTATION_AUTO:
1579       case GST_VIDEO_ORIENTATION_CUSTOM:
1580       default:
1581         break;
1582       case GST_VIDEO_ORIENTATION_90R:
1583         priv->enable_rotation = TRUE;
1584         priv->rotation = D3D11_VIDEO_PROCESSOR_ROTATION_90;
1585         break;
1586       case GST_VIDEO_ORIENTATION_180:
1587         priv->enable_rotation = TRUE;
1588         priv->rotation = D3D11_VIDEO_PROCESSOR_ROTATION_180;
1589         break;
1590       case GST_VIDEO_ORIENTATION_90L:
1591         priv->enable_rotation = TRUE;
1592         priv->rotation = D3D11_VIDEO_PROCESSOR_ROTATION_270;
1593         break;
1594       case GST_VIDEO_ORIENTATION_HORIZ:
1595         priv->enable_mirror = TRUE;
1596         priv->flip_h = TRUE;
1597         break;
1598       case GST_VIDEO_ORIENTATION_VERT:
1599         priv->enable_mirror = TRUE;
1600         priv->flip_v = TRUE;
1601         break;
1602       case GST_VIDEO_ORIENTATION_UL_LR:
1603         priv->enable_rotation = TRUE;
1604         priv->rotation = D3D11_VIDEO_PROCESSOR_ROTATION_270;
1605         priv->enable_mirror = TRUE;
1606         priv->flip_v = TRUE;
1607         break;
1608       case GST_VIDEO_ORIENTATION_UR_LL:
1609         priv->enable_rotation = TRUE;
1610         priv->rotation = D3D11_VIDEO_PROCESSOR_ROTATION_90;
1611         priv->enable_mirror = TRUE;
1612         priv->flip_v = TRUE;
1613         break;
1614     }
1615
1616     if (priv->enable_rotation &&
1617         (priv->processor_caps.FeatureCaps & FEATURE_CAPS_ROTATION) == 0) {
1618       GST_WARNING_OBJECT (self, "Device does not support rotation");
1619       priv->processor_direction_not_supported = TRUE;
1620     }
1621
1622     if (priv->enable_mirror &&
1623         (priv->processor_caps.FeatureCaps & PROCESSOR_FEATURE_CAPS_MIRROR) ==
1624         0) {
1625       GST_WARNING_OBJECT (self, "Device does not support mirror");
1626       priv->processor_direction_not_supported = TRUE;
1627     }
1628   }
1629
1630   if ((priv->supported_backend & GST_D3D11_CONVERTER_BACKEND_SHADER) == 0)
1631     return TRUE;
1632
1633   context_handle = gst_d3d11_device_get_device_context_handle (self->device);
1634
1635   hr = context_handle->Map (priv->vertex_buffer, 0, D3D11_MAP_WRITE_DISCARD,
1636       0, &map);
1637
1638   if (!gst_d3d11_result (hr, self->device)) {
1639     GST_ERROR_OBJECT (self, "Couldn't map vertex buffer, hr: 0x%x", (guint) hr);
1640     return FALSE;
1641   }
1642
1643   GST_DEBUG_OBJECT (self, "Updating vertex buffer");
1644
1645   vertex_data = (VertexData *) map.pData;
1646   /*
1647    *  (u0, v0) -- (u1, v0)
1648    *     |            |
1649    *  (u0, v1) -- (u1, v1)
1650    */
1651   off_u = 0.5f / texture_width;
1652   off_v = 0.5f / texture_height;
1653
1654   if (priv->src_x > 0)
1655     u0 = (priv->src_x / (gfloat) texture_width) + off_u;
1656   else
1657     u0 = 0.0f;
1658
1659   if ((priv->src_x + priv->src_width) != texture_width)
1660     u1 = ((priv->src_x + priv->src_width) / (gfloat) texture_width) - off_u;
1661   else
1662     u1 = 1.0f;
1663
1664   if (priv->src_y > 0)
1665     v0 = (priv->src_y / (gfloat) texture_height) + off_v;
1666   else
1667     v0 = 0.0;
1668
1669   if ((priv->src_y + priv->src_height) != texture_height)
1670     v1 = ((priv->src_y + priv->src_height) / (gfloat) texture_height) - off_v;
1671   else
1672     v1 = 1.0f;
1673
1674   /* bottom left */
1675   vertex_data[0].position.x = -1.0f;
1676   vertex_data[0].position.y = -1.0f;
1677   vertex_data[0].position.z = 0.0f;
1678
1679   /* top left */
1680   vertex_data[1].position.x = -1.0f;
1681   vertex_data[1].position.y = 1.0f;
1682   vertex_data[1].position.z = 0.0f;
1683
1684   /* top right */
1685   vertex_data[2].position.x = 1.0f;
1686   vertex_data[2].position.y = 1.0f;
1687   vertex_data[2].position.z = 0.0f;
1688
1689   /* bottom right */
1690   vertex_data[3].position.x = 1.0f;
1691   vertex_data[3].position.y = -1.0f;
1692   vertex_data[3].position.z = 0.0f;
1693
1694   gst_d3d11_converter_apply_orientation (self, vertex_data, u0, u1, v0, v1);
1695
1696   context_handle->Unmap (priv->vertex_buffer, 0);
1697
1698   return TRUE;
1699 }
1700
1701 static gboolean
1702 gst_d3d11_converter_update_dest_rect (GstD3D11Converter * self)
1703 {
1704   GstD3D11ConverterPrivate *priv = self->priv;
1705   const GstVideoInfo *out_info = &priv->out_info;
1706
1707   priv->viewport[0].TopLeftX = priv->dest_x;
1708   priv->viewport[0].TopLeftY = priv->dest_y;
1709   priv->viewport[0].Width = priv->dest_width;
1710   priv->viewport[0].Height = priv->dest_height;
1711
1712   priv->dest_rect.left = priv->dest_x;
1713   priv->dest_rect.top = priv->dest_y;
1714   priv->dest_rect.right = priv->dest_x + priv->dest_width;
1715   priv->dest_rect.bottom = priv->dest_y + priv->dest_height;
1716
1717   GST_DEBUG_OBJECT (self,
1718       "Update viewport, TopLeftX: %f, TopLeftY: %f, Width: %f, Height %f",
1719       priv->viewport[0].TopLeftX, priv->viewport[0].TopLeftY,
1720       priv->viewport[0].Width, priv->viewport[0].Height);
1721
1722   if (priv->fill_border && (priv->dest_x != 0 || priv->dest_y != 0 ||
1723           priv->dest_width != out_info->width ||
1724           priv->dest_height != out_info->height)) {
1725     GST_DEBUG_OBJECT (self, "Enable background color");
1726     priv->clear_background = TRUE;
1727   } else {
1728     GST_DEBUG_OBJECT (self, "Disable background color");
1729     priv->clear_background = FALSE;
1730   }
1731
1732   switch (GST_VIDEO_INFO_FORMAT (&priv->out_info)) {
1733     case GST_VIDEO_FORMAT_NV12:
1734     case GST_VIDEO_FORMAT_NV21:
1735     case GST_VIDEO_FORMAT_P010_10LE:
1736     case GST_VIDEO_FORMAT_P012_LE:
1737     case GST_VIDEO_FORMAT_P016_LE:
1738     case GST_VIDEO_FORMAT_I420:
1739     case GST_VIDEO_FORMAT_YV12:
1740     case GST_VIDEO_FORMAT_I420_10LE:
1741     case GST_VIDEO_FORMAT_I420_12LE:
1742       priv->viewport[1].TopLeftX = priv->viewport[0].TopLeftX / 2;
1743       priv->viewport[1].TopLeftY = priv->viewport[0].TopLeftY / 2;
1744       priv->viewport[1].Width = priv->viewport[0].Width / 2;
1745       priv->viewport[1].Height = priv->viewport[0].Height / 2;
1746
1747       for (guint i = 2; i < GST_VIDEO_INFO_N_PLANES (&priv->out_info); i++)
1748         priv->viewport[i] = priv->viewport[1];
1749
1750       break;
1751     case GST_VIDEO_FORMAT_Y42B:
1752     case GST_VIDEO_FORMAT_I422_10LE:
1753     case GST_VIDEO_FORMAT_I422_12LE:
1754       priv->viewport[1].TopLeftX = priv->viewport[0].TopLeftX / 2;
1755       priv->viewport[1].TopLeftY = priv->viewport[0].TopLeftY;
1756       priv->viewport[1].Width = priv->viewport[0].Width / 2;
1757       priv->viewport[1].Height = priv->viewport[0].Height;
1758
1759       for (guint i = 2; i < GST_VIDEO_INFO_N_PLANES (&priv->out_info); i++)
1760         priv->viewport[i] = priv->viewport[1];
1761       break;
1762     case GST_VIDEO_FORMAT_Y444:
1763     case GST_VIDEO_FORMAT_Y444_10LE:
1764     case GST_VIDEO_FORMAT_Y444_12LE:
1765     case GST_VIDEO_FORMAT_Y444_16LE:
1766       for (guint i = 1; i < GST_VIDEO_INFO_N_PLANES (&priv->out_info); i++)
1767         priv->viewport[i] = priv->viewport[0];
1768       break;
1769     default:
1770       if (priv->num_output_view > 1) {
1771         g_assert_not_reached ();
1772         return FALSE;
1773       }
1774       break;
1775   }
1776
1777   priv->update_dest_rect = FALSE;
1778
1779   return TRUE;
1780 }
1781
1782 static gboolean
1783 gst_d3d11_converter_prepare_output (GstD3D11Converter * self,
1784     const GstVideoInfo * info)
1785 {
1786   GstD3D11ConverterPrivate *priv = self->priv;
1787   GstVideoFormat format = GST_VIDEO_INFO_FORMAT (info);
1788   ConvertInfo *cinfo = &priv->convert_info;
1789
1790   switch (format) {
1791       /* RGB */
1792     case GST_VIDEO_FORMAT_RGBA64_LE:
1793     case GST_VIDEO_FORMAT_RGB10A2_LE:
1794     case GST_VIDEO_FORMAT_BGRA:
1795     case GST_VIDEO_FORMAT_RGBA:
1796     case GST_VIDEO_FORMAT_BGRx:
1797     case GST_VIDEO_FORMAT_RGBx:
1798       cinfo->ps_output[0] = &output_types[OUTPUT_SINGLE_PLANE];
1799       cinfo->build_output_func[0] = g_strdup (templ_OUTPUT_DEFAULT);
1800       break;
1801       /* VUYA */
1802     case GST_VIDEO_FORMAT_VUYA:
1803     case GST_VIDEO_FORMAT_AYUV:
1804     case GST_VIDEO_FORMAT_AYUV64:{
1805       gchar y, u, v, a;
1806
1807       get_vuya_component (format, &y, &u, &v, &a);
1808       cinfo->ps_output[0] = &output_types[OUTPUT_SINGLE_PLANE];
1809       cinfo->build_output_func[0] =
1810           g_strdup_printf (templ_OUTPUT_VUYA, y, u, v, a);
1811       break;
1812     }
1813       /* semi-planar */
1814     case GST_VIDEO_FORMAT_NV12:
1815     case GST_VIDEO_FORMAT_NV21:
1816     case GST_VIDEO_FORMAT_P010_10LE:
1817     case GST_VIDEO_FORMAT_P012_LE:
1818     case GST_VIDEO_FORMAT_P016_LE:{
1819       gchar u, v;
1820
1821       get_semi_planar_component (format, &u, &v, FALSE);
1822       cinfo->ps_output[0] = &output_types[OUTPUT_SINGLE_PLANE];
1823       cinfo->build_output_func[0] = g_strdup (templ_OUTPUT_LUMA);
1824
1825       cinfo->ps_output[1] = &output_types[OUTPUT_SINGLE_PLANE];
1826       cinfo->build_output_func[1] =
1827           g_strdup_printf (templ_OUTPUT_CHROMA_SEMI_PLANAR, u, v);
1828       break;
1829     }
1830       /* planar */
1831     case GST_VIDEO_FORMAT_I420:
1832     case GST_VIDEO_FORMAT_YV12:
1833     case GST_VIDEO_FORMAT_I420_10LE:
1834     case GST_VIDEO_FORMAT_I420_12LE:
1835     case GST_VIDEO_FORMAT_Y42B:
1836     case GST_VIDEO_FORMAT_I422_10LE:
1837     case GST_VIDEO_FORMAT_I422_12LE:{
1838       gchar u, v;
1839       guint scale;
1840
1841       get_planar_component (format, &u, &v, &scale);
1842
1843       cinfo->ps_output[0] = &output_types[OUTPUT_SINGLE_PLANE];
1844       cinfo->ps_output[1] = &output_types[OUTPUT_TWO_PLANES];
1845
1846       if (info->finfo->depth[0] == 8) {
1847         cinfo->build_output_func[0] = g_strdup (templ_OUTPUT_LUMA);
1848         cinfo->build_output_func[1] =
1849             g_strdup_printf (templ_OUTPUT_CHROMA_PLANAR, u, v);
1850       } else {
1851         cinfo->build_output_func[0] = g_strdup_printf (templ_OUTPUT_LUMA_SCALED,
1852             scale);
1853         cinfo->build_output_func[1] =
1854             g_strdup_printf (templ_OUTPUT_CHROMA_PLANAR_SCALED,
1855             u, scale, v, scale);
1856       }
1857       break;
1858     }
1859     case GST_VIDEO_FORMAT_Y444:
1860     case GST_VIDEO_FORMAT_Y444_10LE:
1861     case GST_VIDEO_FORMAT_Y444_12LE:
1862     case GST_VIDEO_FORMAT_Y444_16LE:{
1863       gchar u, v;
1864       guint scale;
1865
1866       get_planar_component (format, &u, &v, &scale);
1867
1868       cinfo->ps_output[0] = &output_types[OUTPUT_THREE_PLANES];
1869       if (info->finfo->depth[0] == 8) {
1870         cinfo->build_output_func[0] = g_strdup (templ_OUTPUT_Y444);
1871       } else {
1872         cinfo->build_output_func[0] = g_strdup_printf (templ_OUTPUT_Y444_SCALED,
1873             scale);
1874       }
1875       break;
1876     }
1877     case GST_VIDEO_FORMAT_GRAY8:
1878     case GST_VIDEO_FORMAT_GRAY16_LE:
1879       cinfo->ps_output[0] = &output_types[OUTPUT_SINGLE_PLANE];
1880       cinfo->build_output_func[0] = g_strdup (templ_OUTPUT_LUMA);
1881       break;
1882     default:
1883       g_assert_not_reached ();
1884       return FALSE;
1885   }
1886
1887   return TRUE;
1888 }
1889
1890 static gboolean
1891 gst_d3d11_converter_prepare_sample_texture (GstD3D11Converter * self,
1892     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1893 {
1894   GstD3D11ConverterPrivate *priv = self->priv;
1895   GstVideoFormat format = GST_VIDEO_INFO_FORMAT (in_info);
1896   gboolean out_rgb = GST_VIDEO_INFO_IS_RGB (out_info);
1897   gboolean out_yuv = GST_VIDEO_INFO_IS_YUV (out_info);
1898   gboolean out_gray = GST_VIDEO_INFO_IS_GRAY (out_info);
1899   ConvertInfo *cinfo = &priv->convert_info;
1900
1901   switch (format) {
1902       /* RGB */
1903     case GST_VIDEO_FORMAT_RGBA64_LE:
1904     case GST_VIDEO_FORMAT_RGB10A2_LE:
1905     case GST_VIDEO_FORMAT_BGRA:
1906     case GST_VIDEO_FORMAT_RGBA:
1907     case GST_VIDEO_FORMAT_BGRx:
1908     case GST_VIDEO_FORMAT_RGBx:
1909       cinfo->sample_texture_func[0] = g_strdup (templ_SAMPLE_DEFAULT);
1910       if (cinfo->ps_output[1])
1911         cinfo->sample_texture_func[1] =
1912             g_strdup (cinfo->sample_texture_func[0]);
1913       break;
1914       /* VUYA */
1915     case GST_VIDEO_FORMAT_VUYA:
1916     case GST_VIDEO_FORMAT_AYUV:
1917     case GST_VIDEO_FORMAT_AYUV64:{
1918       gchar y, u, v, a;
1919
1920       get_vuya_component (format, &y, &u, &v, &a);
1921       cinfo->sample_texture_func[0] = g_strdup_printf (templ_SAMPLE_VUYA,
1922           y, u, v, a);
1923       if (cinfo->ps_output[1]) {
1924         cinfo->sample_texture_func[1] =
1925             g_strdup (cinfo->sample_texture_func[0]);
1926       }
1927       break;
1928     }
1929       /* semi-planar */
1930     case GST_VIDEO_FORMAT_NV12:
1931     case GST_VIDEO_FORMAT_NV21:
1932     case GST_VIDEO_FORMAT_P010_10LE:
1933     case GST_VIDEO_FORMAT_P012_LE:
1934     case GST_VIDEO_FORMAT_P016_LE:{
1935       gchar u, v;
1936
1937       get_semi_planar_component (format, &u, &v, TRUE);
1938       if (out_rgb) {
1939         cinfo->sample_texture_func[0] =
1940             g_strdup_printf (templ_SAMPLE_SEMI_PLANAR, u, v);
1941       } else if (out_gray) {
1942         cinfo->sample_texture_func[0] = g_strdup (templ_SAMPLE_YUV_LUMA);
1943       } else if (out_yuv) {
1944         if (GST_VIDEO_INFO_N_PLANES (out_info) == 1 ||
1945             cinfo->ps_output[0] == &output_types[OUTPUT_THREE_PLANES]) {
1946           /* YUV packed or Y444 */
1947           cinfo->sample_texture_func[0] =
1948               g_strdup_printf (templ_SAMPLE_SEMI_PLANAR, u, v);
1949         } else {
1950           if (priv->fast_path) {
1951             cinfo->sample_texture_func[0] = g_strdup (templ_SAMPLE_YUV_LUMA);
1952             cinfo->sample_texture_func[1] =
1953                 g_strdup_printf (templ_SAMPLE_SEMI_PLANAR_CHROMA, u, v);
1954           } else {
1955             cinfo->sample_texture_func[0] =
1956                 g_strdup_printf (templ_SAMPLE_SEMI_PLANAR, u, v);
1957             cinfo->sample_texture_func[1] =
1958                 g_strdup (cinfo->sample_texture_func[0]);
1959           }
1960         }
1961       } else {
1962         g_assert_not_reached ();
1963         return FALSE;
1964       }
1965       break;
1966     }
1967       /* planar */
1968     case GST_VIDEO_FORMAT_I420:
1969     case GST_VIDEO_FORMAT_YV12:
1970     case GST_VIDEO_FORMAT_I420_10LE:
1971     case GST_VIDEO_FORMAT_I420_12LE:
1972     case GST_VIDEO_FORMAT_Y42B:
1973     case GST_VIDEO_FORMAT_I422_10LE:
1974     case GST_VIDEO_FORMAT_I422_12LE:
1975     case GST_VIDEO_FORMAT_Y444:
1976     case GST_VIDEO_FORMAT_Y444_10LE:
1977     case GST_VIDEO_FORMAT_Y444_12LE:
1978     case GST_VIDEO_FORMAT_Y444_16LE:{
1979       gchar u, v;
1980       guint scale;
1981
1982       get_planar_component (format, &u, &v, &scale);
1983       if (out_rgb) {
1984         cinfo->sample_texture_func[0] = g_strdup_printf (templ_SAMPLE_PLANAR,
1985             u, v, scale);
1986       } else if (out_gray) {
1987         cinfo->sample_texture_func[0] =
1988             g_strdup_printf (templ_SAMPLE_YUV_LUMA_SCALED, scale);
1989       } else if (out_yuv) {
1990         if (GST_VIDEO_INFO_N_PLANES (out_info) == 1 ||
1991             cinfo->ps_output[0] == &output_types[OUTPUT_THREE_PLANES]) {
1992           /* YUV packed or Y444 */
1993           cinfo->sample_texture_func[0] = g_strdup_printf (templ_SAMPLE_PLANAR,
1994               u, v, scale);
1995         } else {
1996           if (priv->fast_path) {
1997             cinfo->sample_texture_func[0] =
1998                 g_strdup_printf (templ_SAMPLE_YUV_LUMA_SCALED, scale);
1999             cinfo->sample_texture_func[1] =
2000                 g_strdup_printf (templ_SAMPLE_PLANAR_CHROMA, u, v, scale);
2001           } else {
2002             cinfo->sample_texture_func[0] =
2003                 g_strdup_printf (templ_SAMPLE_PLANAR, u, v, scale);
2004             cinfo->sample_texture_func[1] =
2005                 g_strdup (cinfo->sample_texture_func[0]);
2006           }
2007         }
2008       } else {
2009         g_assert_not_reached ();
2010         return FALSE;
2011       }
2012       break;
2013     }
2014       /* yuv packed */
2015     case GST_VIDEO_FORMAT_Y410:{
2016       gchar y, u, v;
2017
2018       get_packed_yuv_components (format, &y, &u, &v);
2019       cinfo->sample_texture_func[0] = g_strdup_printf (templ_SAMPLE_YUV_PACKED,
2020           y, u, v);
2021       if (cinfo->ps_output[1]) {
2022         cinfo->sample_texture_func[1] =
2023             g_strdup (cinfo->sample_texture_func[0]);
2024       }
2025       break;
2026     }
2027     case GST_VIDEO_FORMAT_GRAY8:
2028     case GST_VIDEO_FORMAT_GRAY16_LE:
2029       cinfo->sample_texture_func[0] = g_strdup (templ_SAMPLE_GRAY);
2030       if (cinfo->ps_output[1])
2031         cinfo->sample_texture_func[1] = g_strdup (templ_SAMPLE_GRAY_CHROMA);
2032       break;
2033     default:
2034       g_assert_not_reached ();
2035       return FALSE;
2036   }
2037
2038   return TRUE;
2039 }
2040
2041 static const gchar *
2042 get_color_range_name (GstVideoColorRange range)
2043 {
2044   switch (range) {
2045     case GST_VIDEO_COLOR_RANGE_0_255:
2046       return "FULL";
2047     case GST_VIDEO_COLOR_RANGE_16_235:
2048       return "STUDIO";
2049     default:
2050       break;
2051   }
2052
2053   return "UNKNOWN";
2054 }
2055
2056 static void
2057 convert_info_gray_to_yuv (const GstVideoInfo * gray, GstVideoInfo * yuv)
2058 {
2059   GstVideoInfo tmp;
2060
2061   if (GST_VIDEO_INFO_IS_YUV (gray)) {
2062     *yuv = *gray;
2063     return;
2064   }
2065
2066   if (gray->finfo->depth[0] == 8) {
2067     gst_video_info_set_format (&tmp,
2068         GST_VIDEO_FORMAT_Y444, gray->width, gray->height);
2069   } else {
2070     gst_video_info_set_format (&tmp,
2071         GST_VIDEO_FORMAT_Y444_16LE, gray->width, gray->height);
2072   }
2073
2074   tmp.colorimetry.range = gray->colorimetry.range;
2075   if (tmp.colorimetry.range == GST_VIDEO_COLOR_RANGE_UNKNOWN)
2076     tmp.colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
2077
2078   tmp.colorimetry.primaries = gray->colorimetry.primaries;
2079   if (tmp.colorimetry.primaries == GST_VIDEO_COLOR_PRIMARIES_UNKNOWN)
2080     tmp.colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
2081
2082   tmp.colorimetry.transfer = gray->colorimetry.transfer;
2083   if (tmp.colorimetry.transfer == GST_VIDEO_TRANSFER_UNKNOWN)
2084     tmp.colorimetry.transfer = GST_VIDEO_TRANSFER_BT709;
2085
2086   tmp.colorimetry.matrix = gray->colorimetry.matrix;
2087   if (tmp.colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_UNKNOWN)
2088     tmp.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT709;
2089
2090   *yuv = tmp;
2091 }
2092
2093 static void
2094 convert_info_gray_to_rgb (const GstVideoInfo * gray, GstVideoInfo * rgb)
2095 {
2096   GstVideoInfo tmp;
2097
2098   if (GST_VIDEO_INFO_IS_RGB (gray)) {
2099     *rgb = *gray;
2100     return;
2101   }
2102
2103   if (gray->finfo->depth[0] == 8) {
2104     gst_video_info_set_format (&tmp,
2105         GST_VIDEO_FORMAT_RGBA, gray->width, gray->height);
2106   } else {
2107     gst_video_info_set_format (&tmp,
2108         GST_VIDEO_FORMAT_RGBA64_LE, gray->width, gray->height);
2109   }
2110
2111   tmp.colorimetry.range = gray->colorimetry.range;
2112   if (tmp.colorimetry.range == GST_VIDEO_COLOR_RANGE_UNKNOWN)
2113     tmp.colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
2114
2115   tmp.colorimetry.primaries = gray->colorimetry.primaries;
2116   if (tmp.colorimetry.primaries == GST_VIDEO_COLOR_PRIMARIES_UNKNOWN)
2117     tmp.colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
2118
2119   tmp.colorimetry.transfer = gray->colorimetry.transfer;
2120   if (tmp.colorimetry.transfer == GST_VIDEO_TRANSFER_UNKNOWN)
2121     tmp.colorimetry.transfer = GST_VIDEO_TRANSFER_BT709;
2122
2123   *rgb = tmp;
2124 }
2125
2126 static gboolean
2127 gst_d3d11_converter_prepare_colorspace_fast (GstD3D11Converter * self,
2128     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
2129 {
2130   GstD3D11ConverterPrivate *priv = self->priv;
2131   const GstVideoColorimetry *in_color = &in_info->colorimetry;
2132   const GstVideoColorimetry *out_color = &out_info->colorimetry;
2133   ConvertInfo *cinfo = &priv->convert_info;
2134   PSColorSpace *to_rgb_buf = &priv->const_data.to_rgb_buf;
2135   PSColorSpace *to_yuv_buf = &priv->const_data.to_yuv_buf;
2136   GstD3D11ColorMatrix to_rgb_matrix;
2137   GstD3D11ColorMatrix to_yuv_matrix;
2138   gchar *matrix_dump;
2139
2140   memset (&to_rgb_matrix, 0, sizeof (GstD3D11ColorMatrix));
2141   memset (&to_yuv_matrix, 0, sizeof (GstD3D11ColorMatrix));
2142
2143   for (guint i = 0; i < 2; i++) {
2144     cinfo->to_rgb_func[i] = templ_COLOR_SPACE_IDENTITY;
2145     cinfo->to_yuv_func[i] = templ_COLOR_SPACE_IDENTITY;
2146   }
2147
2148   cinfo->gamma_decode_func = templ_GAMMA_DECODE_IDENTITY;
2149   cinfo->gamma_encode_func = templ_GAMMA_ENCODE_IDENTITY;
2150   cinfo->XYZ_convert_func = templ_XYZ_CONVERT_IDENTITY;
2151
2152   if (GST_VIDEO_INFO_IS_RGB (in_info)) {
2153     if (GST_VIDEO_INFO_IS_RGB (out_info)) {
2154       if (in_color->range == out_color->range) {
2155         GST_DEBUG_OBJECT (self, "RGB -> RGB without colorspace conversion");
2156       } else {
2157         if (!gst_d3d11_color_range_adjust_matrix_unorm (in_info, out_info,
2158                 &to_rgb_matrix)) {
2159           GST_ERROR_OBJECT (self, "Failed to get RGB range adjust matrix");
2160           return FALSE;
2161         }
2162
2163         matrix_dump = gst_d3d11_dump_color_matrix (&to_rgb_matrix);
2164         GST_DEBUG_OBJECT (self, "RGB range adjust %s -> %s\n%s",
2165             get_color_range_name (in_color->range),
2166             get_color_range_name (out_color->range), matrix_dump);
2167         g_free (matrix_dump);
2168
2169         cinfo->to_rgb_func[0] = templ_COLOR_SPACE_CONVERT;
2170       }
2171     } else {
2172       GstVideoInfo yuv_info;
2173
2174       convert_info_gray_to_yuv (out_info, &yuv_info);
2175
2176       if (yuv_info.colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_UNKNOWN ||
2177           yuv_info.colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_RGB) {
2178         GST_WARNING_OBJECT (self, "Invalid matrix is detected");
2179         yuv_info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT709;
2180       }
2181
2182       if (!gst_d3d11_rgb_to_yuv_matrix_unorm (in_info,
2183               &yuv_info, &to_yuv_matrix)) {
2184         GST_ERROR_OBJECT (self, "Failed to get RGB -> YUV transform matrix");
2185         return FALSE;
2186       }
2187
2188       matrix_dump = gst_d3d11_dump_color_matrix (&to_yuv_matrix);
2189       GST_DEBUG_OBJECT (self, "RGB -> YUV matrix:\n%s", matrix_dump);
2190       g_free (matrix_dump);
2191
2192       if (GST_VIDEO_INFO_IS_GRAY (out_info)) {
2193         cinfo->to_yuv_func[0] = templ_COLOR_SPACE_CONVERT_LUMA;
2194       } else if (GST_VIDEO_INFO_N_PLANES (out_info) == 1 ||
2195           cinfo->ps_output[0] == &output_types[OUTPUT_THREE_PLANES]) {
2196         /* YUV packed or Y444 */
2197         cinfo->to_yuv_func[0] = templ_COLOR_SPACE_CONVERT;
2198       } else {
2199         cinfo->to_yuv_func[0] = templ_COLOR_SPACE_CONVERT_LUMA;
2200         cinfo->to_yuv_func[1] = templ_COLOR_SPACE_CONVERT_CHROMA;
2201       }
2202     }
2203   } else if (GST_VIDEO_INFO_IS_GRAY (in_info)) {
2204     gboolean identity = TRUE;
2205     GstD3D11ColorMatrix matrix;
2206
2207     memset (&matrix, 0, sizeof (GstD3D11ColorMatrix));
2208
2209     if (in_color->range != out_color->range) {
2210       GstVideoInfo in_tmp, out_tmp;
2211
2212       if (GST_VIDEO_INFO_IS_RGB (out_info)) {
2213         convert_info_gray_to_rgb (in_info, &in_tmp);
2214         out_tmp = *out_info;
2215       } else {
2216         convert_info_gray_to_yuv (in_info, &in_tmp);
2217         convert_info_gray_to_yuv (out_info, &out_tmp);
2218       }
2219
2220       identity = FALSE;
2221       if (!gst_d3d11_color_range_adjust_matrix_unorm (&in_tmp, &out_tmp,
2222               &matrix)) {
2223         GST_ERROR_OBJECT (self, "Failed to get GRAY range adjust matrix");
2224         return FALSE;
2225       }
2226
2227       matrix_dump = gst_d3d11_dump_color_matrix (&matrix);
2228       GST_DEBUG_OBJECT (self, "GRAY range adjust matrix:\n%s", matrix_dump);
2229       g_free (matrix_dump);
2230     }
2231
2232     if (GST_VIDEO_INFO_IS_GRAY (out_info)) {
2233       if (identity) {
2234         GST_DEBUG_OBJECT (self, "GRAY to GRAY without range adjust");
2235       } else {
2236         cinfo->to_yuv_func[0] = templ_COLOR_SPACE_CONVERT_LUMA;
2237       }
2238
2239       to_yuv_matrix = matrix;
2240     } else if (GST_VIDEO_INFO_IS_RGB (out_info)) {
2241       if (identity) {
2242         GST_DEBUG_OBJECT (self, "GRAY to RGB without range adjust");
2243         cinfo->to_rgb_func[0] = templ_COLOR_SPACE_GRAY_TO_RGB;
2244       } else {
2245         cinfo->to_rgb_func[0] = templ_COLOR_SPACE_GRAY_TO_RGB_RANGE_ADJUST;
2246       }
2247
2248       to_rgb_matrix = matrix;
2249     } else if (GST_VIDEO_INFO_IS_YUV (out_info)) {
2250       if (identity) {
2251         GST_DEBUG_OBJECT (self, "GRAY to YUV without range adjust");
2252       } else {
2253         cinfo->to_yuv_func[0] = templ_COLOR_SPACE_CONVERT_LUMA;
2254         cinfo->to_yuv_func[1] = templ_COLOR_SPACE_CONVERT_LUMA;
2255       }
2256
2257       to_yuv_matrix = matrix;
2258     } else {
2259       g_assert_not_reached ();
2260       return FALSE;
2261     }
2262   } else if (GST_VIDEO_INFO_IS_YUV (in_info)) {
2263     if (GST_VIDEO_INFO_IS_RGB (out_info)) {
2264       GstVideoInfo yuv_info = *in_info;
2265
2266       if (yuv_info.colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_UNKNOWN ||
2267           yuv_info.colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_RGB) {
2268         GST_WARNING_OBJECT (self, "Invalid matrix is detected");
2269         yuv_info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT709;
2270       }
2271
2272       if (!gst_d3d11_yuv_to_rgb_matrix_unorm (&yuv_info,
2273               out_info, &to_rgb_matrix)) {
2274         GST_ERROR_OBJECT (self, "Failed to get YUV -> RGB transform matrix");
2275         return FALSE;
2276       }
2277
2278       matrix_dump = gst_d3d11_dump_color_matrix (&to_rgb_matrix);
2279       GST_DEBUG_OBJECT (self, "YUV -> RGB matrix:\n%s", matrix_dump);
2280       g_free (matrix_dump);
2281
2282       cinfo->to_rgb_func[0] = templ_COLOR_SPACE_CONVERT;
2283     } else if (in_color->range != out_color->range) {
2284       if (!gst_d3d11_color_range_adjust_matrix_unorm (in_info, out_info,
2285               &to_yuv_matrix)) {
2286         GST_ERROR_OBJECT (self, "Failed to get GRAY range adjust matrix");
2287         return FALSE;
2288       }
2289
2290       matrix_dump = gst_d3d11_dump_color_matrix (&to_yuv_matrix);
2291       GST_DEBUG_OBJECT (self, "YUV range adjust matrix:\n%s", matrix_dump);
2292       g_free (matrix_dump);
2293
2294       if (GST_VIDEO_INFO_IS_GRAY (out_info)) {
2295         cinfo->to_yuv_func[0] = templ_COLOR_SPACE_CONVERT_LUMA;
2296       } else if (GST_VIDEO_INFO_N_PLANES (out_info) == 1 ||
2297           cinfo->ps_output[0] == &output_types[OUTPUT_THREE_PLANES]) {
2298         /* YUV packed or Y444 */
2299         cinfo->to_yuv_func[0] = templ_COLOR_SPACE_CONVERT;
2300       } else {
2301         cinfo->to_yuv_func[0] = templ_COLOR_SPACE_CONVERT_LUMA;
2302         cinfo->to_yuv_func[1] = templ_COLOR_SPACE_CONVERT_CHROMA;
2303       }
2304     }
2305   } else {
2306     g_assert_not_reached ();
2307     return FALSE;
2308   }
2309
2310   for (guint i = 0; i < 3; i++) {
2311     to_rgb_buf->coeffX[i] = to_rgb_matrix.matrix[0][i];
2312     to_rgb_buf->coeffY[i] = to_rgb_matrix.matrix[1][i];
2313     to_rgb_buf->coeffZ[i] = to_rgb_matrix.matrix[2][i];
2314     to_rgb_buf->offset[i] = to_rgb_matrix.offset[i];
2315     to_rgb_buf->min[i] = to_rgb_matrix.min[i];
2316     to_rgb_buf->max[i] = to_rgb_matrix.max[i];
2317
2318     to_yuv_buf->coeffX[i] = to_yuv_matrix.matrix[0][i];
2319     to_yuv_buf->coeffY[i] = to_yuv_matrix.matrix[1][i];
2320     to_yuv_buf->coeffZ[i] = to_yuv_matrix.matrix[2][i];
2321     to_yuv_buf->offset[i] = to_yuv_matrix.offset[i];
2322     to_yuv_buf->min[i] = to_yuv_matrix.min[i];
2323     to_yuv_buf->max[i] = to_yuv_matrix.max[i];
2324   }
2325
2326   return TRUE;
2327 }
2328
2329 static gboolean
2330 gst_d3d11_converter_prepare_colorspace (GstD3D11Converter * self,
2331     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
2332 {
2333   GstD3D11ConverterPrivate *priv = self->priv;
2334   const GstVideoColorimetry *in_color = &in_info->colorimetry;
2335   const GstVideoColorimetry *out_color = &out_info->colorimetry;
2336   ConvertInfo *cinfo = &priv->convert_info;
2337   PSColorSpace *to_rgb_buf = &priv->const_data.to_rgb_buf;
2338   PSColorSpace *to_yuv_buf = &priv->const_data.to_yuv_buf;
2339   PSColorSpace *XYZ_convert_buf = &priv->const_data.XYZ_convert_buf;
2340   GstD3D11ColorMatrix to_rgb_matrix;
2341   GstD3D11ColorMatrix to_yuv_matrix;
2342   GstD3D11ColorMatrix XYZ_convert_matrix;
2343   gchar *matrix_dump;
2344   GstVideoInfo in_rgb_info = *in_info;
2345   GstVideoInfo out_rgb_info = *out_info;
2346
2347   g_assert (GST_VIDEO_INFO_IS_RGB (in_info) || GST_VIDEO_INFO_IS_YUV (in_info));
2348   g_assert (GST_VIDEO_INFO_IS_RGB (out_info)
2349       || GST_VIDEO_INFO_IS_YUV (out_info));
2350
2351   memset (&to_rgb_matrix, 0, sizeof (GstD3D11ColorMatrix));
2352   memset (&to_yuv_matrix, 0, sizeof (GstD3D11ColorMatrix));
2353   memset (&XYZ_convert_matrix, 0, sizeof (GstD3D11ColorMatrix));
2354
2355   for (guint i = 0; i < 2; i++) {
2356     cinfo->to_rgb_func[i] = templ_COLOR_SPACE_IDENTITY;
2357     cinfo->to_yuv_func[i] = templ_COLOR_SPACE_IDENTITY;
2358   }
2359
2360   cinfo->XYZ_convert_func = templ_XYZ_CONVERT_IDENTITY;
2361   cinfo->gamma_decode_func = templ_GAMMA_DECODE;
2362   cinfo->gamma_encode_func = templ_GAMMA_ENCODE;
2363
2364   /* 1) convert input to 0..255 range RGB */
2365   if (GST_VIDEO_INFO_IS_RGB (in_info) &&
2366       in_color->range == GST_VIDEO_COLOR_RANGE_16_235) {
2367     in_rgb_info.colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
2368
2369     if (!gst_d3d11_color_range_adjust_matrix_unorm (in_info, &in_rgb_info,
2370             &to_rgb_matrix)) {
2371       GST_ERROR_OBJECT (self, "Failed to get RGB range adjust matrix");
2372       return FALSE;
2373     }
2374
2375     matrix_dump = gst_d3d11_dump_color_matrix (&to_rgb_matrix);
2376     GST_DEBUG_OBJECT (self, "Input RGB range adjust matrix\n%s", matrix_dump);
2377     g_free (matrix_dump);
2378
2379     cinfo->to_rgb_func[0] = cinfo->to_rgb_func[1] = templ_COLOR_SPACE_CONVERT;
2380   } else if (GST_VIDEO_INFO_IS_YUV (in_info)) {
2381     GstVideoInfo yuv_info;
2382     GstVideoFormat rgb_format;
2383
2384     yuv_info = *in_info;
2385     if (yuv_info.colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_UNKNOWN ||
2386         yuv_info.colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_RGB) {
2387       GST_WARNING_OBJECT (self, "Invalid matrix is detected");
2388       yuv_info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT709;
2389     }
2390
2391     if (in_info->finfo->depth[0] == 8) {
2392       rgb_format = GST_VIDEO_FORMAT_RGBA;
2393     } else {
2394       rgb_format = GST_VIDEO_FORMAT_RGBA64_LE;
2395     }
2396
2397     gst_video_info_set_format (&in_rgb_info, rgb_format, in_info->width,
2398         in_info->height);
2399     in_rgb_info.colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
2400     in_rgb_info.colorimetry.transfer = in_color->transfer;
2401     in_rgb_info.colorimetry.primaries = in_color->primaries;
2402
2403     if (!gst_d3d11_yuv_to_rgb_matrix_unorm (&yuv_info, &in_rgb_info,
2404             &to_rgb_matrix)) {
2405       GST_ERROR_OBJECT (self, "Failed to get YUV -> RGB transform matrix");
2406       return FALSE;
2407     }
2408
2409     matrix_dump = gst_d3d11_dump_color_matrix (&to_rgb_matrix);
2410     GST_DEBUG_OBJECT (self, "YUV -> RGB matrix:\n%s", matrix_dump);
2411     g_free (matrix_dump);
2412
2413     cinfo->to_rgb_func[0] = cinfo->to_rgb_func[1] = templ_COLOR_SPACE_CONVERT;
2414   }
2415
2416   /* 2) convert gamma/XYZ converted 0..255 RGB to output format */
2417   if (GST_VIDEO_INFO_IS_RGB (out_info) &&
2418       out_color->range == GST_VIDEO_COLOR_RANGE_16_235) {
2419     out_rgb_info.colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
2420
2421     if (!gst_d3d11_color_range_adjust_matrix_unorm (&out_rgb_info, out_info,
2422             &to_yuv_matrix)) {
2423       GST_ERROR_OBJECT (self, "Failed to get RGB range adjust matrix");
2424       return FALSE;
2425     }
2426
2427     matrix_dump = gst_d3d11_dump_color_matrix (&to_yuv_matrix);
2428     GST_DEBUG_OBJECT (self, "Output RGB range adjust matrix\n%s", matrix_dump);
2429     g_free (matrix_dump);
2430
2431     cinfo->to_yuv_func[0] = cinfo->to_yuv_func[1] = templ_COLOR_SPACE_CONVERT;
2432   } else if (GST_VIDEO_INFO_IS_YUV (out_info)) {
2433     GstVideoInfo yuv_info;
2434
2435     yuv_info = *out_info;
2436     if (yuv_info.colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_UNKNOWN ||
2437         yuv_info.colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_RGB) {
2438       GST_WARNING_OBJECT (self, "Invalid matrix is detected");
2439       yuv_info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT709;
2440     }
2441
2442     gst_video_info_set_format (&out_rgb_info,
2443         GST_VIDEO_INFO_FORMAT (&in_rgb_info), out_info->width,
2444         out_info->height);
2445     out_rgb_info.colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
2446     out_rgb_info.colorimetry.transfer = out_color->transfer;
2447     out_rgb_info.colorimetry.primaries = out_color->primaries;
2448
2449     if (!gst_d3d11_rgb_to_yuv_matrix_unorm (&out_rgb_info,
2450             &yuv_info, &to_yuv_matrix)) {
2451       GST_ERROR_OBJECT (self, "Failed to get RGB -> YUV transform matrix");
2452       return FALSE;
2453     }
2454
2455     matrix_dump = gst_d3d11_dump_color_matrix (&to_yuv_matrix);
2456     GST_DEBUG_OBJECT (self, "RGB -> YUV matrix:\n%s", matrix_dump);
2457     g_free (matrix_dump);
2458
2459     if (GST_VIDEO_INFO_N_PLANES (out_info) == 1 ||
2460         cinfo->ps_output[0] == &output_types[OUTPUT_THREE_PLANES]) {
2461       /* YUV packed or Y444 */
2462       cinfo->to_yuv_func[0] = templ_COLOR_SPACE_CONVERT;
2463     } else {
2464       cinfo->to_yuv_func[0] = templ_COLOR_SPACE_CONVERT_LUMA;
2465       cinfo->to_yuv_func[1] = templ_COLOR_SPACE_CONVERT_CHROMA;
2466     }
2467   }
2468
2469   /* TODO: handle HDR mastring display info */
2470   if (priv->do_primaries) {
2471     const GstVideoColorPrimariesInfo *in_pinfo;
2472     const GstVideoColorPrimariesInfo *out_pinfo;
2473
2474     in_pinfo = gst_video_color_primaries_get_info (in_color->primaries);
2475     out_pinfo = gst_video_color_primaries_get_info (out_color->primaries);
2476
2477     if (!gst_d3d11_color_primaries_matrix_unorm (in_pinfo, out_pinfo,
2478             &XYZ_convert_matrix)) {
2479       GST_ERROR_OBJECT (self, "Failed to get primaries conversion matrix");
2480       return FALSE;
2481     }
2482
2483     matrix_dump = gst_d3d11_dump_color_matrix (&XYZ_convert_matrix);
2484     GST_DEBUG_OBJECT (self, "Primaries conversion matrix:\n%s", matrix_dump);
2485     g_free (matrix_dump);
2486
2487     cinfo->XYZ_convert_func = templ_XYZ_CONVERT;
2488   }
2489
2490   for (guint i = 0; i < 3; i++) {
2491     to_rgb_buf->coeffX[i] = to_rgb_matrix.matrix[0][i];
2492     to_rgb_buf->coeffY[i] = to_rgb_matrix.matrix[1][i];
2493     to_rgb_buf->coeffZ[i] = to_rgb_matrix.matrix[2][i];
2494     to_rgb_buf->offset[i] = to_rgb_matrix.offset[i];
2495     to_rgb_buf->min[i] = to_rgb_matrix.min[i];
2496     to_rgb_buf->max[i] = to_rgb_matrix.max[i];
2497
2498     to_yuv_buf->coeffX[i] = to_yuv_matrix.matrix[0][i];
2499     to_yuv_buf->coeffY[i] = to_yuv_matrix.matrix[1][i];
2500     to_yuv_buf->coeffZ[i] = to_yuv_matrix.matrix[2][i];
2501     to_yuv_buf->offset[i] = to_yuv_matrix.offset[i];
2502     to_yuv_buf->min[i] = to_yuv_matrix.min[i];
2503     to_yuv_buf->max[i] = to_yuv_matrix.max[i];
2504
2505     XYZ_convert_buf->coeffX[i] = XYZ_convert_matrix.matrix[0][i];
2506     XYZ_convert_buf->coeffY[i] = XYZ_convert_matrix.matrix[1][i];
2507     XYZ_convert_buf->coeffZ[i] = XYZ_convert_matrix.matrix[2][i];
2508     XYZ_convert_buf->offset[i] = XYZ_convert_matrix.offset[i];
2509     XYZ_convert_buf->min[i] = XYZ_convert_matrix.min[i];
2510     XYZ_convert_buf->max[i] = XYZ_convert_matrix.max[i];
2511   }
2512
2513   return TRUE;
2514 }
2515
2516 static gboolean
2517 gst_d3d11_converter_setup_lut (GstD3D11Converter * self,
2518     const GstVideoInfo * in_info, const GstVideoInfo * out_info)
2519 {
2520   GstD3D11ConverterPrivate *priv = self->priv;
2521   GstD3D11Device *device = self->device;
2522   ID3D11Device *device_handle = gst_d3d11_device_get_device_handle (device);
2523   D3D11_TEXTURE1D_DESC desc;
2524   D3D11_SUBRESOURCE_DATA subresource;
2525   D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc;
2526   HRESULT hr;
2527   ComPtr < ID3D11Texture1D > gamma_dec_lut;
2528   ComPtr < ID3D11Texture1D > gamma_enc_lut;
2529   ComPtr < ID3D11ShaderResourceView > gamma_dec_srv;
2530   ComPtr < ID3D11ShaderResourceView > gamma_enc_srv;
2531   guint16 gamma_dec_table[GAMMA_LUT_SIZE];
2532   guint16 gamma_enc_table[GAMMA_LUT_SIZE];
2533   GstVideoTransferFunction in_trc = in_info->colorimetry.transfer;
2534   GstVideoTransferFunction out_trc = out_info->colorimetry.transfer;
2535   gdouble scale = (gdouble) 1 / (GAMMA_LUT_SIZE - 1);
2536
2537   memset (&desc, 0, sizeof (D3D11_TEXTURE1D_DESC));
2538   memset (&subresource, 0, sizeof (D3D11_SUBRESOURCE_DATA));
2539   memset (&srv_desc, 0, sizeof (D3D11_SHADER_RESOURCE_VIEW_DESC));
2540
2541   for (guint i = 0; i < GAMMA_LUT_SIZE; i++) {
2542     gdouble val = gst_video_transfer_function_decode (in_trc, i * scale);
2543     val = rint (val * 65535);
2544     val = CLAMP (val, 0, 65535);
2545     gamma_dec_table[i] = (guint16) val;
2546
2547     val = gst_video_transfer_function_encode (out_trc, i * scale);
2548     val = rint (val * 65535);
2549     val = CLAMP (val, 0, 65535);
2550     gamma_enc_table[i] = (guint16) val;
2551   }
2552
2553   desc.Width = GAMMA_LUT_SIZE;
2554   desc.MipLevels = 1;
2555   desc.ArraySize = 1;
2556   desc.Format = DXGI_FORMAT_R16_UNORM;
2557   desc.Usage = D3D11_USAGE_DEFAULT;
2558   desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
2559
2560   subresource.pSysMem = gamma_dec_table;
2561   subresource.SysMemPitch = GAMMA_LUT_SIZE * sizeof (guint16);
2562
2563   srv_desc.Format = DXGI_FORMAT_R16_UNORM;
2564   srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D;
2565   srv_desc.Texture1D.MipLevels = 1;
2566
2567   hr = device_handle->CreateTexture1D (&desc, &subresource, &gamma_dec_lut);
2568   if (!gst_d3d11_result (hr, device)) {
2569     GST_ERROR_OBJECT (self, "Failed to create gamma decode LUT");
2570     return FALSE;
2571   }
2572
2573   hr = device_handle->CreateShaderResourceView (gamma_dec_lut.Get (), &srv_desc,
2574       &gamma_dec_srv);
2575   if (!gst_d3d11_result (hr, device)) {
2576     GST_ERROR_OBJECT (self, "Failed to create gamma decode LUT SRV");
2577     return FALSE;
2578   }
2579
2580   subresource.pSysMem = gamma_enc_table;
2581   hr = device_handle->CreateTexture1D (&desc, &subresource, &gamma_enc_lut);
2582   if (!gst_d3d11_result (hr, device)) {
2583     GST_ERROR_OBJECT (self, "Failed to create gamma encode LUT");
2584     return FALSE;
2585   }
2586
2587   hr = device_handle->CreateShaderResourceView (gamma_enc_lut.Get (), &srv_desc,
2588       &gamma_enc_srv);
2589   if (!gst_d3d11_result (hr, device)) {
2590     GST_ERROR_OBJECT (device, "Failed to create gamma decode LUT SRV");
2591     return FALSE;
2592   }
2593
2594   priv->gamma_dec_lut = gamma_dec_lut.Detach ();
2595   priv->gamma_enc_lut = gamma_enc_lut.Detach ();
2596   priv->gamma_dec_srv = gamma_dec_srv.Detach ();
2597   priv->gamma_enc_srv = gamma_enc_srv.Detach ();
2598
2599   return TRUE;
2600 }
2601
2602 static void
2603 gst_d3d11_converter_calculate_border_color (GstD3D11Converter * self)
2604 {
2605   GstD3D11ConverterPrivate *priv = self->priv;
2606   GstD3D11ColorMatrix *m = &priv->clear_color_matrix;
2607   const GstVideoInfo *out_info = &priv->out_info;
2608   gdouble a;
2609   gdouble rgb[3];
2610   gdouble converted[3];
2611   GstVideoFormat format = GST_VIDEO_INFO_FORMAT (out_info);
2612
2613   a = ((priv->border_color & 0xffff000000000000) >> 48) / (gdouble) G_MAXUINT16;
2614   rgb[0] =
2615       ((priv->border_color & 0x0000ffff00000000) >> 32) / (gdouble) G_MAXUINT16;
2616   rgb[1] =
2617       ((priv->border_color & 0x00000000ffff0000) >> 16) / (gdouble) G_MAXUINT16;
2618   rgb[2] = (priv->border_color & 0x000000000000ffff) / (gdouble) G_MAXUINT16;
2619
2620   for (guint i = 0; i < 3; i++) {
2621     converted[i] = 0;
2622     for (guint j = 0; j < 3; j++) {
2623       converted[i] += m->matrix[i][j] * rgb[j];
2624     }
2625     converted[i] += m->offset[i];
2626     converted[i] = CLAMP (converted[i], m->min[i], m->max[i]);
2627   }
2628
2629   GST_DEBUG_OBJECT (self, "Calculated background color ARGB: %f, %f, %f, %f",
2630       a, converted[0], converted[1], converted[2]);
2631
2632   if (GST_VIDEO_INFO_IS_RGB (out_info) || GST_VIDEO_INFO_IS_GRAY (out_info)) {
2633     /* background color for video processor */
2634     priv->background_color.RGBA.R = converted[0];
2635     priv->background_color.RGBA.G = converted[1];
2636     priv->background_color.RGBA.B = converted[2];
2637     priv->background_color.RGBA.A = a;
2638
2639     for (guint i = 0; i < 3; i++)
2640       priv->clear_color[0][i] = converted[i];
2641     priv->clear_color[0][3] = a;
2642   } else {
2643     /* background color for video processor */
2644     priv->background_color.YCbCr.Y = converted[0];
2645     priv->background_color.YCbCr.Cb = converted[1];
2646     priv->background_color.YCbCr.Cr = converted[2];
2647     priv->background_color.YCbCr.A = a;
2648
2649     switch (format) {
2650       case GST_VIDEO_FORMAT_VUYA:
2651         priv->clear_color[0][0] = converted[2];
2652         priv->clear_color[0][1] = converted[1];
2653         priv->clear_color[0][2] = converted[0];
2654         priv->clear_color[0][3] = a;
2655         break;
2656       case GST_VIDEO_FORMAT_AYUV:
2657       case GST_VIDEO_FORMAT_AYUV64:
2658         priv->clear_color[0][0] = a;
2659         priv->clear_color[0][1] = converted[0];
2660         priv->clear_color[0][2] = converted[1];
2661         priv->clear_color[0][3] = converted[2];
2662         break;
2663       case GST_VIDEO_FORMAT_NV12:
2664       case GST_VIDEO_FORMAT_NV21:
2665       case GST_VIDEO_FORMAT_P010_10LE:
2666       case GST_VIDEO_FORMAT_P012_LE:
2667       case GST_VIDEO_FORMAT_P016_LE:
2668         priv->clear_color[0][0] = converted[0];
2669         priv->clear_color[0][1] = 0;
2670         priv->clear_color[0][2] = 0;
2671         priv->clear_color[0][3] = 1.0;
2672         if (format == GST_VIDEO_FORMAT_NV21) {
2673           priv->clear_color[1][0] = converted[2];
2674           priv->clear_color[1][1] = converted[1];
2675         } else {
2676           priv->clear_color[1][0] = converted[1];
2677           priv->clear_color[1][1] = converted[2];
2678         }
2679         priv->clear_color[1][2] = 0;
2680         priv->clear_color[1][3] = 1.0;
2681         break;
2682       case GST_VIDEO_FORMAT_I420:
2683       case GST_VIDEO_FORMAT_YV12:
2684       case GST_VIDEO_FORMAT_I420_10LE:
2685       case GST_VIDEO_FORMAT_I420_12LE:
2686       case GST_VIDEO_FORMAT_Y42B:
2687       case GST_VIDEO_FORMAT_I422_10LE:
2688       case GST_VIDEO_FORMAT_I422_12LE:
2689       case GST_VIDEO_FORMAT_Y444:
2690       case GST_VIDEO_FORMAT_Y444_10LE:
2691       case GST_VIDEO_FORMAT_Y444_12LE:
2692       case GST_VIDEO_FORMAT_Y444_16LE:
2693         priv->clear_color[0][0] = converted[0];
2694         priv->clear_color[0][1] = 0;
2695         priv->clear_color[0][2] = 0;
2696         priv->clear_color[0][3] = 1.0;
2697         if (format == GST_VIDEO_FORMAT_YV12) {
2698           priv->clear_color[1][0] = converted[2];
2699           priv->clear_color[2][0] = converted[1];
2700         } else {
2701           priv->clear_color[1][0] = converted[1];
2702           priv->clear_color[2][0] = converted[2];
2703         }
2704         priv->clear_color[1][1] = 0;
2705         priv->clear_color[1][2] = 0;
2706         priv->clear_color[1][3] = 1.0;
2707         priv->clear_color[2][1] = 0;
2708         priv->clear_color[2][2] = 0;
2709         priv->clear_color[2][3] = 1.0;
2710         break;
2711       default:
2712         g_assert_not_reached ();
2713         break;
2714     }
2715   }
2716 }
2717
2718 static gboolean
2719 gst_d3d11_converter_setup_processor (GstD3D11Converter * self)
2720 {
2721   GstD3D11ConverterPrivate *priv = self->priv;
2722   GstD3D11Device *device = self->device;
2723   ID3D11VideoDevice *video_device;
2724   ID3D11VideoContext *video_context;
2725   HRESULT hr;
2726   D3D11_VIDEO_PROCESSOR_CONTENT_DESC desc;
2727   ComPtr < ID3D11VideoContext1 > video_context1;
2728   ComPtr < ID3D11VideoContext2 > video_context2;
2729   ComPtr < ID3D11VideoProcessorEnumerator > enumerator;
2730   ComPtr < ID3D11VideoProcessorEnumerator1 > enumerator1;
2731   ComPtr < ID3D11VideoProcessor > processor;
2732   UINT support_flags;
2733   BOOL conversion_supported = TRUE;
2734   DXGI_COLOR_SPACE_TYPE in_space, out_space;
2735   DXGI_FORMAT in_dxgi_format = priv->in_d3d11_format.dxgi_format;
2736   DXGI_FORMAT out_dxgi_format = priv->out_d3d11_format.dxgi_format;
2737   UINT in_format_flags = priv->in_d3d11_format.format_support[0];
2738   UINT out_format_flags = priv->out_d3d11_format.format_support[0];
2739
2740   if (GST_VIDEO_INFO_IS_GRAY (&priv->in_info) ||
2741       GST_VIDEO_INFO_IS_GRAY (&priv->out_info)) {
2742     return FALSE;
2743   }
2744
2745   /* Not a native DXGI format */
2746   if (in_dxgi_format == DXGI_FORMAT_UNKNOWN ||
2747       out_dxgi_format == DXGI_FORMAT_UNKNOWN) {
2748     return FALSE;
2749   }
2750
2751   /* cannot bind to processor in/out view */
2752   if ((in_format_flags & D3D11_FORMAT_SUPPORT_VIDEO_PROCESSOR_INPUT) == 0 ||
2753       (out_format_flags & D3D11_FORMAT_SUPPORT_VIDEO_PROCESSOR_OUTPUT) == 0) {
2754     return FALSE;
2755   }
2756
2757   if (!gst_video_info_to_dxgi_color_space (&priv->in_info, &in_space)) {
2758     GST_WARNING_OBJECT (self, "Unknown input DXGI colorspace");
2759     return FALSE;
2760   }
2761
2762   if (!gst_video_info_to_dxgi_color_space (&priv->out_info, &out_space)) {
2763     GST_WARNING_OBJECT (self, "Unknown output DXGI colorspace");
2764     return FALSE;
2765   }
2766
2767   video_device = gst_d3d11_device_get_video_device_handle (self->device);
2768   if (!video_device) {
2769     GST_DEBUG_OBJECT (self, "video device interface is not available");
2770     return FALSE;
2771   }
2772
2773   video_context = gst_d3d11_device_get_video_context_handle (self->device);
2774   if (!video_context) {
2775     GST_DEBUG_OBJECT (self, "video context interface is not available");
2776     return FALSE;
2777   }
2778
2779   hr = video_context->QueryInterface (IID_PPV_ARGS (&video_context1));
2780   if (!gst_d3d11_result (hr, device)) {
2781     GST_DEBUG_OBJECT (self, "ID3D11VideoContext1 interface is not available");
2782     return FALSE;
2783   }
2784
2785   memset (&desc, 0, sizeof (D3D11_VIDEO_PROCESSOR_CONTENT_DESC));
2786
2787   desc.InputFrameFormat = D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE;
2788   desc.InputWidth = priv->in_info.width;
2789   desc.InputHeight = priv->in_info.height;
2790   desc.OutputWidth = priv->out_info.width;
2791   desc.OutputHeight = priv->out_info.height;
2792   /* TODO: make option for this */
2793   desc.Usage = D3D11_VIDEO_USAGE_PLAYBACK_NORMAL;
2794
2795   hr = video_device->CreateVideoProcessorEnumerator (&desc, &enumerator);
2796   if (!gst_d3d11_result (hr, device)) {
2797     GST_WARNING_OBJECT (self, "Failed to create enumerator");
2798     return FALSE;
2799   }
2800
2801   hr = enumerator.As (&enumerator1);
2802   if (!gst_d3d11_result (hr, device)) {
2803     GST_WARNING_OBJECT (self,
2804         "ID3D11VideoProcessorEnumerator1 interface is not available");
2805     return FALSE;
2806   }
2807
2808   support_flags = 0;
2809   hr = enumerator1->CheckVideoProcessorFormat (in_dxgi_format, &support_flags);
2810   if (!gst_d3d11_result (hr, device) || (support_flags & 0x1) == 0) {
2811     GST_DEBUG_OBJECT (self, "Input format is not supported");
2812     return FALSE;
2813   }
2814
2815   support_flags = 0;
2816   hr = enumerator1->CheckVideoProcessorFormat (out_dxgi_format, &support_flags);
2817   if (!gst_d3d11_result (hr, device) || (support_flags & 0x2) == 0) {
2818     GST_DEBUG_OBJECT (self, "Output format is not supported");
2819     return FALSE;
2820   }
2821
2822   hr = enumerator1->CheckVideoProcessorFormatConversion (in_dxgi_format,
2823       in_space, out_dxgi_format, out_space, &conversion_supported);
2824   if (!gst_d3d11_result (hr, device) || !conversion_supported) {
2825     GST_DEBUG_OBJECT (self, "Conversion is not supported");
2826     return FALSE;
2827   }
2828
2829   hr = enumerator1->GetVideoProcessorCaps (&priv->processor_caps);
2830   if (!gst_d3d11_result (hr, device)) {
2831     GST_WARNING_OBJECT (self, "Failed to query processor caps");
2832     return FALSE;
2833   }
2834
2835   hr = video_device->CreateVideoProcessor (enumerator1.Get (), 0, &processor);
2836   if (!gst_d3d11_result (hr, device)) {
2837     GST_WARNING_OBJECT (self, "Failed to create processor");
2838     return FALSE;
2839   }
2840
2841   GstD3D11DeviceLockGuard lk (device);
2842   /* We don't want auto processing by driver */
2843   video_context1->VideoProcessorSetStreamAutoProcessingMode
2844       (processor.Get (), 0, FALSE);
2845   video_context1->VideoProcessorSetStreamColorSpace1 (processor.Get (),
2846       0, in_space);
2847   video_context1->VideoProcessorSetOutputColorSpace1 (processor.Get (),
2848       out_space);
2849
2850   priv->video_device = video_device;
2851   video_device->AddRef ();
2852   priv->processor = processor.Detach ();
2853   hr = video_context1.As (&video_context2);
2854   if (SUCCEEDED (hr))
2855     priv->video_context2 = video_context2.Detach ();
2856   priv->video_context = video_context1.Detach ();
2857   priv->enumerator = enumerator1.Detach ();
2858
2859   priv->src_rect.left = 0;
2860   priv->src_rect.top = 0;
2861   priv->src_rect.right = priv->in_info.width;
2862   priv->src_rect.bottom = priv->in_info.height;
2863
2864   priv->dest_rect.left = 0;
2865   priv->dest_rect.top = 0;
2866   priv->dest_rect.right = priv->out_info.width;
2867   priv->dest_rect.bottom = priv->out_info.height;
2868
2869   priv->dest_full_rect = priv->dest_rect;
2870
2871   return TRUE;
2872 }
2873
2874 /**
2875  * gst_d3d11_converter_new:
2876  * @device: a #GstD3D11Device
2877  * @in_info: a #GstVideoInfo
2878  * @out_info: a #GstVideoInfo
2879  * @method: (inout) (optional) (nullable): a #GstD3D11ConverterMethod
2880
2881  * Create a new converter object to convert between @in_info and @out_info
2882  * with @method. When @method is not specified, converter will configure
2883  * conversion path for all available method. Otherwise, converter will configure
2884  * conversion path only for specified method(s) and set @method will be updated
2885  * with supported method.
2886  *
2887  * Returns: a #GstD3D11Converter or %NULL if conversion is not possible
2888  *
2889  * Since: 1.22
2890  */
2891 GstD3D11Converter *
2892 gst_d3d11_converter_new (GstD3D11Device * device, const GstVideoInfo * in_info,
2893     const GstVideoInfo * out_info, GstStructure * config)
2894 {
2895   GstD3D11Converter *self;
2896   GstD3D11ConverterPrivate *priv;
2897   GstD3D11Format in_d3d11_format;
2898   GstD3D11Format out_d3d11_format;
2899   guint wanted_backend = 0;
2900   gboolean allow_gamma = FALSE;
2901   gboolean allow_primaries = FALSE;
2902   gchar *backend_str;
2903
2904   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), nullptr);
2905   g_return_val_if_fail (in_info != nullptr, nullptr);
2906   g_return_val_if_fail (out_info != nullptr, nullptr);
2907
2908   self = (GstD3D11Converter *) g_object_new (GST_TYPE_D3D11_CONVERTER, nullptr);
2909   gst_object_ref_sink (self);
2910   priv = self->priv;
2911
2912   if (config) {
2913     gint value;
2914     gst_structure_get_flags (config, GST_D3D11_CONVERTER_OPT_BACKEND,
2915         GST_TYPE_D3D11_CONVERTER_BACKEND, &wanted_backend);
2916
2917     if (gst_structure_get_enum (config, GST_D3D11_CONVERTER_OPT_GAMMA_MODE,
2918             GST_TYPE_VIDEO_GAMMA_MODE, &value) &&
2919         (GstVideoGammaMode) value != GST_VIDEO_GAMMA_MODE_NONE) {
2920       allow_gamma = TRUE;
2921     }
2922
2923     if (gst_structure_get_enum (config, GST_D3D11_CONVERTER_OPT_PRIMARIES_MODE,
2924             GST_TYPE_VIDEO_PRIMARIES_MODE, &value) &&
2925         (GstVideoPrimariesMode) value != GST_VIDEO_PRIMARIES_MODE_NONE) {
2926       allow_primaries = TRUE;
2927     }
2928
2929     gst_structure_free (config);
2930   }
2931
2932   if (!wanted_backend) {
2933     wanted_backend =
2934         GST_D3D11_CONVERTER_BACKEND_SHADER |
2935         GST_D3D11_CONVERTER_BACKEND_VIDEO_PROCESSOR;
2936   }
2937
2938   backend_str = g_flags_to_string (GST_TYPE_D3D11_CONVERTER_BACKEND,
2939       wanted_backend);
2940
2941   GST_DEBUG_OBJECT (self,
2942       "Setup converter with format %s -> %s, wanted backend: %s, "
2943       "allow gamma conversion: %d, allow primaries conversion: %d ",
2944       gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (in_info)),
2945       gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (out_info)),
2946       backend_str, allow_gamma, allow_primaries);
2947   g_free (backend_str);
2948
2949   if (!gst_d3d11_device_get_format (device, GST_VIDEO_INFO_FORMAT (in_info),
2950           &in_d3d11_format)) {
2951     GST_ERROR_OBJECT (self, "%s couldn't be converted to d3d11 format",
2952         gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (in_info)));
2953     gst_object_unref (self);
2954
2955     return nullptr;
2956   }
2957
2958   if (!gst_d3d11_device_get_format (device, GST_VIDEO_INFO_FORMAT (out_info),
2959           &out_d3d11_format)) {
2960     GST_ERROR_OBJECT (self, "%s couldn't be converted to d3d11 format",
2961         gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (in_info)));
2962     gst_object_unref (self);
2963
2964     return nullptr;
2965   }
2966
2967   self->device = (GstD3D11Device *) gst_object_ref (device);
2968   priv->fast_path = TRUE;
2969   priv->const_data.alpha = 1.0;
2970   priv->in_info = *in_info;
2971   priv->fallback_info = *in_info;
2972   priv->out_info = *out_info;
2973   priv->in_d3d11_format = in_d3d11_format;
2974   priv->out_d3d11_format = out_d3d11_format;
2975
2976   /* Init properties */
2977   priv->src_width = GST_VIDEO_INFO_WIDTH (in_info);
2978   priv->src_height = GST_VIDEO_INFO_HEIGHT (in_info);
2979   priv->dest_width = GST_VIDEO_INFO_WIDTH (out_info);
2980   priv->dest_height = GST_VIDEO_INFO_HEIGHT (out_info);
2981   priv->alpha = 1.0;
2982   for (guint i = 0; i < G_N_ELEMENTS (priv->blend_factor); i++)
2983     priv->blend_factor[i] = 1.0;
2984   priv->blend_sample_mask = 0xffffffff;
2985   priv->border_color = 0xffff000000000000;
2986
2987   if (GST_VIDEO_INFO_IS_RGB (out_info)) {
2988     GstVideoInfo rgb_info = *out_info;
2989     rgb_info.colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
2990     gst_d3d11_color_range_adjust_matrix_unorm (&rgb_info, out_info,
2991         &priv->clear_color_matrix);
2992   } else {
2993     GstVideoInfo rgb_info;
2994     GstVideoInfo yuv_info;
2995
2996     gst_video_info_set_format (&rgb_info, GST_VIDEO_FORMAT_RGBA64_LE,
2997         out_info->width, out_info->height);
2998     convert_info_gray_to_yuv (out_info, &yuv_info);
2999
3000     if (yuv_info.colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_UNKNOWN ||
3001         yuv_info.colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_RGB) {
3002       GST_WARNING_OBJECT (self, "Invalid matrix is detected");
3003       yuv_info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT709;
3004     }
3005
3006     gst_d3d11_rgb_to_yuv_matrix_unorm (&rgb_info,
3007         &yuv_info, &priv->clear_color_matrix);
3008   }
3009
3010   gst_d3d11_converter_calculate_border_color (self);
3011
3012   if ((wanted_backend & GST_D3D11_CONVERTER_BACKEND_VIDEO_PROCESSOR) != 0) {
3013     if (gst_d3d11_converter_setup_processor (self)) {
3014       GST_DEBUG_OBJECT (self, "Video processor is available");
3015       priv->supported_backend |= GST_D3D11_CONVERTER_BACKEND_VIDEO_PROCESSOR;
3016     }
3017   }
3018
3019   if ((wanted_backend & GST_D3D11_CONVERTER_BACKEND_SHADER) == 0)
3020     goto out;
3021
3022   if (!GST_VIDEO_INFO_IS_GRAY (in_info) && !GST_VIDEO_INFO_IS_GRAY (out_info)) {
3023     if (in_info->colorimetry.transfer != GST_VIDEO_TRANSFER_UNKNOWN &&
3024         out_info->colorimetry.transfer != GST_VIDEO_TRANSFER_UNKNOWN &&
3025         !gst_video_transfer_function_is_equivalent (in_info->
3026             colorimetry.transfer, GST_VIDEO_INFO_COMP_DEPTH (in_info, 0),
3027             out_info->colorimetry.transfer, GST_VIDEO_INFO_COMP_DEPTH (out_info,
3028                 0))) {
3029       if (allow_gamma) {
3030         GST_DEBUG_OBJECT (self, "Different transfer function %d -> %d",
3031             in_info->colorimetry.transfer, out_info->colorimetry.transfer);
3032         priv->fast_path = FALSE;
3033       } else {
3034         GST_DEBUG_OBJECT (self,
3035             "Different transfer function %d -> %d but gamma remap is disabled",
3036             in_info->colorimetry.transfer, out_info->colorimetry.transfer);
3037       }
3038     }
3039
3040     if (in_info->colorimetry.primaries != GST_VIDEO_COLOR_PRIMARIES_UNKNOWN &&
3041         out_info->colorimetry.primaries != GST_VIDEO_COLOR_PRIMARIES_UNKNOWN &&
3042         !gst_video_color_primaries_is_equivalent (in_info->
3043             colorimetry.primaries, out_info->colorimetry.primaries)) {
3044       if (allow_primaries) {
3045         GST_DEBUG_OBJECT (self, "Different primaries %d -> %d",
3046             in_info->colorimetry.primaries, out_info->colorimetry.primaries);
3047         priv->fast_path = FALSE;
3048         priv->do_primaries = TRUE;
3049       } else {
3050         GST_DEBUG_OBJECT (self,
3051             "Different primaries %d -> %d but chromatic adaptation is disabled",
3052             in_info->colorimetry.primaries, out_info->colorimetry.primaries);
3053       }
3054     }
3055   }
3056
3057   if (!gst_d3d11_converter_prepare_output (self, out_info))
3058     goto out;
3059
3060   if (!gst_d3d11_converter_prepare_sample_texture (self, in_info, out_info))
3061     goto out;
3062
3063   if (priv->fast_path) {
3064     if (!gst_d3d11_converter_prepare_colorspace_fast (self, in_info, out_info))
3065       goto out;
3066   } else {
3067     if (!gst_d3d11_converter_prepare_colorspace (self, in_info, out_info))
3068       goto out;
3069
3070     if (!gst_d3d11_converter_setup_lut (self, in_info, out_info))
3071       goto out;
3072   }
3073
3074   if (!gst_d3d11_color_convert_setup_shader (self, in_info, out_info))
3075     goto out;
3076
3077   priv->supported_backend |= GST_D3D11_CONVERTER_BACKEND_SHADER;
3078
3079 out:
3080   if (priv->supported_backend == 0) {
3081     GST_ERROR_OBJECT (self, "Conversion %s to %s not supported",
3082         gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (in_info)),
3083         gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (out_info)));
3084     gst_object_unref (self);
3085     return nullptr;
3086   }
3087
3088   return self;
3089 }
3090
3091 static gboolean
3092 gst_d3d11_converter_convert_internal (GstD3D11Converter * self,
3093     ID3D11ShaderResourceView * srv[GST_VIDEO_MAX_PLANES],
3094     ID3D11RenderTargetView * rtv[GST_VIDEO_MAX_PLANES])
3095 {
3096   GstD3D11ConverterPrivate *priv;
3097   ComPtr < ID3D11Resource > resource;
3098   ComPtr < ID3D11Texture2D > texture;
3099   D3D11_TEXTURE2D_DESC desc;
3100   ConvertInfo *cinfo;
3101   ID3D11DeviceContext *context;
3102   UINT offsets = 0;
3103   UINT vertex_stride = sizeof (VertexData);
3104   ID3D11ShaderResourceView *clear_view[GST_VIDEO_MAX_PLANES] = { nullptr, };
3105
3106   priv = self->priv;
3107   cinfo = &priv->convert_info;
3108   context = gst_d3d11_device_get_device_context_handle (self->device);
3109
3110   /* check texture resolution and update crop area */
3111   srv[0]->GetResource (&resource);
3112   resource.As (&texture);
3113   texture->GetDesc (&desc);
3114
3115   if (priv->update_dest_rect && !gst_d3d11_converter_update_dest_rect (self)) {
3116     GST_ERROR_OBJECT (self, "Failed to update dest rect");
3117     return FALSE;
3118   }
3119
3120   if (priv->update_src_rect ||
3121       desc.Width != (guint) priv->input_texture_width ||
3122       desc.Height != (guint) priv->input_texture_height) {
3123     GST_DEBUG_OBJECT (self, "Update vertext buffer, texture resolution: %dx%d",
3124         desc.Width, desc.Height);
3125
3126     priv->input_texture_width = desc.Width;
3127     priv->input_texture_height = desc.Height;
3128
3129     if (!gst_d3d11_converter_update_src_rect (self)) {
3130       GST_ERROR_OBJECT (self, "Cannot update src rect");
3131       return FALSE;
3132     }
3133   }
3134
3135   if (priv->update_alpha) {
3136     D3D11_MAPPED_SUBRESOURCE map;
3137     PSConstBuffer *const_buffer;
3138     HRESULT hr;
3139
3140     hr = context->Map (priv->const_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
3141
3142     if (!gst_d3d11_result (hr, self->device)) {
3143       GST_ERROR_OBJECT (self,
3144           "Couldn't map constant buffer, hr: 0x%x", (guint) hr);
3145       return FALSE;
3146     }
3147
3148     const_buffer = (PSConstBuffer *) map.pData;
3149     memcpy (const_buffer, &priv->const_data, sizeof (PSConstBuffer));
3150
3151     context->Unmap (priv->const_buffer, 0);
3152     priv->update_alpha = FALSE;
3153   }
3154
3155   if (priv->clear_background) {
3156     for (guint i = 0; i < priv->num_output_view; i++)
3157       context->ClearRenderTargetView (rtv[i], priv->clear_color[i]);
3158   }
3159
3160   context->IASetPrimitiveTopology (D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
3161   context->IASetInputLayout (priv->layout);
3162   context->IASetVertexBuffers (0, 1, &priv->vertex_buffer, &vertex_stride,
3163       &offsets);
3164   context->IASetIndexBuffer (priv->index_buffer, DXGI_FORMAT_R16_UINT, 0);
3165   context->PSSetSamplers (0, 1, &priv->linear_sampler);
3166   context->VSSetShader (priv->vs, nullptr, 0);
3167   context->PSSetConstantBuffers (0, 1, &priv->const_buffer);
3168   context->PSSetShaderResources (0, priv->num_input_view, srv);
3169   if (!priv->fast_path) {
3170     ID3D11ShaderResourceView *gamma_srv[2];
3171     gamma_srv[0] = priv->gamma_dec_srv;
3172     gamma_srv[1] = priv->gamma_enc_srv;
3173     context->PSSetShaderResources (4, 2, gamma_srv);
3174   }
3175
3176   context->PSSetShader (priv->ps[0], nullptr, 0);
3177   context->RSSetViewports (cinfo->ps_output[0]->num_rtv, priv->viewport);
3178   context->OMSetRenderTargets (cinfo->ps_output[0]->num_rtv, rtv, nullptr);
3179   if (priv->blend) {
3180     context->OMSetBlendState (priv->blend,
3181         priv->blend_factor, priv->blend_sample_mask);
3182   } else {
3183     context->OMSetBlendState (nullptr, nullptr, 0xffffffff);
3184   }
3185   context->DrawIndexed (6, 0, 0);
3186
3187   if (priv->ps[1]) {
3188     guint view_offset = cinfo->ps_output[0]->num_rtv;
3189
3190     context->PSSetShader (priv->ps[1], nullptr, 0);
3191     context->RSSetViewports (cinfo->ps_output[1]->num_rtv,
3192         &priv->viewport[view_offset]);
3193     context->OMSetRenderTargets (cinfo->ps_output[1]->num_rtv,
3194         &rtv[view_offset], nullptr);
3195     context->DrawIndexed (6, 0, 0);
3196   }
3197
3198   context->PSSetShaderResources (0, 4, clear_view);
3199   context->OMSetRenderTargets (0, nullptr, nullptr);
3200
3201   return TRUE;
3202 }
3203
3204 static gboolean
3205 gst_d3d11_converter_check_bind_flags_for_piv (guint bind_flags)
3206 {
3207   static const guint flags = (D3D11_BIND_DECODER |
3208       D3D11_BIND_VIDEO_ENCODER | D3D11_BIND_RENDER_TARGET |
3209       D3D11_BIND_UNORDERED_ACCESS);
3210
3211   if (bind_flags == 0)
3212     return TRUE;
3213
3214   if ((bind_flags & flags) != 0)
3215     return TRUE;
3216
3217   return FALSE;
3218 }
3219
3220 static gboolean
3221 gst_d3d11_converter_ensure_d3d11_buffer (GstD3D11Converter * self,
3222     GstBuffer * buffer)
3223 {
3224   if (gst_buffer_n_memory (buffer) == 0) {
3225     GST_WARNING_OBJECT (self, "Empty buffer");
3226     return FALSE;
3227   }
3228
3229   for (guint i = 0; i < gst_buffer_n_memory (buffer); i++) {
3230     GstMemory *mem = gst_buffer_peek_memory (buffer, i);
3231     GstD3D11Memory *dmem;
3232
3233     if (!gst_is_d3d11_memory (mem)) {
3234       GST_LOG_OBJECT (self, "Memory at %d is not d3d11 memory", i);
3235       return FALSE;
3236     }
3237
3238     dmem = GST_D3D11_MEMORY_CAST (mem);
3239     if (dmem->device != self->device) {
3240       GST_LOG_OBJECT (self, "Memory at %d belongs to different device", i);
3241       return FALSE;
3242     }
3243   }
3244
3245   return TRUE;
3246 }
3247
3248 static gboolean
3249 gst_d3d11_converter_create_fallback_buffer (GstD3D11Converter * self)
3250 {
3251   GstD3D11ConverterPrivate *priv = self->priv;
3252   GstD3D11AllocationParams *params;
3253   GstBufferPool *pool;
3254   GstCaps *caps;
3255   guint bind_flags = D3D11_BIND_SHADER_RESOURCE;
3256   GstStructure *config;
3257
3258   gst_clear_buffer (&priv->fallback_inbuf);
3259
3260   if (priv->processor)
3261     bind_flags |= D3D11_BIND_RENDER_TARGET;
3262
3263   params = gst_d3d11_allocation_params_new (self->device, &priv->fallback_info,
3264       GST_D3D11_ALLOCATION_FLAG_DEFAULT, bind_flags, 0);
3265
3266   caps = gst_video_info_to_caps (&priv->fallback_info);
3267   pool = gst_d3d11_buffer_pool_new (self->device);
3268
3269   config = gst_buffer_pool_get_config (pool);
3270   gst_buffer_pool_config_set_params (config, caps, priv->fallback_info.size,
3271       0, 0);
3272   gst_buffer_pool_config_set_d3d11_allocation_params (config, params);
3273   gst_caps_unref (caps);
3274   gst_d3d11_allocation_params_free (params);
3275
3276   if (!gst_buffer_pool_set_config (pool, config)) {
3277     GST_ERROR_OBJECT (self, "Failed to set pool config");
3278     gst_object_unref (pool);
3279     return FALSE;
3280   }
3281
3282   if (!gst_buffer_pool_set_active (pool, TRUE)) {
3283     GST_ERROR_OBJECT (self, "Failed to set active");
3284     gst_object_unref (pool);
3285     return FALSE;
3286   }
3287
3288   gst_buffer_pool_acquire_buffer (pool, &priv->fallback_inbuf, nullptr);
3289   gst_buffer_pool_set_active (pool, FALSE);
3290   gst_object_unref (pool);
3291
3292   if (!priv->fallback_inbuf) {
3293     GST_ERROR_OBJECT (self, "Failed to create fallback buffer");
3294     return FALSE;
3295   }
3296
3297   return TRUE;
3298 }
3299
3300 static gboolean
3301 gst_d3d11_converter_copy_buffer (GstD3D11Converter * self, GstBuffer * in_buf)
3302 {
3303   GstD3D11ConverterPrivate *priv = self->priv;
3304   GstVideoFrame frame, fallback_frame;
3305   GstVideoInfo *fallback_info = &priv->fallback_info;
3306   gboolean ret;
3307
3308   if (!gst_video_frame_map (&frame, &priv->in_info, in_buf, GST_MAP_READ)) {
3309     GST_ERROR_OBJECT (self, "Failed to map input buffer");
3310     return FALSE;
3311   }
3312
3313   /* Probably cropped buffer */
3314   if (fallback_info->width != GST_VIDEO_FRAME_WIDTH (&frame) ||
3315       fallback_info->height != GST_VIDEO_FRAME_HEIGHT (&frame)) {
3316     gst_clear_buffer (&priv->fallback_inbuf);
3317     *fallback_info = frame.info;
3318   }
3319
3320   if (!priv->fallback_inbuf &&
3321       !gst_d3d11_converter_create_fallback_buffer (self)) {
3322     goto error;
3323   }
3324
3325   if (!gst_video_frame_map (&fallback_frame,
3326           &priv->fallback_info, priv->fallback_inbuf, GST_MAP_WRITE)) {
3327     GST_ERROR_OBJECT (self, "Couldn't map fallback buffer");
3328     goto error;
3329   }
3330
3331   ret = gst_video_frame_copy (&fallback_frame, &frame);
3332   gst_video_frame_unmap (&fallback_frame);
3333   gst_video_frame_unmap (&frame);
3334
3335   return ret;
3336
3337 error:
3338   gst_video_frame_unmap (&frame);
3339   return FALSE;
3340 }
3341
3342 static gboolean
3343 gst_d3d11_converter_map_buffer (GstD3D11Converter * self, GstBuffer * buffer,
3344     GstMapInfo info[GST_VIDEO_MAX_PLANES], GstMapFlags flags)
3345 {
3346   GstMapFlags map_flags;
3347   guint num_mapped = 0;
3348
3349   map_flags = (GstMapFlags) (flags | GST_MAP_D3D11);
3350
3351   for (num_mapped = 0; num_mapped < gst_buffer_n_memory (buffer); num_mapped++) {
3352     GstMemory *mem = gst_buffer_peek_memory (buffer, num_mapped);
3353
3354     if (!gst_memory_map (mem, &info[num_mapped], map_flags)) {
3355       GST_WARNING_OBJECT (self, "Failed to map memory at %d", num_mapped);
3356       goto error;
3357     }
3358   }
3359
3360   return TRUE;
3361
3362 error:
3363   for (guint i = 0; i < num_mapped; i++) {
3364     GstMemory *mem = gst_buffer_peek_memory (buffer, i);
3365     gst_memory_unmap (mem, &info[i]);
3366   }
3367
3368   return FALSE;
3369 }
3370
3371 static void
3372 gst_d3d11_converter_unmap_buffer (GstD3D11Converter * self, GstBuffer * buffer,
3373     GstMapInfo info[GST_VIDEO_MAX_PLANES])
3374 {
3375   for (guint i = 0; i < gst_buffer_n_memory (buffer); i++) {
3376     GstMemory *mem = gst_buffer_peek_memory (buffer, i);
3377
3378     gst_memory_unmap (mem, &info[i]);
3379   }
3380 }
3381
3382 static guint
3383 gst_d3d11_converter_get_srv (GstD3D11Converter * self, GstBuffer * buffer,
3384     ID3D11ShaderResourceView * srv[GST_VIDEO_MAX_PLANES])
3385 {
3386   guint num_views = 0;
3387
3388   for (guint i = 0; i < gst_buffer_n_memory (buffer); i++) {
3389     GstD3D11Memory *mem = (GstD3D11Memory *) gst_buffer_peek_memory (buffer, i);
3390     guint num_view_in_mem;
3391
3392     num_view_in_mem = gst_d3d11_memory_get_shader_resource_view_size (mem);
3393     if (!num_view_in_mem)
3394       return 0;
3395
3396     for (guint j = 0; j < num_view_in_mem; j++) {
3397       if (num_views >= GST_VIDEO_MAX_PLANES) {
3398         GST_ERROR_OBJECT (self, "Too many SRV");
3399         return 0;
3400       }
3401
3402       srv[num_views] = gst_d3d11_memory_get_shader_resource_view (mem, j);
3403       num_views++;
3404     }
3405   }
3406
3407   return num_views;
3408 }
3409
3410 static guint
3411 gst_d3d11_converter_get_rtv (GstD3D11Converter * self, GstBuffer * buffer,
3412     ID3D11RenderTargetView * rtv[GST_VIDEO_MAX_PLANES])
3413 {
3414   guint num_views = 0;
3415
3416   for (guint i = 0; i < gst_buffer_n_memory (buffer); i++) {
3417     GstD3D11Memory *mem = (GstD3D11Memory *) gst_buffer_peek_memory (buffer, i);
3418     guint num_view_in_mem;
3419
3420     num_view_in_mem = gst_d3d11_memory_get_render_target_view_size (mem);
3421     if (!num_view_in_mem)
3422       return 0;
3423
3424     for (guint j = 0; j < num_view_in_mem; j++) {
3425       if (num_views >= GST_VIDEO_MAX_PLANES) {
3426         GST_ERROR_OBJECT (self, "Too many SRV");
3427         return 0;
3428       }
3429
3430       rtv[num_views] = gst_d3d11_memory_get_render_target_view (mem, j);
3431       num_views++;
3432     }
3433   }
3434
3435   return num_views;
3436 }
3437
3438 static gboolean
3439 gst_d3d11_converter_ensure_fallback_inbuf (GstD3D11Converter * self,
3440     GstBuffer * in_buf, GstMapInfo in_info[GST_VIDEO_MAX_PLANES])
3441 {
3442   GstD3D11ConverterPrivate *priv = self->priv;
3443   D3D11_TEXTURE2D_DESC desc[GST_VIDEO_MAX_PLANES];
3444   gboolean same_size = TRUE;
3445   ID3D11DeviceContext *context;
3446
3447   for (guint i = 0; i < gst_buffer_n_memory (in_buf); i++) {
3448     GstD3D11Memory *in_mem =
3449         (GstD3D11Memory *) gst_buffer_peek_memory (in_buf, i);
3450
3451     gst_d3d11_memory_get_texture_desc (in_mem, &desc[i]);
3452
3453     if (same_size && priv->fallback_inbuf) {
3454       D3D11_TEXTURE2D_DESC prev_desc;
3455       GstD3D11Memory *prev_mem =
3456           (GstD3D11Memory *) gst_buffer_peek_memory (priv->fallback_inbuf, i);
3457
3458       gst_d3d11_memory_get_texture_desc (prev_mem, &prev_desc);
3459
3460       if (prev_desc.Width != desc[i].Width ||
3461           prev_desc.Height != desc[i].Height) {
3462         same_size = FALSE;
3463       }
3464     }
3465   }
3466
3467   priv->fallback_info.width = desc[0].Width;
3468   priv->fallback_info.height = desc[0].Height;
3469
3470   if (priv->fallback_inbuf && !same_size) {
3471     GST_DEBUG_OBJECT (self,
3472         "Size of new buffer is different from previous fallback");
3473     gst_clear_buffer (&priv->fallback_inbuf);
3474   }
3475
3476   if (!priv->fallback_inbuf &&
3477       !gst_d3d11_converter_create_fallback_buffer (self)) {
3478     return FALSE;
3479   }
3480
3481   context = gst_d3d11_device_get_device_context_handle (self->device);
3482   for (guint i = 0; i < gst_buffer_n_memory (in_buf); i++) {
3483     GstMemory *mem = gst_buffer_peek_memory (priv->fallback_inbuf, i);
3484     GstD3D11Memory *dmem = GST_D3D11_MEMORY_CAST (mem);
3485     GstMapInfo info;
3486     ID3D11Resource *src_tex = (ID3D11Resource *) in_info[i].data;
3487     guint src_subresource = GPOINTER_TO_UINT (in_info[i].user_data[0]);
3488     ID3D11Resource *fallback_tex;
3489     D3D11_TEXTURE2D_DESC fallback_desc;
3490     D3D11_BOX src_box = { 0, };
3491
3492     if (!gst_memory_map (mem, &info, (GstMapFlags)
3493             (GST_MAP_WRITE | GST_MAP_D3D11))) {
3494       GST_ERROR_OBJECT (self, "Couldn't map fallback memory");
3495     }
3496
3497     fallback_tex = (ID3D11Resource *) info.data;
3498     gst_d3d11_memory_get_texture_desc (dmem, &fallback_desc);
3499
3500     src_box.left = 0;
3501     src_box.top = 0;
3502     src_box.front = 0;
3503     src_box.back = 1;
3504     src_box.right = MIN (fallback_desc.Width, desc[i].Width);
3505     src_box.bottom = MIN (fallback_desc.Height, desc[i].Height);
3506
3507     context->CopySubresourceRegion (fallback_tex, 0, 0, 0, 0,
3508         src_tex, src_subresource, &src_box);
3509     gst_memory_unmap (mem, &info);
3510   }
3511
3512   return TRUE;
3513 }
3514
3515 static void
3516 gst_d3d11_converter_fill_hdr10_meta (const GstVideoMasteringDisplayInfo * mdcv,
3517     const GstVideoContentLightLevel * cll, DXGI_HDR_METADATA_HDR10 * meta)
3518 {
3519   meta->RedPrimary[0] = mdcv->display_primaries[0].x;
3520   meta->RedPrimary[1] = mdcv->display_primaries[0].y;
3521   meta->GreenPrimary[0] = mdcv->display_primaries[1].x;
3522   meta->GreenPrimary[1] = mdcv->display_primaries[1].y;
3523   meta->BluePrimary[0] = mdcv->display_primaries[2].x;
3524   meta->BluePrimary[1] = mdcv->display_primaries[2].y;
3525   meta->WhitePoint[0] = mdcv->white_point.x;
3526   meta->WhitePoint[1] = mdcv->white_point.y;
3527   meta->MaxMasteringLuminance = mdcv->max_display_mastering_luminance;
3528   meta->MinMasteringLuminance = mdcv->min_display_mastering_luminance;
3529
3530   meta->MaxContentLightLevel = cll->max_content_light_level;
3531   meta->MaxFrameAverageLightLevel = cll->max_frame_average_light_level;
3532 }
3533
3534 /* called with prop lock */
3535 static void
3536 gst_d3d11_converter_update_hdr10_meta (GstD3D11Converter * self)
3537 {
3538   GstD3D11ConverterPrivate *priv = self->priv;
3539
3540   if (priv->in_hdr10_updated) {
3541     if (!priv->in_mdcv_str || !priv->in_cll_str) {
3542       priv->have_in_hdr10 = FALSE;
3543     } else {
3544       GstVideoMasteringDisplayInfo mdcv;
3545       GstVideoContentLightLevel cll;
3546
3547       if (gst_video_mastering_display_info_from_string (&mdcv,
3548               priv->in_mdcv_str) &&
3549           gst_video_content_light_level_from_string (&cll, priv->in_cll_str)) {
3550         gst_d3d11_converter_fill_hdr10_meta (&mdcv, &cll, &priv->in_hdr10_meta);
3551         priv->have_in_hdr10 = TRUE;
3552       } else {
3553         priv->have_in_hdr10 = FALSE;
3554       }
3555     }
3556
3557     priv->in_hdr10_updated = FALSE;
3558   }
3559
3560   if (priv->out_hdr10_updated) {
3561     if (!priv->in_mdcv_str || !priv->in_cll_str) {
3562       priv->have_out_hdr10 = FALSE;
3563     } else {
3564       GstVideoMasteringDisplayInfo mdcv;
3565       GstVideoContentLightLevel cll;
3566
3567       if (gst_video_mastering_display_info_from_string (&mdcv,
3568               priv->in_mdcv_str) &&
3569           gst_video_content_light_level_from_string (&cll, priv->in_cll_str)) {
3570         gst_d3d11_converter_fill_hdr10_meta (&mdcv, &cll, &priv->in_hdr10_meta);
3571         priv->have_out_hdr10 = TRUE;
3572       } else {
3573         priv->have_out_hdr10 = FALSE;
3574       }
3575     }
3576
3577     priv->out_hdr10_updated = FALSE;
3578   }
3579 }
3580
3581 static gboolean
3582 gst_d3d11_converter_convert_buffer_internal (GstD3D11Converter * self,
3583     GstBuffer * in_buf, GstBuffer * out_buf)
3584 {
3585   GstD3D11ConverterPrivate *priv = self->priv;
3586   ID3D11ShaderResourceView *srv[GST_VIDEO_MAX_PLANES] = { nullptr, };
3587   ID3D11RenderTargetView *rtv[GST_VIDEO_MAX_PLANES] = { nullptr, };
3588   ID3D11VideoProcessorInputView *piv = nullptr;
3589   ID3D11VideoProcessorOutputView *pov = nullptr;
3590   gboolean use_processor = FALSE;
3591   GstD3D11Memory *in_dmem;
3592   GstD3D11Memory *out_dmem;
3593   GstMapInfo in_info[GST_VIDEO_MAX_PLANES];
3594   GstMapInfo out_info[GST_VIDEO_MAX_PLANES];
3595   D3D11_TEXTURE2D_DESC in_desc, out_desc;
3596   guint num_srv, num_rtv;
3597   gboolean ret = FALSE;
3598   gboolean need_blend = FALSE;
3599
3600   /* Output buffer must be valid D3D11 buffer */
3601   if (!gst_d3d11_converter_ensure_d3d11_buffer (self, out_buf)) {
3602     GST_ERROR_OBJECT (self, "Output is not d3d11 buffer");
3603     return FALSE;
3604   }
3605
3606   if (gst_buffer_n_memory (in_buf) == 0) {
3607     GST_ERROR_OBJECT (self, "Empty buffer");
3608     return FALSE;
3609   }
3610
3611   /* But allows input copying */
3612   if (!gst_d3d11_converter_ensure_d3d11_buffer (self, in_buf)) {
3613     GST_LOG_OBJECT (self, "Input is not d3d11 buffer");
3614     if (!gst_d3d11_converter_copy_buffer (self, in_buf)) {
3615       GST_ERROR_OBJECT (self, "Couldn't copy into fallback buffer");
3616       return FALSE;
3617     }
3618
3619     in_buf = priv->fallback_inbuf;
3620   }
3621
3622   in_dmem = (GstD3D11Memory *) gst_buffer_peek_memory (in_buf, 0);
3623   out_dmem = (GstD3D11Memory *) gst_buffer_peek_memory (out_buf, 0);
3624
3625   if (!gst_d3d11_memory_get_texture_desc (in_dmem, &in_desc)) {
3626     GST_ERROR_OBJECT (self, "Failed to get input desc");
3627     return FALSE;
3628   }
3629
3630   if (!gst_d3d11_memory_get_texture_desc (out_dmem, &out_desc)) {
3631     GST_ERROR_OBJECT (self, "Failed to get output desc");
3632     return FALSE;
3633   }
3634
3635   if ((out_desc.BindFlags & D3D11_BIND_RENDER_TARGET) == 0) {
3636     GST_ERROR_OBJECT (self, "Output is not bound to render target");
3637     return FALSE;
3638   }
3639
3640   if (!gst_d3d11_converter_map_buffer (self, in_buf, in_info,
3641           (GstMapFlags) (GST_MAP_READ | GST_MAP_D3D11))) {
3642     GST_ERROR_OBJECT (self, "Couldn't map input buffer");
3643     return FALSE;
3644   }
3645
3646   if (!gst_d3d11_converter_map_buffer (self, out_buf, out_info,
3647           (GstMapFlags) (GST_MAP_WRITE | GST_MAP_D3D11))) {
3648     GST_ERROR_OBJECT (self, "Couldn't map output buffer");
3649     gst_d3d11_converter_unmap_buffer (self, in_buf, in_info);
3650     return FALSE;
3651   }
3652
3653   GstD3D11SRWLockGuard (&priv->prop_lock);
3654   gst_d3d11_converter_update_hdr10_meta (self);
3655
3656   if (priv->blend && priv->blend_desc.RenderTarget[0].BlendEnable) {
3657     if (priv->alpha != 1.0) {
3658       need_blend = TRUE;
3659     } else if ((priv->blend_desc.RenderTarget[0].SrcBlend ==
3660             D3D11_BLEND_BLEND_FACTOR
3661             || priv->blend_desc.RenderTarget[0].SrcBlend ==
3662             D3D11_BLEND_INV_BLEND_FACTOR)
3663         && (priv->blend_factor[0] != 1.0 || priv->blend_factor[1] != 1.0
3664             || priv->blend_factor[2] != 1.0 || priv->blend_factor[3] != 1.0)) {
3665       need_blend = TRUE;
3666     }
3667   }
3668
3669   if (priv->supported_backend == GST_D3D11_CONVERTER_BACKEND_VIDEO_PROCESSOR) {
3670     piv =
3671         gst_d3d11_memory_get_processor_input_view (in_dmem,
3672         priv->video_device, priv->enumerator);
3673     pov =
3674         gst_d3d11_memory_get_processor_output_view (out_dmem,
3675         priv->video_device, priv->enumerator);
3676
3677     use_processor = TRUE;
3678   } else if ((priv->supported_backend &
3679           GST_D3D11_CONVERTER_BACKEND_VIDEO_PROCESSOR) != 0 && !need_blend
3680       && gst_d3d11_converter_check_bind_flags_for_piv (in_desc.BindFlags)) {
3681     /* TODO: processor supports alpha blending */
3682
3683     /* Try processor when:
3684      * - We were using processor already
3685      * - or SRV is unavailable (likely from decoder output)
3686      * - or HDR10, as we don't support tone-mapping via shader yet
3687      */
3688     if (priv->processor_in_use ||
3689         (in_desc.BindFlags & D3D11_BIND_SHADER_RESOURCE) == 0 ||
3690         (priv->video_context2 && (priv->have_in_hdr10
3691                 || priv->have_out_hdr10))) {
3692       piv =
3693           gst_d3d11_memory_get_processor_input_view (in_dmem,
3694           priv->video_device, priv->enumerator);
3695       pov =
3696           gst_d3d11_memory_get_processor_output_view (out_dmem,
3697           priv->video_device, priv->enumerator);
3698     }
3699
3700     if (piv != nullptr && pov != nullptr)
3701       use_processor = TRUE;
3702   }
3703
3704   if (use_processor) {
3705     if (!pov) {
3706       GST_ERROR_OBJECT (self, "POV is unavailable");
3707       goto out;
3708     }
3709
3710     if (!piv) {
3711       if (!gst_d3d11_converter_ensure_fallback_inbuf (self, in_buf, in_info)) {
3712         GST_ERROR_OBJECT (self, "Couldn't copy into fallback texture");
3713         goto out;
3714       }
3715
3716       gst_d3d11_converter_unmap_buffer (self, in_buf, in_info);
3717       in_buf = priv->fallback_inbuf;
3718
3719       if (!gst_d3d11_converter_map_buffer (self,
3720               in_buf, in_info, (GstMapFlags) (GST_MAP_READ | GST_MAP_D3D11))) {
3721         GST_ERROR_OBJECT (self, "Couldn't map fallback buffer");
3722         in_buf = nullptr;
3723         goto out;
3724       }
3725
3726       in_dmem = (GstD3D11Memory *) gst_buffer_peek_memory (in_buf, 0);
3727       piv = gst_d3d11_memory_get_processor_input_view (in_dmem,
3728           priv->video_device, priv->enumerator);
3729       if (!piv) {
3730         GST_ERROR_OBJECT (self, "Couldn't get POV from fallback buffer");
3731         goto out;
3732       }
3733     }
3734   }
3735
3736   priv->processor_in_use = use_processor;
3737   if (use_processor && !priv->processor_direction_not_supported) {
3738     ID3D11VideoContext1 *video_ctx = priv->video_context;
3739     ID3D11VideoProcessor *proc = priv->processor;
3740     D3D11_VIDEO_PROCESSOR_STREAM stream = { 0, };
3741     HRESULT hr;
3742
3743     if (priv->update_dest_rect && !gst_d3d11_converter_update_dest_rect (self)) {
3744       GST_ERROR_OBJECT (self, "Failed to update dest rect");
3745       goto out;
3746     }
3747
3748     if (priv->update_src_rect && !gst_d3d11_converter_update_src_rect (self)) {
3749       GST_ERROR_OBJECT (self, "Cannot update src rect");
3750       goto out;
3751     }
3752
3753     video_ctx->VideoProcessorSetStreamSourceRect (proc,
3754         0, TRUE, &priv->src_rect);
3755     video_ctx->VideoProcessorSetStreamDestRect (proc,
3756         0, TRUE, &priv->dest_rect);
3757
3758     if (priv->clear_background) {
3759       video_ctx->VideoProcessorSetOutputTargetRect (proc,
3760           TRUE, &priv->dest_full_rect);
3761       video_ctx->VideoProcessorSetOutputBackgroundColor (proc,
3762           GST_VIDEO_INFO_IS_YUV (&priv->out_info), &priv->background_color);
3763     } else {
3764       video_ctx->VideoProcessorSetOutputTargetRect (proc, TRUE,
3765           &priv->dest_rect);
3766     }
3767
3768     if (priv->video_context2 &&
3769         (priv->processor_caps.FeatureCaps & FEATURE_CAPS_METADATA_HDR10) != 0) {
3770       if (priv->have_in_hdr10) {
3771         priv->video_context2->VideoProcessorSetStreamHDRMetaData (proc, 0,
3772             DXGI_HDR_METADATA_TYPE_HDR10, sizeof (DXGI_HDR_METADATA_HDR10),
3773             &priv->in_hdr10_meta);
3774       } else {
3775         priv->video_context2->VideoProcessorSetStreamHDRMetaData (proc, 0,
3776             DXGI_HDR_METADATA_TYPE_NONE, 0, nullptr);
3777       }
3778
3779       if (priv->have_out_hdr10) {
3780         priv->video_context2->VideoProcessorSetOutputHDRMetaData (proc,
3781             DXGI_HDR_METADATA_TYPE_HDR10, sizeof (DXGI_HDR_METADATA_HDR10),
3782             &priv->in_hdr10_meta);
3783       }
3784     }
3785
3786     if ((priv->processor_caps.FeatureCaps & FEATURE_CAPS_ROTATION) != 0) {
3787       video_ctx->VideoProcessorSetStreamRotation (proc, 0,
3788           priv->enable_rotation, priv->rotation);
3789     }
3790
3791     if ((priv->processor_caps.FeatureCaps & PROCESSOR_FEATURE_CAPS_MIRROR) != 0) {
3792       video_ctx->VideoProcessorSetStreamMirror (proc, 0, priv->enable_mirror,
3793           priv->flip_h, priv->flip_v);
3794     }
3795
3796     stream.Enable = TRUE;
3797     stream.pInputSurface = piv;
3798
3799     GST_TRACE_OBJECT (self, "Converting using processor");
3800
3801     hr = video_ctx->VideoProcessorBlt (proc, pov, 0, 1, &stream);
3802
3803     ret = gst_d3d11_result (hr, self->device);
3804     goto out;
3805   }
3806
3807   if ((priv->supported_backend & GST_D3D11_CONVERTER_BACKEND_SHADER) == 0) {
3808     GST_ERROR_OBJECT (self, "Conversion is not supported");
3809     goto out;
3810   }
3811
3812   num_rtv = gst_d3d11_converter_get_rtv (self, out_buf, rtv);
3813   if (!num_rtv) {
3814     GST_ERROR_OBJECT (self, "RTV is unavailable");
3815     goto out;
3816   }
3817
3818   num_srv = gst_d3d11_converter_get_srv (self, in_buf, srv);
3819   if (!num_srv) {
3820     if (in_buf == priv->fallback_inbuf) {
3821       GST_ERROR_OBJECT (self, "Unable to get SRV from fallback buffer");
3822       goto out;
3823     } else if (!gst_d3d11_converter_ensure_fallback_inbuf (self,
3824             in_buf, in_info)) {
3825       GST_ERROR_OBJECT (self, "Couldn't copy into fallback texture");
3826       goto out;
3827     }
3828
3829     gst_d3d11_converter_unmap_buffer (self, in_buf, in_info);
3830     in_buf = priv->fallback_inbuf;
3831
3832     if (!gst_d3d11_converter_map_buffer (self,
3833             in_buf, in_info, (GstMapFlags) (GST_MAP_READ | GST_MAP_D3D11))) {
3834       GST_ERROR_OBJECT (self, "Couldn't map fallback buffer");
3835       in_buf = nullptr;
3836       goto out;
3837     }
3838
3839     num_srv = gst_d3d11_converter_get_srv (self, in_buf, srv);
3840     if (!num_srv) {
3841       GST_ERROR_OBJECT (self, "Couldn't get SRV from fallback input");
3842       goto out;
3843     }
3844   }
3845
3846   GST_TRACE_OBJECT (self, "Converting using shader");
3847
3848   ret = gst_d3d11_converter_convert_internal (self, srv, rtv);
3849
3850 out:
3851   if (in_buf)
3852     gst_d3d11_converter_unmap_buffer (self, in_buf, in_info);
3853   gst_d3d11_converter_unmap_buffer (self, out_buf, out_info);
3854
3855   return ret;
3856 }
3857
3858 /**
3859  * gst_d3d11_converter_convert_buffer:
3860  * @converter: a #GstD3D11Converter
3861  * @in_buf: a #GstBuffer
3862  * @out_buf: a #GstBuffer
3863  *
3864  * Converts @in_buf into @out_buf
3865  *
3866  * Returns: %TRUE if conversion is successful
3867  *
3868  * Since: 1.22
3869  */
3870 gboolean
3871 gst_d3d11_converter_convert_buffer (GstD3D11Converter * converter,
3872     GstBuffer * in_buf, GstBuffer * out_buf)
3873 {
3874   g_return_val_if_fail (GST_IS_D3D11_CONVERTER (converter), FALSE);
3875   g_return_val_if_fail (GST_IS_BUFFER (in_buf), FALSE);
3876   g_return_val_if_fail (GST_IS_BUFFER (out_buf), FALSE);
3877
3878   GstD3D11DeviceLockGuard lk (converter->device);
3879
3880   return gst_d3d11_converter_convert_buffer_internal (converter,
3881       in_buf, out_buf);
3882 }
3883
3884 /**
3885  * gst_d3d11_converter_convert_buffer_unlocked:
3886  * @converter: a #GstD3D11Converter
3887  * @in_buf: a #GstBuffer
3888  * @out_buf: a #GstBuffer
3889  *
3890  * Converts @in_buf into @out_buf. Caller should take d3d11 device lock
3891  * in case that multiple threads can perform GPU processing using the
3892  * same #GstD3D11Device
3893  *
3894  * Returns: %TRUE if conversion is successful
3895  *
3896  * Since: 1.22
3897  */
3898
3899 gboolean
3900 gst_d3d11_converter_convert_buffer_unlocked (GstD3D11Converter * converter,
3901     GstBuffer * in_buf, GstBuffer * out_buf)
3902 {
3903   g_return_val_if_fail (GST_IS_D3D11_CONVERTER (converter), FALSE);
3904   g_return_val_if_fail (GST_IS_BUFFER (in_buf), FALSE);
3905   g_return_val_if_fail (GST_IS_BUFFER (out_buf), FALSE);
3906
3907   return gst_d3d11_converter_convert_buffer_internal (converter,
3908       in_buf, out_buf);
3909 }