1 /* GStreamer
2 * Copyright (C) <2019> Seungha Yang <seungha.yang@navercorp.com>
3 * Copyright (C) <2019> Jeongki Kim <jeongki.kim@jeongki.kim>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
24
25 #include "gstd3d11converter.h"
26 #include "gstd3d11shader.h"
27 #include "gstd3d11pluginutils.h"
28 #include <wrl.h>
29 #include <string.h>
30
31 GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_converter_debug);
32 #define GST_CAT_DEFAULT gst_d3d11_converter_debug
33
34 /* *INDENT-OFF* */
35 using namespace Microsoft::WRL;
36 /* *INDENT-ON* */
37
38 #define CONVERTER_MAX_QUADS 2
39
40 /* *INDENT-OFF* */
41 typedef struct
42 {
43 FLOAT trans_matrix[12];
44 FLOAT padding[4];
45 } PixelShaderColorTransform;
46
47 typedef struct
48 {
49 FLOAT alpha_mul;
50 FLOAT padding[3];
51 } AlphaConstBuffer;
52
53 typedef struct
54 {
55 struct {
56 FLOAT x;
57 FLOAT y;
58 FLOAT z;
59 } position;
60 struct {
61 FLOAT x;
62 FLOAT y;
63 } texture;
64 } VertexData;
65
66 typedef struct
67 {
68 gboolean has_transform;
69 gboolean has_alpha;
70 const gchar *func;
71 } PixelShaderTemplate;
72
73 static const gchar templ_color_transform_const_buffer[] =
74 "cbuffer PixelShaderColorTransform : register(b%u)\n"
75 "{\n"
76 " float3x4 trans_matrix;\n"
77 " float3 padding;\n"
78 "};";
79
80 static const gchar templ_alpha_const_buffer[] =
81 "cbuffer AlphaConstBuffer : register(b%u)\n"
82 "{\n"
83 " float alpha_mul;\n"
84 " float3 padding;\n"
85 "};";
86
87 #define HLSL_FUNC_YUV_TO_RGB \
88 "float3 yuv_to_rgb (float3 yuv)\n" \
89 "{\n" \
90 " yuv += float3(-0.062745f, -0.501960f, -0.501960f);\n" \
91 " yuv = mul(yuv, trans_matrix);\n" \
92 " return saturate(yuv);\n" \
93 "}\n"
94
95 #define HLSL_FUNC_RGB_TO_YUV \
96 "float3 rgb_to_yuv (float3 rgb)\n" \
97 "{\n" \
98 " float3 yuv;\n" \
99 " yuv = mul(rgb, trans_matrix);\n" \
100 " yuv += float3(0.062745f, 0.501960f, 0.501960f);\n" \
101 " return saturate(yuv);\n" \
102 "}\n"
103
104 #define HLSL_PS_OUTPUT_ONE_PLANE_BODY \
105 " float4 Plane_0: SV_TARGET0;"
106
107 #define HLSL_PS_OUTPUT_TWO_PLANES_BODY \
108 " float4 Plane_0: SV_TARGET0;\n" \
109 " float4 Plane_1: SV_TARGET1;"
110
111 static const PixelShaderTemplate templ_REORDER =
112 { FALSE, TRUE, NULL };
113
114 static const PixelShaderTemplate templ_REORDER_NO_ALPHA =
115 { FALSE, FALSE, NULL };
116
117 static const PixelShaderTemplate templ_YUV_to_RGB =
118 { TRUE, FALSE, HLSL_FUNC_YUV_TO_RGB };
119
120 static const PixelShaderTemplate templ_RGB_to_YUV =
121 { TRUE, FALSE, HLSL_FUNC_RGB_TO_YUV };
122
123 static const gchar templ_REORDER_BODY[] =
124 " float4 xyza;\n"
125 " xyza.xyz = shaderTexture[0].Sample(samplerState, input.Texture).xyz;\n"
126 " xyza.a = shaderTexture[0].Sample(samplerState, input.Texture).a * alpha_mul;\n"
127 " output.Plane_0 = xyza;\n";
128
129 static const gchar templ_VUYA_to_RGB_BODY[] =
130 " float4 sample, rgba;\n"
131 " sample.x = shaderTexture[0].Sample(samplerState, input.Texture).z;\n"
132 " sample.y = shaderTexture[0].Sample(samplerState, input.Texture).y;\n"
133 " sample.z = shaderTexture[0].Sample(samplerState, input.Texture).x;\n"
134 " sample.a = shaderTexture[0].Sample(samplerState, input.Texture).a;\n"
135 " rgba.rgb = yuv_to_rgb (sample.xyz);\n"
136 " rgba.a = sample.a;\n"
137 " output.Plane_0 = rgba;\n";
138
139 static const gchar templ_RGB_to_VUYA_BODY[] =
140 " float4 sample, vuya;\n"
141 " sample = shaderTexture[0].Sample(samplerState, input.Texture);\n"
142 " vuya.zyx = rgb_to_yuv (sample.rgb);\n"
143 " vuya.a = sample.a;\n"
144 " output.Plane_0 = vuya;\n";
145
146 static const gchar templ_PACKED_YUV_to_RGB_BODY[] =
147 " float4 sample, rgba;\n"
148 " sample.x = shaderTexture[0].Sample(samplerState, input.Texture).%c;\n"
149 " sample.y = shaderTexture[0].Sample(samplerState, input.Texture).%c;\n"
150 " sample.z = shaderTexture[0].Sample(samplerState, input.Texture).%c;\n"
151 " rgba.rgb = yuv_to_rgb (sample.xyz);\n"
152 " rgba.a = 1;\n"
153 " output.Plane_0 = rgba;\n";
154
155 /* YUV to RGB conversion */
156 static const gchar templ_PLANAR_YUV_to_RGB_BODY[] =
157 " float4 sample, rgba;\n"
158 " sample.x = shaderTexture[0].Sample(samplerState, input.Texture).x * %u;\n"
159 " sample.%c = shaderTexture[1].Sample(samplerState, input.Texture).x * %u;\n"
160 " sample.%c = shaderTexture[2].Sample(samplerState, input.Texture).x * %u;\n"
161 " rgba.rgb = yuv_to_rgb (sample.xyz);\n"
162 " rgba.a = 1.0;\n"
163 " output.Plane_0 = rgba;\n";
164
165 static const gchar templ_SEMI_PLANAR_to_RGB_BODY[] =
166 " float4 sample, rgba;\n"
167 " sample.x = shaderTexture[0].Sample(samplerState, input.Texture).x;\n"
168 " sample.yz = shaderTexture[1].Sample(samplerState, input.Texture).%c%c;\n"
169 " rgba.rgb = yuv_to_rgb (sample.xyz);\n"
170 " rgba.a = 1.0;\n"
171 " output.Plane_0 = rgba;\n";
172
173 /* RGB to YUV conversion */
174 static const gchar templ_RGB_to_LUMA_BODY[] =
175 " float4 sample, rgba;\n"
176 " rgba.rgb = shaderTexture[0].Sample(samplerState, input.Texture).rgb;\n"
177 " sample.xyz = rgb_to_yuv (rgba.rgb);\n"
178 " sample.y = 0.0;\n"
179 " sample.z = 0.0;\n"
180 " sample.a = 0.0;\n"
181 " sample.x = sample.x / %d;\n"
182 " output.Plane_0 = sample;\n";
183
184 static const gchar templ_RGB_to_SEMI_PLANAR_CHROMA_BODY[] =
185 " float4 sample, rgba;\n"
186 " rgba.rgb = shaderTexture[0].Sample(samplerState, input.Texture).rgb;\n"
187 " sample.xyz = rgb_to_yuv (rgba.rgb);\n"
188 " sample.%c = sample.y;\n"
189 " sample.%c = sample.z;\n"
190 " sample.z = 0.0;\n"
191 " sample.a = 0.0;\n"
192 " output.Plane_0 = sample;\n";
193
194 static const gchar templ_RGB_to_PLANAR_CHROMA_BODY[] =
195 " float4 sample, rgba;\n"
196 " rgba.rgb = shaderTexture[0].Sample(samplerState, input.Texture).rgb;\n"
197 " sample.xyz = rgb_to_yuv (rgba.rgb);\n"
198 " output.Plane_0 = float4(sample.%c / %u, 0.0, 0.0, 0.0);\n"
199 " output.Plane_1 = float4(sample.%c / %u, 0.0, 0.0, 0.0);\n";
200
201 /* YUV to YUV conversion */
202 static const gchar templ_LUMA_to_LUMA_BODY[] =
203 " float4 sample;\n"
204 " sample.x = shaderTexture[0].Sample(samplerState, input.Texture).x * %u;\n"
205 " output.Plane_0 = float4(sample.x / %u, 0.0, 0.0, 0.0);\n";
206
207 static const gchar templ_PLANAR_TO_SEMI_PLANAR_CHROMA_BODY[] =
208 " float4 in_sample;\n"
209 " float4 out_sample;\n"
210 " in_sample.%c = shaderTexture[1].Sample(samplerState, input.Texture).x * %u;\n"
211 " in_sample.%c = shaderTexture[2].Sample(samplerState, input.Texture).x * %u;\n"
212 " out_sample.xy = in_sample.yz;\n"
213 " output.Plane_0 = float4(out_sample.%c%c, 0.0, 0.0);\n";
214
215 static const gchar templ_SEMI_PLANAR_TO_PLANAR_CHROMA_BODY[] =
216 " float4 sample;\n"
217 " sample.yz = shaderTexture[1].Sample(samplerState, input.Texture).%c%c;\n"
218 " output.Plane_0 = float4(sample.%c / %d, 0.0, 0.0, 0.0);\n"
219 " output.Plane_1 = float4(sample.%c / %d, 0.0, 0.0, 0.0);\n";
220
221 static const gchar templ_SEMI_PLANAR_TO_SEMI_PLANAR_CHROMA_BODY[] =
222 " float4 sample;\n"
223 " sample.xy = shaderTexture[1].Sample(samplerState, input.Texture).%c%c;\n"
224 " output.Plane_0 = float4(sample.%c%c, 0.0, 0.0);\n";
225
226 static const gchar templ_PLANAR_TO_PLANAR_CHROMA_BODY[] =
227 " float4 sample;\n"
228 " sample.%c = shaderTexture[1].Sample(samplerState, input.Texture).x * %u;\n"
229 " sample.%c = shaderTexture[2].Sample(samplerState, input.Texture).x * %u;\n"
230 " output.Plane_0 = float4(sample.%c / %u, 0.0, 0.0, 0.0);\n"
231 " output.Plane_1 = float4(sample.%c / %u, 0.0, 0.0, 0.0);\n";
232
233 /* VUYA to YUV */
234 static const gchar templ_VUYA_to_LUMA_BODY[] =
235 " float4 sample;\n"
236 " sample.x = shaderTexture[0].Sample(samplerState, input.Texture).z;\n"
237 " output.Plane_0 = float4(sample.x / %u, 0.0, 0.0, 0.0);\n";
238
239 static const gchar templ_VUYA_TO_PLANAR_CHROMA_BODY[] =
240 " float4 sample;\n"
241 " sample.yz = shaderTexture[0].Sample(samplerState, input.Texture).yx;\n"
242 " output.Plane_0 = float4(sample.%c / %d, 0.0, 0.0, 0.0);\n"
243 " output.Plane_1 = float4(sample.%c / %d, 0.0, 0.0, 0.0);\n";
244
245 static const gchar templ_VUYA_TO_SEMI_PLANAR_CHROMA_BODY[] =
246 " float2 sample;\n"
247 " sample.xy = shaderTexture[0].Sample(samplerState, input.Texture).%c%c;\n"
248 " output.Plane_0 = float4(sample.xy, 0.0, 0.0);\n";
249
250 /* YUV to VUYA */
251 static const gchar templ_PLANAR_to_VUYA_BODY[] =
252 " float4 sample;\n"
253 " sample.x = shaderTexture[0].Sample(samplerState, input.Texture).x * %u;\n"
254 " sample.%c = shaderTexture[1].Sample(samplerState, input.Texture).x * %u;\n"
255 " sample.%c = shaderTexture[2].Sample(samplerState, input.Texture).x * %u;\n"
256 " output.Plane_0 = float4(sample.zyx, 1.0f);\n";
257
258 static const gchar templ_SEMI_PLANAR_to_VUYA_BODY[] =
259 " float4 sample;\n"
260 " sample.z = shaderTexture[0].Sample(samplerState, input.Texture).x;\n"
261 " sample.xy = shaderTexture[1].Sample(samplerState, input.Texture).%c%c;\n"
262 " output.Plane_0 = float4(sample.xyz, 1.0f);\n";
263
264 static const gchar templ_PACKED_YUV_to_VUYA_BODY[] =
265 " float4 sample;\n"
266 " sample.z = shaderTexture[0].Sample(samplerState, input.Texture).%c;\n"
267 " sample.y = shaderTexture[0].Sample(samplerState, input.Texture).%c;\n"
268 " sample.x = shaderTexture[0].Sample(samplerState, input.Texture).%c;\n"
269 " output.Plane_0 = float4(sample.xyz, 1.0f);\n";
270
271 /* packed YUV to (semi) planar YUV */
272 static const gchar templ_PACKED_YUV_to_LUMA_BODY[] =
273 " float4 sample;\n"
274 " sample.x = shaderTexture[0].Sample(samplerState, input.Texture).%c;\n"
275 " output.Plane_0 = float4(sample.x / %u, 0.0, 0.0, 0.0);\n";
276
277 static const gchar templ_PACKED_YUV_TO_PLANAR_CHROMA_BODY[] =
278 " float4 sample;\n"
279 " sample.y = shaderTexture[0].Sample(samplerState, input.Texture).%c;\n"
280 " sample.z = shaderTexture[0].Sample(samplerState, input.Texture).%c;\n"
281 " output.Plane_0 = float4(sample.%c / %u, 0.0, 0.0, 0.0);\n"
282 " output.Plane_1 = float4(sample.%c / %u, 0.0, 0.0, 0.0);\n";
283
284 static const gchar templ_PACKED_YUV_TO_SEMI_PLANAR_CHROMA_BODY[] =
285 " float4 sample;\n"
286 " sample.x = shaderTexture[0].Sample(samplerState, input.Texture).%c;\n"
287 " sample.y = shaderTexture[0].Sample(samplerState, input.Texture).%c;\n"
288 " output.Plane_0 = float4(sample.%c%c, 0.0, 0.0);\n";
289
290 /* to GRAY */
291 static const gchar templ_RGB_to_GRAY_BODY[] =
292 " float4 sample, rgba;\n"
293 " rgba.rgb = shaderTexture[0].Sample(samplerState, input.Texture).rgb;\n"
294 " sample.x = rgb_to_yuv (rgba.rgb).x;\n"
295 " sample.y = 0.0;\n"
296 " sample.z = 0.0;\n"
297 " sample.a = 0.0;\n"
298 " output.Plane_0 = sample;\n";
299
300 static const gchar templ_VUYA_to_GRAY_BODY[] =
301 " float4 sample;\n"
302 " sample.x = shaderTexture[0].Sample(samplerState, input.Texture).z;\n"
303 " sample.y = 0.0;\n"
304 " sample.z = 0.0;\n"
305 " sample.a = 0.0;\n"
306 " output.Plane_0 = sample;\n";
307
308 static const gchar templ_YUV_to_GRAY_BODY[] =
309 " float4 sample;\n"
310 " sample.x = shaderTexture[0].Sample(samplerState, input.Texture).x * %u;\n"
311 " sample.y = 0.0;\n"
312 " sample.z = 0.0;\n"
313 " sample.a = 0.0;\n"
314 " output.Plane_0 = sample;\n";
315
316 static const gchar templ_PACKED_YUV_TO_GRAY[] =
317 " float4 sample;\n"
318 " sample.x = shaderTexture[0].Sample(samplerState, input.Texture).%c;\n"
319 " sample.y = 0.0;\n"
320 " sample.z = 0.0;\n"
321 " sample.a = 0.0;\n"
322 " output.Plane_0 = sample;\n";
323
324 static const gchar templ_GRAY_to_GRAY_BODY[] =
325 " float4 sample;\n"
326 " sample.x = shaderTexture[0].Sample(samplerState, input.Texture).x;\n"
327 " sample.y = 0.0;\n"
328 " sample.z = 0.0;\n"
329 " sample.a = 0.0;\n"
330 " output.Plane_0 = sample;\n";
331
332 /* from GRAY */
333 static const gchar templ_GRAY_to_RGB_BODY[] =
334 " float4 sample, rgba;\n"
335 " sample.x = shaderTexture[0].Sample(samplerState, input.Texture).x;\n"
336 " sample.y = sample.x;\n"
337 " sample.z = sample.x;\n"
338 " sample.a = 1.0;\n"
339 " output.Plane_0 = sample;\n";
340
341 static const gchar templ_GRAY_to_VUYA_BODY[] =
342 " float4 sample;\n"
343 " sample.z = shaderTexture[0].Sample(samplerState, input.Texture).x;\n"
344 " sample.x = 0.5;\n"
345 " sample.y = 0.5;\n"
346 " sample.a = 1.0;\n"
347 " output.Plane_0 = sample;\n";
348
349 static const gchar templ_GRAY_to_LUMA_BODY[] =
350 " float4 sample;\n"
351 " sample.x = shaderTexture[0].Sample(samplerState, input.Texture).x / %u;\n"
352 " sample.y = 0.0;\n"
353 " sample.z = 0.0;\n"
354 " sample.a = 0.0;\n"
355 " output.Plane_0 = sample;\n";
356
357 static const gchar templ_GRAY_to_PLANAR_CHROMA_BODY[] =
358 " float val = 0.5 / %u;\n"
359 " output.Plane_0 = float4(val, 0.0, 0.0, 0.0);\n"
360 " output.Plane_1 = float4(val, 0.0, 0.0, 0.0);\n";
361
362 static const gchar templ_GRAY_to_SEMI_PLANAR_CHROMA_BODY[] =
363 " output.Plane_0 = float4(0.5, 0.5, 0.0, 0.0);\n";
364
365 static const gchar templ_pixel_shader[] =
366 /* constant buffer */
367 "%s\n"
368 "%s\n"
369 "Texture2D shaderTexture[4];\n"
370 "SamplerState samplerState;\n"
371 "\n"
372 "struct PS_INPUT\n"
373 "{\n"
374 " float4 Position: SV_POSITION;\n"
375 " float3 Texture: TEXCOORD0;\n"
376 "};\n"
377 "\n"
378 "struct PS_OUTPUT\n"
379 "{\n"
380 " %s\n"
381 "};\n"
382 "\n"
383 /* rgb <-> yuv function */
384 "%s\n"
385 "PS_OUTPUT main(PS_INPUT input)\n"
386 "{\n"
387 " PS_OUTPUT output;\n"
388 "%s"
389 " return output;\n"
390 "}\n";
391
392 static const gchar templ_vertex_shader[] =
393 "struct VS_INPUT\n"
394 "{\n"
395 " float4 Position : POSITION;\n"
396 " float4 Texture : TEXCOORD0;\n"
397 "};\n"
398 "\n"
399 "struct VS_OUTPUT\n"
400 "{\n"
401 " float4 Position: SV_POSITION;\n"
402 " float4 Texture: TEXCOORD0;\n"
403 "};\n"
404 "\n"
405 "VS_OUTPUT main(VS_INPUT input)\n"
406 "{\n"
407 " return input;\n"
408 "}\n";
409
410 /* *INDENT-ON* */
411
412 typedef struct
413 {
414 const PixelShaderTemplate *templ;
415 gchar *ps_body[CONVERTER_MAX_QUADS];
416 const gchar *ps_output[CONVERTER_MAX_QUADS];
417 PixelShaderColorTransform transform;
418 } ConvertInfo;
419
420 struct _GstD3D11Converter
421 {
422 GstD3D11Device *device;
423 GstVideoInfo in_info;
424 GstVideoInfo out_info;
425 gdouble alpha;
426
427 const GstD3D11Format *in_d3d11_format;
428 const GstD3D11Format *out_d3d11_format;
429
430 guint num_input_view;
431 guint num_output_view;
432
433 GstD3D11Quad *quad[CONVERTER_MAX_QUADS];
434
435 D3D11_VIEWPORT viewport[GST_VIDEO_MAX_PLANES];
436
437 RECT src_rect;
438 RECT dest_rect;
439 gint input_texture_width;
440 gint input_texture_height;
441 ID3D11Buffer *vertex_buffer;
442 ID3D11Buffer *alpha_const_buffer;
443 gboolean update_vertex;
444 gboolean update_alpha;
445
446 ID3D11SamplerState *linear_sampler;
447
448 ConvertInfo convert_info;
449
450 GstStructure *config;
451 };
452
453 static gdouble
get_opt_double(GstD3D11Converter * self,const gchar * opt,gdouble def)454 get_opt_double (GstD3D11Converter * self, const gchar * opt, gdouble def)
455 {
456 gdouble res;
457 if (!gst_structure_get_double (self->config, opt, &res))
458 res = def;
459
460 return res;
461 }
462
463 #define DEFAULT_OPT_ALPHA_VALUE 1.0
464
465 #define GET_OPT_ALPHA_VALUE(c) get_opt_double(c, \
466 GST_D3D11_CONVERTER_OPT_ALPHA_VALUE, DEFAULT_OPT_ALPHA_VALUE);
467
468 /* from video-converter.c */
469 typedef struct
470 {
471 gfloat dm[4][4];
472 } MatrixData;
473
474 static void
color_matrix_set_identity(MatrixData * m)475 color_matrix_set_identity (MatrixData * m)
476 {
477 gint i, j;
478
479 for (i = 0; i < 4; i++) {
480 for (j = 0; j < 4; j++) {
481 m->dm[i][j] = (i == j);
482 }
483 }
484 }
485
486 static void
color_matrix_copy(MatrixData * d,const MatrixData * s)487 color_matrix_copy (MatrixData * d, const MatrixData * s)
488 {
489 gint i, j;
490
491 for (i = 0; i < 4; i++)
492 for (j = 0; j < 4; j++)
493 d->dm[i][j] = s->dm[i][j];
494 }
495
496 /* Perform 4x4 matrix multiplication:
497 * - @dst@ = @a@ * @b@
498 * - @dst@ may be a pointer to @a@ andor @b@
499 */
500 static void
color_matrix_multiply(MatrixData * dst,MatrixData * a,MatrixData * b)501 color_matrix_multiply (MatrixData * dst, MatrixData * a, MatrixData * b)
502 {
503 MatrixData tmp;
504 gint i, j, k;
505
506 for (i = 0; i < 4; i++) {
507 for (j = 0; j < 4; j++) {
508 gfloat x = 0;
509 for (k = 0; k < 4; k++) {
510 x += a->dm[i][k] * b->dm[k][j];
511 }
512 tmp.dm[i][j] = x;
513 }
514 }
515 color_matrix_copy (dst, &tmp);
516 }
517
518 static void
color_matrix_offset_components(MatrixData * m,gfloat a1,gfloat a2,gfloat a3)519 color_matrix_offset_components (MatrixData * m, gfloat a1, gfloat a2, gfloat a3)
520 {
521 MatrixData a;
522
523 color_matrix_set_identity (&a);
524 a.dm[0][3] = a1;
525 a.dm[1][3] = a2;
526 a.dm[2][3] = a3;
527 color_matrix_multiply (m, &a, m);
528 }
529
530 static void
color_matrix_scale_components(MatrixData * m,gfloat a1,gfloat a2,gfloat a3)531 color_matrix_scale_components (MatrixData * m, gfloat a1, gfloat a2, gfloat a3)
532 {
533 MatrixData a;
534
535 color_matrix_set_identity (&a);
536 a.dm[0][0] = a1;
537 a.dm[1][1] = a2;
538 a.dm[2][2] = a3;
539 color_matrix_multiply (m, &a, m);
540 }
541
542 static void
color_matrix_debug(GstD3D11Converter * self,const MatrixData * s)543 color_matrix_debug (GstD3D11Converter * self, const MatrixData * s)
544 {
545 GST_DEBUG ("[%f %f %f %f]",
546 s->dm[0][0], s->dm[0][1], s->dm[0][2], s->dm[0][3]);
547 GST_DEBUG ("[%f %f %f %f]",
548 s->dm[1][0], s->dm[1][1], s->dm[1][2], s->dm[1][3]);
549 GST_DEBUG ("[%f %f %f %f]",
550 s->dm[2][0], s->dm[2][1], s->dm[2][2], s->dm[2][3]);
551 GST_DEBUG ("[%f %f %f %f]",
552 s->dm[3][0], s->dm[3][1], s->dm[3][2], s->dm[3][3]);
553 }
554
555 static void
color_matrix_YCbCr_to_RGB(MatrixData * m,gfloat Kr,gfloat Kb)556 color_matrix_YCbCr_to_RGB (MatrixData * m, gfloat Kr, gfloat Kb)
557 {
558 gfloat Kg = 1.0 - Kr - Kb;
559 MatrixData k = {
560 {
561 {1., 0., 2 * (1 - Kr), 0.},
562 {1., -2 * Kb * (1 - Kb) / Kg, -2 * Kr * (1 - Kr) / Kg, 0.},
563 {1., 2 * (1 - Kb), 0., 0.},
564 {0., 0., 0., 1.},
565 }
566 };
567
568 color_matrix_multiply (m, &k, m);
569 }
570
571 static void
color_matrix_RGB_to_YCbCr(MatrixData * m,gfloat Kr,gfloat Kb)572 color_matrix_RGB_to_YCbCr (MatrixData * m, gfloat Kr, gfloat Kb)
573 {
574 gfloat Kg = 1.0 - Kr - Kb;
575 MatrixData k;
576 gfloat x;
577
578 k.dm[0][0] = Kr;
579 k.dm[0][1] = Kg;
580 k.dm[0][2] = Kb;
581 k.dm[0][3] = 0;
582
583 x = 1 / (2 * (1 - Kb));
584 k.dm[1][0] = -x * Kr;
585 k.dm[1][1] = -x * Kg;
586 k.dm[1][2] = x * (1 - Kb);
587 k.dm[1][3] = 0;
588
589 x = 1 / (2 * (1 - Kr));
590 k.dm[2][0] = x * (1 - Kr);
591 k.dm[2][1] = -x * Kg;
592 k.dm[2][2] = -x * Kb;
593 k.dm[2][3] = 0;
594
595 k.dm[3][0] = 0;
596 k.dm[3][1] = 0;
597 k.dm[3][2] = 0;
598 k.dm[3][3] = 1;
599
600 color_matrix_multiply (m, &k, m);
601 }
602
603 static void
compute_matrix_to_RGB(GstD3D11Converter * self,MatrixData * data,GstVideoInfo * info)604 compute_matrix_to_RGB (GstD3D11Converter * self, MatrixData * data,
605 GstVideoInfo * info)
606 {
607 gdouble Kr = 0, Kb = 0;
608 gint offset[4], scale[4];
609
610 /* bring color components to [0..1.0] range */
611 gst_video_color_range_offsets (info->colorimetry.range, info->finfo, offset,
612 scale);
613
614 color_matrix_offset_components (data, -offset[0], -offset[1], -offset[2]);
615 color_matrix_scale_components (data, 1 / ((float) scale[0]),
616 1 / ((float) scale[1]), 1 / ((float) scale[2]));
617
618 if (!GST_VIDEO_INFO_IS_RGB (info)) {
619 /* bring components to R'G'B' space */
620 if (gst_video_color_matrix_get_Kr_Kb (info->colorimetry.matrix, &Kr, &Kb))
621 color_matrix_YCbCr_to_RGB (data, Kr, Kb);
622 }
623 color_matrix_debug (self, data);
624 }
625
626 static void
compute_matrix_to_YUV(GstD3D11Converter * self,MatrixData * data,GstVideoInfo * info)627 compute_matrix_to_YUV (GstD3D11Converter * self, MatrixData * data,
628 GstVideoInfo * info)
629 {
630 gdouble Kr = 0, Kb = 0;
631 gint offset[4], scale[4];
632
633 if (!GST_VIDEO_INFO_IS_RGB (info)) {
634 /* bring components to YCbCr space */
635 if (gst_video_color_matrix_get_Kr_Kb (info->colorimetry.matrix, &Kr, &Kb))
636 color_matrix_RGB_to_YCbCr (data, Kr, Kb);
637 }
638
639 /* bring color components to nominal range */
640 gst_video_color_range_offsets (info->colorimetry.range, info->finfo, offset,
641 scale);
642
643 color_matrix_scale_components (data, (float) scale[0], (float) scale[1],
644 (float) scale[2]);
645 color_matrix_offset_components (data, offset[0], offset[1], offset[2]);
646
647 color_matrix_debug (self, data);
648 }
649
650 static gboolean
converter_get_matrix(GstD3D11Converter * self,MatrixData * matrix,GstVideoInfo * in_info,GstVideoInfo * out_info)651 converter_get_matrix (GstD3D11Converter * self, MatrixData * matrix,
652 GstVideoInfo * in_info, GstVideoInfo * out_info)
653 {
654 gboolean same_matrix;
655 guint in_bits, out_bits;
656
657 in_bits = GST_VIDEO_INFO_COMP_DEPTH (in_info, 0);
658 out_bits = GST_VIDEO_INFO_COMP_DEPTH (out_info, 0);
659
660 same_matrix = in_info->colorimetry.matrix == out_info->colorimetry.matrix;
661
662 GST_DEBUG ("matrix %d -> %d (%d)", in_info->colorimetry.matrix,
663 out_info->colorimetry.matrix, same_matrix);
664
665 color_matrix_set_identity (matrix);
666
667 if (same_matrix) {
668 GST_DEBUG ("conversion matrix is not required");
669 return FALSE;
670 }
671
672 if (in_bits < out_bits) {
673 gint scale = 1 << (out_bits - in_bits);
674 color_matrix_scale_components (matrix,
675 1 / (float) scale, 1 / (float) scale, 1 / (float) scale);
676 }
677
678 GST_DEBUG ("to RGB matrix");
679 compute_matrix_to_RGB (self, matrix, in_info);
680 GST_DEBUG ("current matrix");
681 color_matrix_debug (self, matrix);
682
683 GST_DEBUG ("to YUV matrix");
684 compute_matrix_to_YUV (self, matrix, out_info);
685 GST_DEBUG ("current matrix");
686 color_matrix_debug (self, matrix);
687
688 if (in_bits > out_bits) {
689 gint scale = 1 << (in_bits - out_bits);
690 color_matrix_scale_components (matrix,
691 (float) scale, (float) scale, (float) scale);
692 }
693
694 GST_DEBUG ("final matrix");
695 color_matrix_debug (self, matrix);
696
697 return TRUE;
698 }
699
700 static gboolean
setup_convert_info_rgb_to_rgb(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)701 setup_convert_info_rgb_to_rgb (GstD3D11Converter * self,
702 const GstVideoInfo * in_info, const GstVideoInfo * out_info)
703 {
704 ConvertInfo *convert_info = &self->convert_info;
705
706 convert_info->templ = &templ_REORDER;
707 convert_info->ps_body[0] = g_strdup_printf (templ_REORDER_BODY);
708 convert_info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
709
710 return TRUE;
711 }
712
713 static gboolean
get_packed_yuv_components(GstD3D11Converter * self,GstVideoFormat format,gchar * y,gchar * u,gchar * v)714 get_packed_yuv_components (GstD3D11Converter * self, GstVideoFormat
715 format, gchar * y, gchar * u, gchar * v)
716 {
717 switch (format) {
718 case GST_VIDEO_FORMAT_YUY2:
719 {
720 const GstD3D11Format *d3d11_format =
721 gst_d3d11_device_format_from_gst (self->device,
722 GST_VIDEO_FORMAT_YUY2);
723
724 g_assert (d3d11_format != NULL);
725
726 if (d3d11_format->resource_format[0] == DXGI_FORMAT_R8G8B8A8_UNORM) {
727 *y = 'x';
728 *u = 'y';
729 *v = 'a';
730 } else if (d3d11_format->resource_format[0] ==
731 DXGI_FORMAT_G8R8_G8B8_UNORM) {
732 *y = 'y';
733 *u = 'x';
734 *v = 'z';
735 } else {
736 g_assert_not_reached ();
737 return FALSE;
738 }
739 break;
740 }
741 case GST_VIDEO_FORMAT_UYVY:
742 *y = 'y';
743 *u = 'x';
744 *v = 'z';
745 break;
746 case GST_VIDEO_FORMAT_VYUY:
747 *y = 'y';
748 *u = 'z';
749 *v = 'x';
750 break;
751 case GST_VIDEO_FORMAT_Y210:
752 *y = 'r';
753 *u = 'g';
754 *v = 'a';
755 break;
756 case GST_VIDEO_FORMAT_Y410:
757 *y = 'g';
758 *u = 'r';
759 *v = 'b';
760 break;
761 default:
762 g_assert_not_reached ();
763 return FALSE;
764 }
765
766 return TRUE;
767 }
768
769 static void
get_planar_component(const GstVideoInfo * info,gchar * u,gchar * v,guint * scale)770 get_planar_component (const GstVideoInfo * info, gchar * u, gchar * v,
771 guint * scale)
772 {
773 switch (GST_VIDEO_INFO_FORMAT (info)) {
774 case GST_VIDEO_FORMAT_I420_10LE:
775 case GST_VIDEO_FORMAT_I422_10LE:
776 case GST_VIDEO_FORMAT_Y444_10LE:
777 *scale = (1 << 6);
778 break;
779 case GST_VIDEO_FORMAT_I420_12LE:
780 case GST_VIDEO_FORMAT_I422_12LE:
781 case GST_VIDEO_FORMAT_Y444_12LE:
782 *scale = (1 << 4);
783 break;
784 default:
785 *scale = 1;
786 break;
787 }
788
789 if (GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_YV12) {
790 *u = 'z';
791 *v = 'y';
792 } else {
793 *u = 'y';
794 *v = 'z';
795 }
796 }
797
798 static void
get_semi_planar_component(const GstVideoInfo * info,gchar * u,gchar * v)799 get_semi_planar_component (const GstVideoInfo * info, gchar * u, gchar * v)
800 {
801 if (GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_NV21) {
802 *u = 'y';
803 *v = 'x';
804 } else {
805 *u = 'x';
806 *v = 'y';
807 }
808 }
809
810 static gboolean
setup_convert_info_yuv_to_rgb(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)811 setup_convert_info_yuv_to_rgb (GstD3D11Converter * self,
812 const GstVideoInfo * in_info, const GstVideoInfo * out_info)
813 {
814 ConvertInfo *info = &self->convert_info;
815
816 info->templ = &templ_YUV_to_RGB;
817 info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
818
819 switch (GST_VIDEO_INFO_FORMAT (in_info)) {
820 case GST_VIDEO_FORMAT_VUYA:
821 info->ps_body[0] = g_strdup_printf (templ_VUYA_to_RGB_BODY);
822 break;
823 case GST_VIDEO_FORMAT_YUY2:
824 case GST_VIDEO_FORMAT_UYVY:
825 case GST_VIDEO_FORMAT_VYUY:
826 case GST_VIDEO_FORMAT_Y210:
827 case GST_VIDEO_FORMAT_Y410:
828 {
829 gchar y, u, v;
830 if (!get_packed_yuv_components (self, GST_VIDEO_INFO_FORMAT (in_info),
831 &y, &u, &v)) {
832 return FALSE;
833 }
834
835 info->ps_body[0] =
836 g_strdup_printf (templ_PACKED_YUV_to_RGB_BODY, y, u, v);
837 break;
838 }
839 case GST_VIDEO_FORMAT_I420:
840 case GST_VIDEO_FORMAT_YV12:
841 case GST_VIDEO_FORMAT_I420_10LE:
842 case GST_VIDEO_FORMAT_I420_12LE:
843 case GST_VIDEO_FORMAT_Y42B:
844 case GST_VIDEO_FORMAT_I422_10LE:
845 case GST_VIDEO_FORMAT_I422_12LE:
846 case GST_VIDEO_FORMAT_Y444:
847 case GST_VIDEO_FORMAT_Y444_10LE:
848 case GST_VIDEO_FORMAT_Y444_12LE:
849 case GST_VIDEO_FORMAT_Y444_16LE:
850 {
851 guint mul;
852 gchar u, v;
853
854 get_planar_component (in_info, &u, &v, &mul);
855
856 info->ps_body[0] =
857 g_strdup_printf (templ_PLANAR_YUV_to_RGB_BODY, mul, u, mul, v, mul);
858 break;
859 }
860 case GST_VIDEO_FORMAT_NV12:
861 case GST_VIDEO_FORMAT_NV21:
862 case GST_VIDEO_FORMAT_P010_10LE:
863 case GST_VIDEO_FORMAT_P012_LE:
864 case GST_VIDEO_FORMAT_P016_LE:
865 {
866 gchar u, v;
867
868 get_semi_planar_component (in_info, &u, &v);
869
870 info->ps_body[0] = g_strdup_printf (templ_SEMI_PLANAR_to_RGB_BODY, u, v);
871 break;
872 }
873 default:
874 GST_ERROR ("Unhandled input format %s",
875 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (in_info)));
876 return FALSE;
877 }
878
879 return TRUE;
880 }
881
882 static gboolean
setup_convert_info_rgb_to_yuv(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)883 setup_convert_info_rgb_to_yuv (GstD3D11Converter * self,
884 const GstVideoInfo * in_info, const GstVideoInfo * out_info)
885 {
886 ConvertInfo *info = &self->convert_info;
887
888 info->templ = &templ_RGB_to_YUV;
889 info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
890
891 switch (GST_VIDEO_INFO_FORMAT (out_info)) {
892 case GST_VIDEO_FORMAT_VUYA:
893 info->ps_body[0] = g_strdup_printf (templ_RGB_to_VUYA_BODY);
894 break;
895 case GST_VIDEO_FORMAT_NV12:
896 case GST_VIDEO_FORMAT_NV21:
897 case GST_VIDEO_FORMAT_P010_10LE:
898 case GST_VIDEO_FORMAT_P012_LE:
899 case GST_VIDEO_FORMAT_P016_LE:
900 {
901 gchar u, v;
902
903 get_semi_planar_component (out_info, &u, &v);
904
905 info->ps_body[0] = g_strdup_printf (templ_RGB_to_LUMA_BODY, 1);
906 info->ps_body[1] = g_strdup_printf (templ_RGB_to_SEMI_PLANAR_CHROMA_BODY,
907 u, v);
908 info->ps_output[1] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
909 break;
910 }
911 case GST_VIDEO_FORMAT_I420:
912 case GST_VIDEO_FORMAT_YV12:
913 case GST_VIDEO_FORMAT_I420_10LE:
914 case GST_VIDEO_FORMAT_I420_12LE:
915 case GST_VIDEO_FORMAT_Y42B:
916 case GST_VIDEO_FORMAT_I422_10LE:
917 case GST_VIDEO_FORMAT_I422_12LE:
918 case GST_VIDEO_FORMAT_Y444:
919 case GST_VIDEO_FORMAT_Y444_10LE:
920 case GST_VIDEO_FORMAT_Y444_12LE:
921 case GST_VIDEO_FORMAT_Y444_16LE:
922 {
923 guint div;
924 gchar u, v;
925
926 get_planar_component (out_info, &u, &v, &div);
927
928 info->ps_body[0] = g_strdup_printf (templ_RGB_to_LUMA_BODY, div);
929 info->ps_body[1] =
930 g_strdup_printf (templ_RGB_to_PLANAR_CHROMA_BODY, u, div, v, div);
931 info->ps_output[1] = HLSL_PS_OUTPUT_TWO_PLANES_BODY;
932 break;
933 }
934 default:
935 GST_ERROR ("Unhandled output format %s",
936 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (out_info)));
937 return FALSE;
938 }
939
940 return TRUE;
941 }
942
943 static gboolean
setup_convert_info_planar_to_planar(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)944 setup_convert_info_planar_to_planar (GstD3D11Converter * self,
945 const GstVideoInfo * in_info, const GstVideoInfo * out_info)
946 {
947 ConvertInfo *info = &self->convert_info;
948 guint in_scale, out_scale;
949 gchar in_u, in_v, out_u, out_v;
950
951 info->templ = &templ_REORDER;
952 info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
953 info->ps_output[1] = HLSL_PS_OUTPUT_TWO_PLANES_BODY;
954
955 get_planar_component (in_info, &in_u, &in_v, &in_scale);
956 get_planar_component (out_info, &out_u, &out_v, &out_scale);
957
958 info->ps_body[0] = g_strdup_printf (templ_LUMA_to_LUMA_BODY,
959 in_scale, out_scale);
960 info->ps_body[1] =
961 g_strdup_printf (templ_PLANAR_TO_PLANAR_CHROMA_BODY,
962 in_u, in_scale, in_v, in_scale, out_u, out_scale, out_v, out_scale);
963
964 return TRUE;
965 }
966
967 static gboolean
setup_convert_info_planar_to_semi_planar(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)968 setup_convert_info_planar_to_semi_planar (GstD3D11Converter * self,
969 const GstVideoInfo * in_info, const GstVideoInfo * out_info)
970 {
971 ConvertInfo *info = &self->convert_info;
972 guint in_scale;
973 gchar in_u, in_v, out_u, out_v;
974
975 info->templ = &templ_REORDER;
976 info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
977 info->ps_output[1] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
978
979 get_planar_component (in_info, &in_u, &in_v, &in_scale);
980 get_semi_planar_component (out_info, &out_u, &out_v);
981
982 info->ps_body[0] = g_strdup_printf (templ_LUMA_to_LUMA_BODY, in_scale, 1);
983 info->ps_body[1] =
984 g_strdup_printf (templ_PLANAR_TO_SEMI_PLANAR_CHROMA_BODY,
985 in_u, in_scale, in_v, in_scale, out_u, out_v);
986
987 return TRUE;
988 }
989
990 static gboolean
setup_convert_info_semi_planar_to_planar(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)991 setup_convert_info_semi_planar_to_planar (GstD3D11Converter * self,
992 const GstVideoInfo * in_info, const GstVideoInfo * out_info)
993 {
994 ConvertInfo *info = &self->convert_info;
995 gchar in_u, in_v, out_u, out_v;
996 guint div = 1;
997
998 info->templ = &templ_REORDER;
999 info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1000 info->ps_output[1] = HLSL_PS_OUTPUT_TWO_PLANES_BODY;
1001
1002 get_semi_planar_component (in_info, &in_u, &in_v);
1003 get_planar_component (out_info, &out_u, &out_v, &div);
1004
1005 info->ps_body[0] = g_strdup_printf (templ_LUMA_to_LUMA_BODY, 1, div);
1006 info->ps_body[1] =
1007 g_strdup_printf (templ_SEMI_PLANAR_TO_PLANAR_CHROMA_BODY,
1008 in_u, in_v, out_u, div, out_v, div);
1009
1010 return TRUE;
1011 }
1012
1013 static gboolean
setup_convert_info_semi_planar_to_semi_planar(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)1014 setup_convert_info_semi_planar_to_semi_planar (GstD3D11Converter * self,
1015 const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1016 {
1017 ConvertInfo *info = &self->convert_info;
1018 gchar in_u, in_v, out_u, out_v;
1019
1020 info->templ = &templ_REORDER;
1021 info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1022 info->ps_output[1] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1023
1024 get_semi_planar_component (in_info, &in_u, &in_v);
1025 get_semi_planar_component (out_info, &out_u, &out_v);
1026
1027 info->ps_body[0] = g_strdup_printf (templ_LUMA_to_LUMA_BODY, 1, 1);
1028 info->ps_body[1] =
1029 g_strdup_printf (templ_SEMI_PLANAR_TO_SEMI_PLANAR_CHROMA_BODY,
1030 in_u, in_v, out_u, out_v);
1031
1032 return TRUE;
1033 }
1034
1035 static gboolean
setup_convert_info_vuya_to_vuya(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)1036 setup_convert_info_vuya_to_vuya (GstD3D11Converter * self,
1037 const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1038 {
1039 ConvertInfo *info = &self->convert_info;
1040
1041 info->templ = &templ_REORDER;
1042 info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1043
1044 info->ps_body[0] = g_strdup_printf (templ_REORDER_BODY);
1045
1046 return TRUE;
1047 }
1048
1049 static gboolean
setup_convert_info_vuya_to_planar(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)1050 setup_convert_info_vuya_to_planar (GstD3D11Converter * self,
1051 const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1052 {
1053 ConvertInfo *info = &self->convert_info;
1054 guint div;
1055 gchar u, v;
1056
1057 info->templ = &templ_REORDER;
1058 info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1059 info->ps_output[1] = HLSL_PS_OUTPUT_TWO_PLANES_BODY;
1060
1061 get_planar_component (out_info, &u, &v, &div);
1062
1063 info->ps_body[0] = g_strdup_printf (templ_VUYA_to_LUMA_BODY, div);
1064 info->ps_body[1] =
1065 g_strdup_printf (templ_VUYA_TO_PLANAR_CHROMA_BODY, u, div, v, div);
1066
1067 return TRUE;
1068 }
1069
1070 static gboolean
setup_convert_info_vuya_to_semi_planar(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)1071 setup_convert_info_vuya_to_semi_planar (GstD3D11Converter * self,
1072 const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1073 {
1074 ConvertInfo *info = &self->convert_info;
1075 guint div = 1;
1076 gchar u, v;
1077
1078 info->templ = &templ_REORDER;
1079 info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1080 info->ps_output[1] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1081
1082 get_semi_planar_component (out_info, &u, &v);
1083
1084 info->ps_body[0] = g_strdup_printf (templ_VUYA_to_LUMA_BODY, div);
1085 info->ps_body[1] =
1086 g_strdup_printf (templ_VUYA_TO_SEMI_PLANAR_CHROMA_BODY, v, u);
1087
1088 return TRUE;
1089 }
1090
1091 static gboolean
setup_convert_info_planar_to_vuya(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)1092 setup_convert_info_planar_to_vuya (GstD3D11Converter * self,
1093 const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1094 {
1095 ConvertInfo *info = &self->convert_info;
1096 guint mul;
1097 gchar u, v;
1098
1099 get_planar_component (in_info, &u, &v, &mul);
1100
1101 info->templ = &templ_REORDER;
1102 info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1103
1104 info->ps_body[0] =
1105 g_strdup_printf (templ_PLANAR_to_VUYA_BODY, mul, u, mul, v, mul);
1106
1107 return TRUE;
1108 }
1109
1110 static gboolean
setup_convert_info_packed_yuv_to_vuya(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)1111 setup_convert_info_packed_yuv_to_vuya (GstD3D11Converter * self,
1112 const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1113 {
1114 ConvertInfo *info = &self->convert_info;
1115 gchar y, u, v;
1116
1117 info->templ = &templ_REORDER;
1118 info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1119
1120 if (!get_packed_yuv_components (self, GST_VIDEO_INFO_FORMAT (in_info),
1121 &y, &u, &v)) {
1122 return FALSE;
1123 }
1124
1125 info->ps_body[0] = g_strdup_printf (templ_PACKED_YUV_to_VUYA_BODY, y, u, v);
1126
1127 return TRUE;
1128 }
1129
1130 static gboolean
setup_convert_info_semi_planar_to_vuya(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)1131 setup_convert_info_semi_planar_to_vuya (GstD3D11Converter * self,
1132 const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1133 {
1134 ConvertInfo *info = &self->convert_info;
1135 gchar u, v;
1136
1137 get_semi_planar_component (in_info, &u, &v);
1138
1139 info->templ = &templ_REORDER;
1140 info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1141
1142 info->ps_body[0] = g_strdup_printf (templ_SEMI_PLANAR_to_VUYA_BODY, v, u);
1143
1144 return TRUE;
1145 }
1146
1147 static gboolean
setup_convert_info_packed_yuv_to_planar(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)1148 setup_convert_info_packed_yuv_to_planar (GstD3D11Converter * self,
1149 const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1150 {
1151 ConvertInfo *info = &self->convert_info;
1152 gchar in_y, in_u, in_v;
1153 gchar out_u, out_v;
1154 guint out_scale;
1155
1156 info->templ = &templ_REORDER;
1157 info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1158 info->ps_output[1] = HLSL_PS_OUTPUT_TWO_PLANES_BODY;
1159
1160 if (!get_packed_yuv_components (self, GST_VIDEO_INFO_FORMAT (in_info),
1161 &in_y, &in_u, &in_v)) {
1162 return FALSE;
1163 }
1164
1165 get_planar_component (out_info, &out_u, &out_v, &out_scale);
1166
1167 info->ps_body[0] =
1168 g_strdup_printf (templ_PACKED_YUV_to_LUMA_BODY, in_y, out_scale);
1169 info->ps_body[1] =
1170 g_strdup_printf (templ_PACKED_YUV_TO_PLANAR_CHROMA_BODY, in_u, in_v,
1171 out_u, out_scale, out_v, out_scale);
1172
1173 return TRUE;
1174 }
1175
1176 static gboolean
setup_convert_info_packed_yuv_to_semi_planar(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)1177 setup_convert_info_packed_yuv_to_semi_planar (GstD3D11Converter * self,
1178 const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1179 {
1180 ConvertInfo *info = &self->convert_info;
1181 gchar in_y, in_u, in_v;
1182 gchar out_u, out_v;
1183
1184 info->templ = &templ_REORDER;
1185 info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1186 info->ps_output[1] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1187
1188 if (!get_packed_yuv_components (self, GST_VIDEO_INFO_FORMAT (in_info),
1189 &in_y, &in_u, &in_v)) {
1190 return FALSE;
1191 }
1192
1193 get_semi_planar_component (out_info, &out_u, &out_v);
1194
1195 info->ps_body[0] = g_strdup_printf (templ_PACKED_YUV_to_LUMA_BODY, in_y, 1);
1196 info->ps_body[1] =
1197 g_strdup_printf (templ_PACKED_YUV_TO_SEMI_PLANAR_CHROMA_BODY,
1198 in_u, in_v, out_u, out_v);
1199
1200 return TRUE;
1201 }
1202
1203 static gboolean
is_planar_format(const GstVideoInfo * info)1204 is_planar_format (const GstVideoInfo * info)
1205 {
1206 switch (GST_VIDEO_INFO_FORMAT (info)) {
1207 case GST_VIDEO_FORMAT_I420:
1208 case GST_VIDEO_FORMAT_YV12:
1209 case GST_VIDEO_FORMAT_I420_10LE:
1210 case GST_VIDEO_FORMAT_I420_12LE:
1211 case GST_VIDEO_FORMAT_Y42B:
1212 case GST_VIDEO_FORMAT_I422_10LE:
1213 case GST_VIDEO_FORMAT_I422_12LE:
1214 case GST_VIDEO_FORMAT_Y444:
1215 case GST_VIDEO_FORMAT_Y444_10LE:
1216 case GST_VIDEO_FORMAT_Y444_12LE:
1217 case GST_VIDEO_FORMAT_Y444_16LE:
1218 return TRUE;
1219 default:
1220 break;
1221 }
1222
1223 return FALSE;
1224 }
1225
1226 static gboolean
setup_convert_info_yuv_to_yuv(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)1227 setup_convert_info_yuv_to_yuv (GstD3D11Converter * self,
1228 const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1229 {
1230 gboolean in_planar, out_planar;
1231 gboolean in_vuya, out_vuya;
1232 gboolean in_packed;
1233
1234 in_vuya = GST_VIDEO_INFO_FORMAT (in_info) == GST_VIDEO_FORMAT_VUYA;
1235 out_vuya = GST_VIDEO_INFO_FORMAT (out_info) == GST_VIDEO_FORMAT_VUYA;
1236 in_planar = is_planar_format (in_info);
1237 in_packed = (GST_VIDEO_INFO_FORMAT (in_info) == GST_VIDEO_FORMAT_YUY2 ||
1238 GST_VIDEO_INFO_FORMAT (in_info) == GST_VIDEO_FORMAT_UYVY ||
1239 GST_VIDEO_INFO_FORMAT (in_info) == GST_VIDEO_FORMAT_VYUY ||
1240 GST_VIDEO_INFO_FORMAT (in_info) == GST_VIDEO_FORMAT_Y210 ||
1241 GST_VIDEO_INFO_FORMAT (in_info) == GST_VIDEO_FORMAT_Y410);
1242 out_planar = is_planar_format (out_info);
1243
1244 /* From/to VUYA */
1245 if (in_vuya && out_vuya) {
1246 return setup_convert_info_vuya_to_vuya (self, in_info, out_info);
1247 } else if (in_vuya) {
1248 if (out_planar)
1249 return setup_convert_info_vuya_to_planar (self, in_info, out_info);
1250 else
1251 return setup_convert_info_vuya_to_semi_planar (self, in_info, out_info);
1252 } else if (out_vuya) {
1253 if (in_planar)
1254 return setup_convert_info_planar_to_vuya (self, in_info, out_info);
1255 else if (in_packed)
1256 return setup_convert_info_packed_yuv_to_vuya (self, in_info, out_info);
1257 else
1258 return setup_convert_info_semi_planar_to_vuya (self, in_info, out_info);
1259 }
1260
1261 if (in_planar) {
1262 if (out_planar)
1263 return setup_convert_info_planar_to_planar (self, in_info, out_info);
1264 else
1265 return setup_convert_info_planar_to_semi_planar (self, in_info, out_info);
1266 } else if (in_packed) {
1267 if (out_planar)
1268 return setup_convert_info_packed_yuv_to_planar (self, in_info, out_info);
1269 else
1270 return setup_convert_info_packed_yuv_to_semi_planar (self, in_info,
1271 out_info);
1272 } else {
1273 if (out_planar)
1274 return setup_convert_info_semi_planar_to_planar (self, in_info, out_info);
1275 else
1276 return setup_convert_info_semi_planar_to_semi_planar (self, in_info,
1277 out_info);
1278 }
1279
1280 return FALSE;
1281 }
1282
1283 static gboolean
setup_convert_info_rgb_to_gray(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)1284 setup_convert_info_rgb_to_gray (GstD3D11Converter * self,
1285 const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1286 {
1287 ConvertInfo *info = &self->convert_info;
1288
1289 info->templ = &templ_RGB_to_YUV;
1290 info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1291
1292 switch (GST_VIDEO_INFO_FORMAT (out_info)) {
1293 case GST_VIDEO_FORMAT_GRAY8:
1294 case GST_VIDEO_FORMAT_GRAY16_LE:
1295 info->ps_body[0] = g_strdup_printf (templ_RGB_to_GRAY_BODY);
1296 break;
1297 default:
1298 GST_ERROR ("Unhandled output format %s",
1299 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (out_info)));
1300 return FALSE;
1301 }
1302
1303 return TRUE;
1304 }
1305
1306 static gboolean
setup_convert_info_yuv_to_gray(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)1307 setup_convert_info_yuv_to_gray (GstD3D11Converter * self,
1308 const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1309 {
1310 ConvertInfo *info = &self->convert_info;
1311
1312 info->templ = &templ_REORDER_NO_ALPHA;
1313 info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1314
1315 if (GST_VIDEO_INFO_FORMAT (out_info) != GST_VIDEO_FORMAT_GRAY8 &&
1316 GST_VIDEO_INFO_FORMAT (out_info) != GST_VIDEO_FORMAT_GRAY16_LE)
1317 return FALSE;
1318
1319 switch (GST_VIDEO_INFO_FORMAT (in_info)) {
1320 case GST_VIDEO_FORMAT_VUYA:
1321 info->ps_body[0] = g_strdup_printf (templ_VUYA_to_GRAY_BODY);
1322 break;
1323 case GST_VIDEO_FORMAT_I420:
1324 case GST_VIDEO_FORMAT_YV12:
1325 case GST_VIDEO_FORMAT_I420_10LE:
1326 case GST_VIDEO_FORMAT_I420_12LE:
1327 case GST_VIDEO_FORMAT_Y42B:
1328 case GST_VIDEO_FORMAT_I422_10LE:
1329 case GST_VIDEO_FORMAT_I422_12LE:
1330 case GST_VIDEO_FORMAT_Y444:
1331 case GST_VIDEO_FORMAT_Y444_10LE:
1332 case GST_VIDEO_FORMAT_Y444_12LE:
1333 case GST_VIDEO_FORMAT_Y444_16LE:
1334 case GST_VIDEO_FORMAT_NV12:
1335 case GST_VIDEO_FORMAT_NV21:
1336 case GST_VIDEO_FORMAT_P010_10LE:
1337 case GST_VIDEO_FORMAT_P012_LE:
1338 case GST_VIDEO_FORMAT_P016_LE:
1339 {
1340 gchar u, v;
1341 guint scale;
1342
1343 get_planar_component (in_info, &u, &v, &scale);
1344
1345 info->ps_body[0] = g_strdup_printf (templ_YUV_to_GRAY_BODY, scale);
1346 break;
1347 }
1348 case GST_VIDEO_FORMAT_Y410:
1349 {
1350 gchar y, u, v;
1351 get_packed_yuv_components (self, GST_VIDEO_FORMAT_Y410, &y, &u, &v);
1352
1353 info->ps_body[0] = g_strdup_printf (templ_PACKED_YUV_TO_GRAY, y);
1354 break;
1355 }
1356 default:
1357 GST_ERROR ("Unhandled input format %s",
1358 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (in_info)));
1359 return FALSE;
1360 }
1361
1362 return TRUE;
1363 }
1364
1365 static gboolean
setup_convert_info_gray_to_gray(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)1366 setup_convert_info_gray_to_gray (GstD3D11Converter * self,
1367 const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1368 {
1369 ConvertInfo *info = &self->convert_info;
1370
1371 info->templ = &templ_REORDER_NO_ALPHA;
1372 info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1373
1374 if (GST_VIDEO_INFO_FORMAT (in_info) != GST_VIDEO_FORMAT_GRAY8 &&
1375 GST_VIDEO_INFO_FORMAT (in_info) != GST_VIDEO_FORMAT_GRAY16_LE)
1376 return FALSE;
1377
1378 if (GST_VIDEO_INFO_FORMAT (out_info) != GST_VIDEO_FORMAT_GRAY8 &&
1379 GST_VIDEO_INFO_FORMAT (out_info) != GST_VIDEO_FORMAT_GRAY16_LE)
1380 return FALSE;
1381
1382 info->ps_body[0] = g_strdup_printf (templ_GRAY_to_GRAY_BODY);
1383
1384 return TRUE;
1385 }
1386
1387 static gboolean
setup_convert_info_gray_to_rgb(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)1388 setup_convert_info_gray_to_rgb (GstD3D11Converter * self,
1389 const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1390 {
1391 ConvertInfo *info = &self->convert_info;
1392
1393 info->templ = &templ_REORDER_NO_ALPHA;
1394 info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1395
1396 if (GST_VIDEO_INFO_FORMAT (in_info) != GST_VIDEO_FORMAT_GRAY8 &&
1397 GST_VIDEO_INFO_FORMAT (in_info) != GST_VIDEO_FORMAT_GRAY16_LE)
1398 return FALSE;
1399
1400 info->ps_body[0] = g_strdup_printf (templ_GRAY_to_RGB_BODY);
1401
1402 return TRUE;
1403 }
1404
1405 static gboolean
setup_convert_info_gray_to_yuv(GstD3D11Converter * self,const GstVideoInfo * in_info,const GstVideoInfo * out_info)1406 setup_convert_info_gray_to_yuv (GstD3D11Converter * self,
1407 const GstVideoInfo * in_info, const GstVideoInfo * out_info)
1408 {
1409 ConvertInfo *info = &self->convert_info;
1410
1411 info->templ = &templ_REORDER_NO_ALPHA;
1412 info->ps_output[0] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1413
1414 if (GST_VIDEO_INFO_FORMAT (in_info) != GST_VIDEO_FORMAT_GRAY8 &&
1415 GST_VIDEO_INFO_FORMAT (in_info) != GST_VIDEO_FORMAT_GRAY16_LE)
1416 return FALSE;
1417
1418 switch (GST_VIDEO_INFO_FORMAT (out_info)) {
1419 case GST_VIDEO_FORMAT_VUYA:
1420 info->ps_body[0] = g_strdup_printf (templ_GRAY_to_VUYA_BODY);
1421 break;
1422 case GST_VIDEO_FORMAT_I420:
1423 case GST_VIDEO_FORMAT_YV12:
1424 case GST_VIDEO_FORMAT_I420_10LE:
1425 case GST_VIDEO_FORMAT_I420_12LE:
1426 case GST_VIDEO_FORMAT_Y42B:
1427 case GST_VIDEO_FORMAT_I422_10LE:
1428 case GST_VIDEO_FORMAT_I422_12LE:
1429 case GST_VIDEO_FORMAT_Y444:
1430 case GST_VIDEO_FORMAT_Y444_10LE:
1431 case GST_VIDEO_FORMAT_Y444_12LE:
1432 case GST_VIDEO_FORMAT_Y444_16LE:
1433 {
1434 gchar u, v;
1435 guint div;
1436
1437 get_planar_component (out_info, &u, &v, &div);
1438 info->ps_body[0] = g_strdup_printf (templ_GRAY_to_LUMA_BODY, div);
1439 info->ps_body[1] =
1440 g_strdup_printf (templ_GRAY_to_PLANAR_CHROMA_BODY, div);
1441 info->ps_output[1] = HLSL_PS_OUTPUT_TWO_PLANES_BODY;
1442 break;
1443 }
1444 case GST_VIDEO_FORMAT_NV12:
1445 case GST_VIDEO_FORMAT_NV21:
1446 case GST_VIDEO_FORMAT_P010_10LE:
1447 case GST_VIDEO_FORMAT_P012_LE:
1448 case GST_VIDEO_FORMAT_P016_LE:
1449 info->ps_body[0] = g_strdup_printf (templ_GRAY_to_LUMA_BODY, 1);
1450 info->ps_body[1] =
1451 g_strdup_printf (templ_GRAY_to_SEMI_PLANAR_CHROMA_BODY);
1452 info->ps_output[1] = HLSL_PS_OUTPUT_ONE_PLANE_BODY;
1453 break;
1454 default:
1455 GST_ERROR ("Unhandled output format %s",
1456 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (out_info)));
1457 return FALSE;
1458 }
1459
1460 return TRUE;
1461 }
1462
1463 static gboolean
gst_d3d11_color_convert_setup_shader(GstD3D11Converter * self,GstD3D11Device * device,GstVideoInfo * in_info,GstVideoInfo * out_info)1464 gst_d3d11_color_convert_setup_shader (GstD3D11Converter * self,
1465 GstD3D11Device * device, GstVideoInfo * in_info, GstVideoInfo * out_info)
1466 {
1467 HRESULT hr;
1468 D3D11_SAMPLER_DESC sampler_desc;
1469 D3D11_INPUT_ELEMENT_DESC input_desc[2];
1470 D3D11_BUFFER_DESC buffer_desc;
1471 D3D11_MAPPED_SUBRESOURCE map;
1472 VertexData *vertex_data;
1473 WORD *indices;
1474 ID3D11Device *device_handle;
1475 ID3D11DeviceContext *context_handle;
1476 ConvertInfo *convert_info = &self->convert_info;
1477 /* *INDENT-OFF* */
1478 ComPtr<ID3D11PixelShader> ps[CONVERTER_MAX_QUADS];
1479 ComPtr<ID3D11VertexShader> vs;
1480 ComPtr<ID3D11InputLayout> layout;
1481 ComPtr<ID3D11SamplerState> linear_sampler;
1482 ComPtr<ID3D11Buffer> transform_const_buffer;
1483 ComPtr<ID3D11Buffer> alpha_const_buffer;
1484 ComPtr<ID3D11Buffer> vertex_buffer;
1485 ComPtr<ID3D11Buffer> index_buffer;
1486 /* *INDENT-ON* */
1487 const guint index_count = 2 * 3;
1488 gint i;
1489 gboolean ret;
1490 ID3D11Buffer *const_buffers[2] = { nullptr, nullptr };
1491 guint num_const_buffers = 0;
1492
1493 memset (&sampler_desc, 0, sizeof (sampler_desc));
1494 memset (input_desc, 0, sizeof (input_desc));
1495 memset (&buffer_desc, 0, sizeof (buffer_desc));
1496
1497 device_handle = gst_d3d11_device_get_device_handle (device);
1498 context_handle = gst_d3d11_device_get_device_context_handle (device);
1499
1500 /* bilinear filtering */
1501 sampler_desc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
1502 sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
1503 sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
1504 sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
1505 sampler_desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
1506 sampler_desc.MinLOD = 0;
1507 sampler_desc.MaxLOD = D3D11_FLOAT32_MAX;
1508
1509 hr = device_handle->CreateSamplerState (&sampler_desc, &linear_sampler);
1510 if (!gst_d3d11_result (hr, device)) {
1511 GST_ERROR ("Couldn't create sampler state, hr: 0x%x", (guint) hr);
1512 return FALSE;
1513 }
1514
1515 for (i = 0; i < CONVERTER_MAX_QUADS; i++) {
1516 gchar *shader_code = NULL;
1517
1518 if (convert_info->ps_body[i]) {
1519 gchar *transform_const_buffer = nullptr;
1520 gchar *alpha_const_buffer = nullptr;
1521 guint register_idx = 0;
1522
1523 g_assert (convert_info->ps_output[i] != NULL);
1524
1525 if (convert_info->templ->has_transform) {
1526 transform_const_buffer =
1527 g_strdup_printf (templ_color_transform_const_buffer, register_idx);
1528 register_idx++;
1529 }
1530
1531 if (convert_info->templ->has_alpha) {
1532 alpha_const_buffer =
1533 g_strdup_printf (templ_alpha_const_buffer, register_idx);
1534 register_idx++;
1535 }
1536
1537 shader_code = g_strdup_printf (templ_pixel_shader,
1538 transform_const_buffer ? transform_const_buffer : "",
1539 alpha_const_buffer ? alpha_const_buffer : "",
1540 convert_info->ps_output[i],
1541 convert_info->templ->func ? convert_info->templ->func : "",
1542 convert_info->ps_body[i]);
1543 g_free (transform_const_buffer);
1544 g_free (alpha_const_buffer);
1545
1546 ret = gst_d3d11_create_pixel_shader (device, shader_code, &ps[i]);
1547 g_free (shader_code);
1548 if (!ret) {
1549 return FALSE;
1550 }
1551 }
1552 }
1553
1554 if (convert_info->templ->has_transform) {
1555 D3D11_BUFFER_DESC const_buffer_desc = { 0, };
1556
1557 G_STATIC_ASSERT (sizeof (PixelShaderColorTransform) % 16 == 0);
1558
1559 const_buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
1560 const_buffer_desc.ByteWidth = sizeof (PixelShaderColorTransform);
1561 const_buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
1562 const_buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1563 const_buffer_desc.MiscFlags = 0;
1564 const_buffer_desc.StructureByteStride = 0;
1565
1566 hr = device_handle->CreateBuffer (&const_buffer_desc, nullptr,
1567 &transform_const_buffer);
1568 if (!gst_d3d11_result (hr, device)) {
1569 GST_ERROR ("Couldn't create constant buffer, hr: 0x%x", (guint) hr);
1570 return FALSE;
1571 }
1572
1573 gst_d3d11_device_lock (device);
1574 hr = context_handle->Map (transform_const_buffer.Get (),
1575 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
1576
1577 if (!gst_d3d11_result (hr, device)) {
1578 GST_ERROR ("Couldn't map constant buffer, hr: 0x%x", (guint) hr);
1579 gst_d3d11_device_unlock (device);
1580 return FALSE;
1581 }
1582
1583 memcpy (map.pData, &convert_info->transform,
1584 sizeof (PixelShaderColorTransform));
1585
1586 context_handle->Unmap (transform_const_buffer.Get (), 0);
1587 gst_d3d11_device_unlock (device);
1588
1589 const_buffers[num_const_buffers] = transform_const_buffer.Get ();
1590 num_const_buffers++;
1591 }
1592
1593 if (convert_info->templ->has_alpha) {
1594 D3D11_BUFFER_DESC const_buffer_desc = { 0, };
1595 AlphaConstBuffer *alpha_const;
1596
1597 G_STATIC_ASSERT (sizeof (AlphaConstBuffer) % 16 == 0);
1598
1599 const_buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
1600 const_buffer_desc.ByteWidth = sizeof (AlphaConstBuffer);
1601 const_buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
1602 const_buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1603 const_buffer_desc.MiscFlags = 0;
1604 const_buffer_desc.StructureByteStride = 0;
1605
1606 hr = device_handle->CreateBuffer (&const_buffer_desc,
1607 nullptr, &alpha_const_buffer);
1608 if (!gst_d3d11_result (hr, device)) {
1609 GST_ERROR ("Couldn't create constant buffer, hr: 0x%x", (guint) hr);
1610 return FALSE;
1611 }
1612
1613 gst_d3d11_device_lock (device);
1614 hr = context_handle->Map (alpha_const_buffer.Get (),
1615 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
1616
1617 if (!gst_d3d11_result (hr, device)) {
1618 GST_ERROR ("Couldn't map constant buffer, hr: 0x%x", (guint) hr);
1619 gst_d3d11_device_unlock (device);
1620 return FALSE;
1621 }
1622
1623 alpha_const = (AlphaConstBuffer *) map.pData;
1624 memset (alpha_const, 0, sizeof (AlphaConstBuffer));
1625 alpha_const->alpha_mul = (FLOAT) self->alpha;
1626
1627 context_handle->Unmap (alpha_const_buffer.Get (), 0);
1628 gst_d3d11_device_unlock (device);
1629
1630 self->alpha_const_buffer = alpha_const_buffer.Get ();
1631 /* We will hold this buffer and update later */
1632 self->alpha_const_buffer->AddRef ();
1633 const_buffers[num_const_buffers] = alpha_const_buffer.Get ();
1634 num_const_buffers++;
1635 }
1636
1637 input_desc[0].SemanticName = "POSITION";
1638 input_desc[0].SemanticIndex = 0;
1639 input_desc[0].Format = DXGI_FORMAT_R32G32B32_FLOAT;
1640 input_desc[0].InputSlot = 0;
1641 input_desc[0].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
1642 input_desc[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
1643 input_desc[0].InstanceDataStepRate = 0;
1644
1645 input_desc[1].SemanticName = "TEXCOORD";
1646 input_desc[1].SemanticIndex = 0;
1647 input_desc[1].Format = DXGI_FORMAT_R32G32_FLOAT;
1648 input_desc[1].InputSlot = 0;
1649 input_desc[1].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
1650 input_desc[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
1651 input_desc[1].InstanceDataStepRate = 0;
1652
1653 if (!gst_d3d11_create_vertex_shader (device, templ_vertex_shader,
1654 input_desc, G_N_ELEMENTS (input_desc), &vs, &layout)) {
1655 GST_ERROR ("Couldn't vertex pixel shader");
1656 return FALSE;
1657 }
1658
1659 /* setup vertext buffer and index buffer */
1660 buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
1661 buffer_desc.ByteWidth = sizeof (VertexData) * 4;
1662 buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
1663 buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1664
1665 hr = device_handle->CreateBuffer (&buffer_desc, NULL, &vertex_buffer);
1666 if (!gst_d3d11_result (hr, device)) {
1667 GST_ERROR ("Couldn't create vertex buffer, hr: 0x%x", (guint) hr);
1668 return FALSE;
1669 }
1670
1671 buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
1672 buffer_desc.ByteWidth = sizeof (WORD) * index_count;
1673 buffer_desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
1674 buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1675
1676 hr = device_handle->CreateBuffer (&buffer_desc, NULL, &index_buffer);
1677 if (!gst_d3d11_result (hr, device)) {
1678 GST_ERROR ("Couldn't create index buffer, hr: 0x%x", (guint) hr);
1679 return FALSE;
1680 }
1681
1682 gst_d3d11_device_lock (device);
1683 hr = context_handle->Map (vertex_buffer.Get (), 0, D3D11_MAP_WRITE_DISCARD, 0,
1684 &map);
1685 if (!gst_d3d11_result (hr, device)) {
1686 GST_ERROR ("Couldn't map vertex buffer, hr: 0x%x", (guint) hr);
1687 gst_d3d11_device_unlock (device);
1688 return FALSE;
1689 }
1690
1691 vertex_data = (VertexData *) map.pData;
1692
1693 hr = context_handle->Map (index_buffer.Get (), 0, D3D11_MAP_WRITE_DISCARD, 0,
1694 &map);
1695 if (!gst_d3d11_result (hr, device)) {
1696 GST_ERROR ("Couldn't map index buffer, hr: 0x%x", (guint) hr);
1697 context_handle->Unmap (vertex_buffer.Get (), 0);
1698 gst_d3d11_device_unlock (device);
1699 return FALSE;
1700 }
1701
1702 indices = (WORD *) map.pData;
1703
1704 /* bottom left */
1705 vertex_data[0].position.x = -1.0f;
1706 vertex_data[0].position.y = -1.0f;
1707 vertex_data[0].position.z = 0.0f;
1708 vertex_data[0].texture.x = 0.0f;
1709 vertex_data[0].texture.y = 1.0f;
1710
1711 /* top left */
1712 vertex_data[1].position.x = -1.0f;
1713 vertex_data[1].position.y = 1.0f;
1714 vertex_data[1].position.z = 0.0f;
1715 vertex_data[1].texture.x = 0.0f;
1716 vertex_data[1].texture.y = 0.0f;
1717
1718 /* top right */
1719 vertex_data[2].position.x = 1.0f;
1720 vertex_data[2].position.y = 1.0f;
1721 vertex_data[2].position.z = 0.0f;
1722 vertex_data[2].texture.x = 1.0f;
1723 vertex_data[2].texture.y = 0.0f;
1724
1725 /* bottom right */
1726 vertex_data[3].position.x = 1.0f;
1727 vertex_data[3].position.y = -1.0f;
1728 vertex_data[3].position.z = 0.0f;
1729 vertex_data[3].texture.x = 1.0f;
1730 vertex_data[3].texture.y = 1.0f;
1731
1732 /* clockwise indexing */
1733 indices[0] = 0; /* bottom left */
1734 indices[1] = 1; /* top left */
1735 indices[2] = 2; /* top right */
1736
1737 indices[3] = 3; /* bottom right */
1738 indices[4] = 0; /* bottom left */
1739 indices[5] = 2; /* top right */
1740
1741 context_handle->Unmap (vertex_buffer.Get (), 0);
1742 context_handle->Unmap (index_buffer.Get (), 0);
1743 gst_d3d11_device_unlock (device);
1744
1745 self->quad[0] = gst_d3d11_quad_new (device,
1746 ps[0].Get (), vs.Get (), layout.Get (),
1747 const_buffers, num_const_buffers,
1748 vertex_buffer.Get (), sizeof (VertexData),
1749 index_buffer.Get (), DXGI_FORMAT_R16_UINT, index_count);
1750
1751 if (ps[1]) {
1752 self->quad[1] = gst_d3d11_quad_new (device,
1753 ps[1].Get (), vs.Get (), layout.Get (),
1754 const_buffers, num_const_buffers,
1755 vertex_buffer.Get (), sizeof (VertexData),
1756 index_buffer.Get (), DXGI_FORMAT_R16_UINT, index_count);
1757 }
1758
1759 self->num_input_view = GST_VIDEO_INFO_N_PLANES (in_info);
1760 self->num_output_view = GST_VIDEO_INFO_N_PLANES (out_info);
1761
1762 /* holds vertex buffer for crop rect update */
1763 self->vertex_buffer = vertex_buffer.Detach ();
1764
1765 self->src_rect.left = 0;
1766 self->src_rect.top = 0;
1767 self->src_rect.right = GST_VIDEO_INFO_WIDTH (in_info);
1768 self->src_rect.bottom = GST_VIDEO_INFO_HEIGHT (in_info);
1769
1770 self->dest_rect.left = 0;
1771 self->dest_rect.top = 0;
1772 self->dest_rect.right = GST_VIDEO_INFO_WIDTH (out_info);
1773 self->dest_rect.bottom = GST_VIDEO_INFO_HEIGHT (out_info);
1774
1775 self->input_texture_width = GST_VIDEO_INFO_WIDTH (in_info);
1776 self->input_texture_height = GST_VIDEO_INFO_HEIGHT (in_info);
1777
1778 self->linear_sampler = linear_sampler.Detach ();
1779
1780 return TRUE;
1781 }
1782
1783 static gboolean
copy_config(GQuark field_id,const GValue * value,GstD3D11Converter * self)1784 copy_config (GQuark field_id, const GValue * value, GstD3D11Converter * self)
1785 {
1786 gst_structure_id_set_value (self->config, field_id, value);
1787
1788 return TRUE;
1789 }
1790
1791 static gboolean
gst_d3d11_converter_set_config(GstD3D11Converter * converter,GstStructure * config)1792 gst_d3d11_converter_set_config (GstD3D11Converter * converter,
1793 GstStructure * config)
1794 {
1795 gst_structure_foreach (config, (GstStructureForeachFunc) copy_config,
1796 converter);
1797 gst_structure_free (config);
1798
1799 return TRUE;
1800 }
1801
1802 GstD3D11Converter *
gst_d3d11_converter_new(GstD3D11Device * device,GstVideoInfo * in_info,GstVideoInfo * out_info,GstStructure * config)1803 gst_d3d11_converter_new (GstD3D11Device * device,
1804 GstVideoInfo * in_info, GstVideoInfo * out_info, GstStructure * config)
1805 {
1806 const GstVideoInfo *unknown_info;
1807 const GstD3D11Format *in_d3d11_format;
1808 const GstD3D11Format *out_d3d11_format;
1809 gboolean is_supported = FALSE;
1810 MatrixData matrix;
1811 GstD3D11Converter *converter = NULL;
1812 gboolean ret;
1813 guint i;
1814
1815 g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
1816 g_return_val_if_fail (in_info != NULL, NULL);
1817 g_return_val_if_fail (out_info != NULL, NULL);
1818
1819 GST_DEBUG ("Setup convert with format %s -> %s",
1820 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (in_info)),
1821 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (out_info)));
1822
1823 in_d3d11_format =
1824 gst_d3d11_device_format_from_gst (device,
1825 GST_VIDEO_INFO_FORMAT (in_info));
1826 if (!in_d3d11_format) {
1827 unknown_info = in_info;
1828 goto format_unknown;
1829 }
1830
1831 out_d3d11_format =
1832 gst_d3d11_device_format_from_gst (device,
1833 GST_VIDEO_INFO_FORMAT (out_info));
1834 if (!out_d3d11_format) {
1835 unknown_info = out_info;
1836 goto format_unknown;
1837 }
1838
1839 converter = g_new0 (GstD3D11Converter, 1);
1840 converter->device = (GstD3D11Device *) gst_object_ref (device);
1841 converter->config = gst_structure_new_empty ("GstD3D11Converter-Config");
1842 if (config)
1843 gst_d3d11_converter_set_config (converter, config);
1844
1845 converter->alpha = GET_OPT_ALPHA_VALUE (converter);
1846
1847 if (GST_VIDEO_INFO_IS_RGB (in_info)) {
1848 if (GST_VIDEO_INFO_IS_RGB (out_info)) {
1849 is_supported =
1850 setup_convert_info_rgb_to_rgb (converter, in_info, out_info);
1851 } else if (GST_VIDEO_INFO_IS_YUV (out_info)) {
1852 is_supported =
1853 setup_convert_info_rgb_to_yuv (converter, in_info, out_info);
1854 } else if (GST_VIDEO_INFO_IS_GRAY (out_info)) {
1855 is_supported =
1856 setup_convert_info_rgb_to_gray (converter, in_info, out_info);
1857 }
1858 } else if (GST_VIDEO_INFO_IS_YUV (in_info)) {
1859 if (GST_VIDEO_INFO_IS_RGB (out_info)) {
1860 is_supported =
1861 setup_convert_info_yuv_to_rgb (converter, in_info, out_info);
1862 } else if (GST_VIDEO_INFO_IS_YUV (out_info)) {
1863 is_supported =
1864 setup_convert_info_yuv_to_yuv (converter, in_info, out_info);
1865 } else if (GST_VIDEO_INFO_IS_GRAY (out_info)) {
1866 is_supported =
1867 setup_convert_info_yuv_to_gray (converter, in_info, out_info);
1868 }
1869 } else if (GST_VIDEO_INFO_IS_GRAY (in_info)) {
1870 if (GST_VIDEO_INFO_IS_RGB (out_info)) {
1871 is_supported =
1872 setup_convert_info_gray_to_rgb (converter, in_info, out_info);
1873 } else if (GST_VIDEO_INFO_IS_YUV (out_info)) {
1874 is_supported =
1875 setup_convert_info_gray_to_yuv (converter, in_info, out_info);
1876 } else if (GST_VIDEO_INFO_IS_GRAY (out_info)) {
1877 is_supported =
1878 setup_convert_info_gray_to_gray (converter, in_info, out_info);
1879 }
1880 }
1881
1882 if (!is_supported) {
1883 goto conversion_not_supported;
1884 }
1885
1886 if (converter_get_matrix (converter, &matrix, in_info, out_info)) {
1887 PixelShaderColorTransform *transform = &converter->convert_info.transform;
1888
1889 /* padding the last column for 16bytes alignment */
1890 transform->trans_matrix[0] = matrix.dm[0][0];
1891 transform->trans_matrix[1] = matrix.dm[0][1];
1892 transform->trans_matrix[2] = matrix.dm[0][2];
1893 transform->trans_matrix[3] = 0;
1894 transform->trans_matrix[4] = matrix.dm[1][0];
1895 transform->trans_matrix[5] = matrix.dm[1][1];
1896 transform->trans_matrix[6] = matrix.dm[1][2];
1897 transform->trans_matrix[7] = 0;
1898 transform->trans_matrix[8] = matrix.dm[2][0];
1899 transform->trans_matrix[9] = matrix.dm[2][1];
1900 transform->trans_matrix[10] = matrix.dm[2][2];
1901 transform->trans_matrix[11] = 0;
1902 }
1903
1904 for (i = 0; i < GST_VIDEO_INFO_N_PLANES (out_info); i++) {
1905 converter->viewport[i].TopLeftX = 0;
1906 converter->viewport[i].TopLeftY = 0;
1907 converter->viewport[i].Width = GST_VIDEO_INFO_COMP_WIDTH (out_info, i);
1908 converter->viewport[i].Height = GST_VIDEO_INFO_COMP_HEIGHT (out_info, i);
1909 converter->viewport[i].MinDepth = 0.0f;
1910 converter->viewport[i].MaxDepth = 1.0f;
1911 }
1912
1913 ret = gst_d3d11_color_convert_setup_shader (converter,
1914 device, in_info, out_info);
1915
1916 if (!ret) {
1917 GST_ERROR ("Couldn't setup shader");
1918 gst_d3d11_converter_free (converter);
1919 converter = NULL;
1920 } else {
1921 converter->in_info = *in_info;
1922 converter->out_info = *out_info;
1923 }
1924
1925 return converter;
1926
1927 /* ERRORS */
1928 format_unknown:
1929 {
1930 GST_ERROR ("%s couldn't be converted to d3d11 format",
1931 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (unknown_info)));
1932 if (config)
1933 gst_structure_free (config);
1934
1935 return NULL;
1936 }
1937 conversion_not_supported:
1938 {
1939 GST_ERROR ("Conversion %s to %s not supported",
1940 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (in_info)),
1941 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (out_info)));
1942 gst_d3d11_converter_free (converter);
1943 return NULL;
1944 }
1945 }
1946
1947 void
gst_d3d11_converter_free(GstD3D11Converter * converter)1948 gst_d3d11_converter_free (GstD3D11Converter * converter)
1949 {
1950 gint i;
1951
1952 g_return_if_fail (converter != NULL);
1953
1954 for (i = 0; i < CONVERTER_MAX_QUADS; i++) {
1955 if (converter->quad[i])
1956 gst_d3d11_quad_free (converter->quad[i]);
1957
1958 g_free (converter->convert_info.ps_body[i]);
1959 }
1960
1961 GST_D3D11_CLEAR_COM (converter->vertex_buffer);
1962 GST_D3D11_CLEAR_COM (converter->linear_sampler);
1963 GST_D3D11_CLEAR_COM (converter->alpha_const_buffer);
1964
1965 gst_clear_object (&converter->device);
1966
1967 if (converter->config)
1968 gst_structure_free (converter->config);
1969
1970 g_free (converter);
1971 }
1972
1973 /* must be called with gst_d3d11_device_lock since ID3D11DeviceContext is not
1974 * thread-safe */
1975 static gboolean
gst_d3d11_converter_update_vertex_buffer(GstD3D11Converter * self)1976 gst_d3d11_converter_update_vertex_buffer (GstD3D11Converter * self)
1977 {
1978 D3D11_MAPPED_SUBRESOURCE map;
1979 VertexData *vertex_data;
1980 ID3D11DeviceContext *context_handle;
1981 HRESULT hr;
1982 FLOAT x1, y1, x2, y2;
1983 FLOAT u, v;
1984 const RECT *src_rect = &self->src_rect;
1985 const RECT *dest_rect = &self->dest_rect;
1986 gint texture_width = self->input_texture_width;
1987 gint texture_height = self->input_texture_height;
1988 gdouble val;
1989
1990 context_handle = gst_d3d11_device_get_device_context_handle (self->device);
1991
1992 hr = context_handle->Map (self->vertex_buffer, 0, D3D11_MAP_WRITE_DISCARD,
1993 0, &map);
1994
1995 if (!gst_d3d11_result (hr, self->device)) {
1996 GST_ERROR ("Couldn't map vertex buffer, hr: 0x%x", (guint) hr);
1997 return FALSE;
1998 }
1999
2000 vertex_data = (VertexData *) map.pData;
2001 /* bottom left */
2002 gst_util_fraction_to_double (dest_rect->left,
2003 GST_VIDEO_INFO_WIDTH (&self->out_info), &val);
2004 x1 = (val * 2.0f) - 1.0f;
2005
2006 gst_util_fraction_to_double (dest_rect->bottom,
2007 GST_VIDEO_INFO_HEIGHT (&self->out_info), &val);
2008 y1 = (val * -2.0f) + 1.0f;
2009
2010 /* top right */
2011 gst_util_fraction_to_double (dest_rect->right,
2012 GST_VIDEO_INFO_WIDTH (&self->out_info), &val);
2013 x2 = (val * 2.0f) - 1.0f;
2014
2015 gst_util_fraction_to_double (dest_rect->top,
2016 GST_VIDEO_INFO_HEIGHT (&self->out_info), &val);
2017 y2 = (val * -2.0f) + 1.0f;
2018
2019 /* bottom left */
2020 u = (src_rect->left / (gfloat) texture_width) - 0.5f / texture_width;
2021 v = (src_rect->bottom / (gfloat) texture_height) - 0.5f / texture_height;
2022
2023 vertex_data[0].position.x = x1;
2024 vertex_data[0].position.y = y1;
2025 vertex_data[0].position.z = 0.0f;
2026 vertex_data[0].texture.x = u;
2027 vertex_data[0].texture.y = v;
2028
2029 /* top left */
2030 u = (src_rect->left / (gfloat) texture_width) - 0.5f / texture_width;
2031 v = (src_rect->top / (gfloat) texture_height) - 0.5f / texture_height;
2032
2033 vertex_data[1].position.x = x1;
2034 vertex_data[1].position.y = y2;
2035 vertex_data[1].position.z = 0.0f;
2036 vertex_data[1].texture.x = u;
2037 vertex_data[1].texture.y = v;
2038
2039 /* top right */
2040 u = (src_rect->right / (gfloat) texture_width) - 0.5f / texture_width;
2041 v = (src_rect->top / (gfloat) texture_height) - 0.5f / texture_height;
2042
2043 vertex_data[2].position.x = x2;
2044 vertex_data[2].position.y = y2;
2045 vertex_data[2].position.z = 0.0f;
2046 vertex_data[2].texture.x = u;
2047 vertex_data[2].texture.y = v;
2048
2049 /* bottom right */
2050 u = (src_rect->right / (gfloat) texture_width) - 0.5f / texture_width;
2051 v = (src_rect->bottom / (gfloat) texture_height) - 0.5f / texture_height;
2052
2053 vertex_data[3].position.x = x2;
2054 vertex_data[3].position.y = y1;
2055 vertex_data[3].position.z = 0.0f;
2056 vertex_data[3].texture.x = u;
2057 vertex_data[3].texture.y = v;
2058
2059 context_handle->Unmap (self->vertex_buffer, 0);
2060
2061 self->update_vertex = FALSE;
2062
2063 return TRUE;
2064 }
2065
2066 gboolean
gst_d3d11_converter_convert(GstD3D11Converter * converter,ID3D11ShaderResourceView * srv[GST_VIDEO_MAX_PLANES],ID3D11RenderTargetView * rtv[GST_VIDEO_MAX_PLANES],ID3D11BlendState * blend,gfloat blend_factor[4])2067 gst_d3d11_converter_convert (GstD3D11Converter * converter,
2068 ID3D11ShaderResourceView * srv[GST_VIDEO_MAX_PLANES],
2069 ID3D11RenderTargetView * rtv[GST_VIDEO_MAX_PLANES],
2070 ID3D11BlendState * blend, gfloat blend_factor[4])
2071 {
2072 gboolean ret;
2073
2074 g_return_val_if_fail (converter != NULL, FALSE);
2075 g_return_val_if_fail (srv != NULL, FALSE);
2076 g_return_val_if_fail (rtv != NULL, FALSE);
2077
2078 gst_d3d11_device_lock (converter->device);
2079 ret = gst_d3d11_converter_convert_unlocked (converter,
2080 srv, rtv, blend, blend_factor);
2081 gst_d3d11_device_unlock (converter->device);
2082
2083 return ret;
2084 }
2085
2086 gboolean
gst_d3d11_converter_convert_unlocked(GstD3D11Converter * converter,ID3D11ShaderResourceView * srv[GST_VIDEO_MAX_PLANES],ID3D11RenderTargetView * rtv[GST_VIDEO_MAX_PLANES],ID3D11BlendState * blend,gfloat blend_factor[4])2087 gst_d3d11_converter_convert_unlocked (GstD3D11Converter * converter,
2088 ID3D11ShaderResourceView * srv[GST_VIDEO_MAX_PLANES],
2089 ID3D11RenderTargetView * rtv[GST_VIDEO_MAX_PLANES],
2090 ID3D11BlendState * blend, gfloat blend_factor[4])
2091 {
2092 gboolean ret;
2093 /* *INDENT-OFF* */
2094 ComPtr<ID3D11Resource> resource;
2095 ComPtr<ID3D11Texture2D> texture;
2096 /* *INDENT-ON* */
2097 D3D11_TEXTURE2D_DESC desc;
2098
2099 g_return_val_if_fail (converter != NULL, FALSE);
2100 g_return_val_if_fail (srv != NULL, FALSE);
2101 g_return_val_if_fail (rtv != NULL, FALSE);
2102
2103 /* check texture resolution and update crop area */
2104 srv[0]->GetResource (&resource);
2105 resource.As (&texture);
2106 texture->GetDesc (&desc);
2107
2108 if (converter->update_vertex ||
2109 desc.Width != (guint) converter->input_texture_width ||
2110 desc.Height != (guint) converter->input_texture_height) {
2111 GST_DEBUG ("Update vertext buffer, texture resolution: %dx%d",
2112 desc.Width, desc.Height);
2113
2114 converter->input_texture_width = desc.Width;
2115 converter->input_texture_height = desc.Height;
2116
2117 if (!gst_d3d11_converter_update_vertex_buffer (converter)) {
2118 GST_ERROR ("Cannot update vertex buffer");
2119 return FALSE;
2120 }
2121 }
2122
2123 if (converter->update_alpha) {
2124 D3D11_MAPPED_SUBRESOURCE map;
2125 ID3D11DeviceContext *context_handle;
2126 AlphaConstBuffer *alpha_const;
2127 HRESULT hr;
2128
2129 g_assert (converter->alpha_const_buffer != nullptr);
2130
2131 context_handle =
2132 gst_d3d11_device_get_device_context_handle (converter->device);
2133
2134 hr = context_handle->Map (converter->alpha_const_buffer,
2135 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
2136
2137 if (!gst_d3d11_result (hr, converter->device)) {
2138 GST_ERROR ("Couldn't map constant buffer, hr: 0x%x", (guint) hr);
2139 return FALSE;
2140 }
2141
2142 alpha_const = (AlphaConstBuffer *) map.pData;
2143 alpha_const->alpha_mul = (FLOAT) converter->alpha;
2144
2145 context_handle->Unmap (converter->alpha_const_buffer, 0);
2146 converter->update_alpha = FALSE;
2147 }
2148
2149 ret = gst_d3d11_draw_quad_unlocked (converter->quad[0], converter->viewport,
2150 1, srv, converter->num_input_view, rtv, 1, blend, blend_factor,
2151 &converter->linear_sampler, 1);
2152
2153 if (!ret)
2154 return FALSE;
2155
2156 if (converter->quad[1]) {
2157 ret = gst_d3d11_draw_quad_unlocked (converter->quad[1],
2158 &converter->viewport[1], converter->num_output_view - 1,
2159 srv, converter->num_input_view, &rtv[1], converter->num_output_view - 1,
2160 blend, blend_factor, &converter->linear_sampler, 1);
2161
2162 if (!ret)
2163 return FALSE;
2164 }
2165
2166 return TRUE;
2167 }
2168
2169 gboolean
gst_d3d11_converter_update_viewport(GstD3D11Converter * converter,D3D11_VIEWPORT * viewport)2170 gst_d3d11_converter_update_viewport (GstD3D11Converter * converter,
2171 D3D11_VIEWPORT * viewport)
2172 {
2173 g_return_val_if_fail (converter != NULL, FALSE);
2174 g_return_val_if_fail (viewport != NULL, FALSE);
2175
2176 converter->viewport[0] = *viewport;
2177
2178 switch (GST_VIDEO_INFO_FORMAT (&converter->out_info)) {
2179 case GST_VIDEO_FORMAT_NV12:
2180 case GST_VIDEO_FORMAT_NV21:
2181 case GST_VIDEO_FORMAT_P010_10LE:
2182 case GST_VIDEO_FORMAT_P012_LE:
2183 case GST_VIDEO_FORMAT_P016_LE:
2184 case GST_VIDEO_FORMAT_I420:
2185 case GST_VIDEO_FORMAT_YV12:
2186 case GST_VIDEO_FORMAT_I420_10LE:
2187 case GST_VIDEO_FORMAT_I420_12LE:
2188 {
2189 guint i;
2190 converter->viewport[1].TopLeftX = converter->viewport[0].TopLeftX / 2;
2191 converter->viewport[1].TopLeftY = converter->viewport[0].TopLeftY / 2;
2192 converter->viewport[1].Width = converter->viewport[0].Width / 2;
2193 converter->viewport[1].Height = converter->viewport[0].Height / 2;
2194
2195 for (i = 2; i < GST_VIDEO_INFO_N_PLANES (&converter->out_info); i++)
2196 converter->viewport[i] = converter->viewport[1];
2197
2198 break;
2199 }
2200 case GST_VIDEO_FORMAT_Y42B:
2201 case GST_VIDEO_FORMAT_I422_10LE:
2202 case GST_VIDEO_FORMAT_I422_12LE:
2203 {
2204 guint i;
2205 converter->viewport[1].TopLeftX = converter->viewport[0].TopLeftX / 2;
2206 converter->viewport[1].TopLeftY = converter->viewport[0].TopLeftY;
2207 converter->viewport[1].Width = converter->viewport[0].Width / 2;
2208 converter->viewport[1].Height = converter->viewport[0].Height;
2209
2210 for (i = 2; i < GST_VIDEO_INFO_N_PLANES (&converter->out_info); i++)
2211 converter->viewport[i] = converter->viewport[1];
2212
2213 break;
2214 }
2215 case GST_VIDEO_FORMAT_Y444:
2216 case GST_VIDEO_FORMAT_Y444_10LE:
2217 case GST_VIDEO_FORMAT_Y444_12LE:
2218 case GST_VIDEO_FORMAT_Y444_16LE:
2219 {
2220 guint i;
2221 for (i = 1; i < GST_VIDEO_INFO_N_PLANES (&converter->out_info); i++)
2222 converter->viewport[i] = converter->viewport[1];
2223 break;
2224 }
2225 default:
2226 if (converter->num_output_view > 1)
2227 g_assert_not_reached ();
2228 break;
2229 }
2230
2231 return TRUE;
2232 }
2233
2234 gboolean
gst_d3d11_converter_update_src_rect(GstD3D11Converter * converter,RECT * src_rect)2235 gst_d3d11_converter_update_src_rect (GstD3D11Converter * converter,
2236 RECT * src_rect)
2237 {
2238 g_return_val_if_fail (converter != NULL, FALSE);
2239 g_return_val_if_fail (src_rect != NULL, FALSE);
2240
2241 gst_d3d11_device_lock (converter->device);
2242 if (converter->src_rect.left != src_rect->left ||
2243 converter->src_rect.top != src_rect->top ||
2244 converter->src_rect.right != src_rect->right ||
2245 converter->src_rect.bottom != src_rect->bottom) {
2246 converter->src_rect = *src_rect;
2247
2248 /* vertex buffer will be updated on next convert() call */
2249 converter->update_vertex = TRUE;
2250 }
2251 gst_d3d11_device_unlock (converter->device);
2252
2253 return TRUE;
2254 }
2255
2256 gboolean
gst_d3d11_converter_update_dest_rect(GstD3D11Converter * converter,RECT * dest_rect)2257 gst_d3d11_converter_update_dest_rect (GstD3D11Converter * converter,
2258 RECT * dest_rect)
2259 {
2260 g_return_val_if_fail (converter != NULL, FALSE);
2261 g_return_val_if_fail (dest_rect != NULL, FALSE);
2262
2263 gst_d3d11_device_lock (converter->device);
2264 if (converter->dest_rect.left != dest_rect->left ||
2265 converter->dest_rect.top != dest_rect->top ||
2266 converter->dest_rect.right != dest_rect->right ||
2267 converter->dest_rect.bottom != dest_rect->bottom) {
2268 converter->dest_rect = *dest_rect;
2269
2270 /* vertex buffer will be updated on next convert() call */
2271 converter->update_vertex = TRUE;
2272 }
2273 gst_d3d11_device_unlock (converter->device);
2274
2275 return TRUE;
2276 }
2277
2278 gboolean
gst_d3d11_converter_update_config(GstD3D11Converter * converter,GstStructure * config)2279 gst_d3d11_converter_update_config (GstD3D11Converter * converter,
2280 GstStructure * config)
2281 {
2282 g_return_val_if_fail (converter != nullptr, FALSE);
2283 g_return_val_if_fail (config != nullptr, FALSE);
2284
2285 gst_d3d11_device_lock (converter->device);
2286 gst_d3d11_converter_set_config (converter, config);
2287
2288 /* Check whether options are updated or not */
2289 if (converter->alpha_const_buffer) {
2290 gdouble alpha = GET_OPT_ALPHA_VALUE (converter);
2291
2292 if (alpha != converter->alpha) {
2293 GST_DEBUG ("Updating alpha %lf -> %lf", converter->alpha, alpha);
2294 converter->alpha = alpha;
2295 converter->update_alpha = TRUE;
2296 }
2297 }
2298 gst_d3d11_device_unlock (converter->device);
2299
2300 return TRUE;
2301 }
2302