d3d11compositor: Add gamma-mode and primaries-mode properties
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / sys / d3d11 / gstd3d11compositor.cpp
1 /*
2  * GStreamer
3  * Copyright (C) 2004, 2008 Wim Taymans <wim@fluendo.com>
4  * Copyright (C) 2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
5  * Copyright (C) 2014 Mathieu Duponchelle <mathieu.duponchelle@opencreed.com>
6  * Copyright (C) 2014 Thibault Saunier <tsaunier@gnome.org>
7  * Copyright (C) 2020 Seungha Yang <seungha@centricular.com>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  */
24
25 /**
26  * SECTION:element-d3d11compositor
27  * @title: d3d11compositor
28  *
29  * A Direct3D11 based video compositing element.
30  *
31  * ## Example launch line
32  * ```
33  * gst-launch-1.0 d3d11compositor name=c ! d3d11videosink \
34  *     videotestsrc ! video/x-raw,width=320,height=240 ! c. \
35  *     videotestsrc pattern=ball ! video/x-raw,width=100,height=100 ! c.
36  *
37  * Since: 1.20
38  *
39  */
40
41 #ifdef HAVE_CONFIG_H
42 #include "config.h"
43 #endif
44
45 #include "gstd3d11compositor.h"
46 #include "gstd3d11pluginutils.h"
47 #include <string.h>
48 #include <wrl.h>
49
50 GST_DEBUG_CATEGORY_STATIC (gst_d3d11_compositor_debug);
51 #define GST_CAT_DEFAULT gst_d3d11_compositor_debug
52
53 /* *INDENT-OFF* */
54 using namespace Microsoft::WRL;
55 /* *INDENT-ON* */
56
57 typedef enum
58 {
59   GST_D3D11_COMPOSITOR_BACKGROUND_CHECKER,
60   GST_D3D11_COMPOSITOR_BACKGROUND_BLACK,
61   GST_D3D11_COMPOSITOR_BACKGROUND_WHITE,
62   GST_D3D11_COMPOSITOR_BACKGROUND_TRANSPARENT,
63 } GstD3D11CompositorBackground;
64
65 #define GST_TYPE_D3D11_COMPOSITOR_BACKGROUND (gst_d3d11_compositor_background_get_type())
66 static GType
67 gst_d3d11_compositor_background_get_type (void)
68 {
69   static GType compositor_background_type = 0;
70
71   static const GEnumValue compositor_background[] = {
72     {GST_D3D11_COMPOSITOR_BACKGROUND_CHECKER, "Checker pattern", "checker"},
73     {GST_D3D11_COMPOSITOR_BACKGROUND_BLACK, "Black", "black"},
74     {GST_D3D11_COMPOSITOR_BACKGROUND_WHITE, "White", "white"},
75     {GST_D3D11_COMPOSITOR_BACKGROUND_TRANSPARENT,
76         "Transparent Background to enable further compositing", "transparent"},
77     {0, nullptr, nullptr},
78   };
79
80   if (!compositor_background_type) {
81     compositor_background_type =
82         g_enum_register_static ("GstD3D11CompositorBackground",
83         compositor_background);
84   }
85   return compositor_background_type;
86 }
87
88 typedef enum
89 {
90   GST_D3D11_COMPOSITOR_OPERATOR_SOURCE,
91   GST_D3D11_COMPOSITOR_OPERATOR_OVER,
92 } GstD3D11CompositorOperator;
93
94 #define GST_TYPE_D3D11_COMPOSITOR_OPERATOR (gst_d3d11_compositor_operator_get_type())
95 static GType
96 gst_d3d11_compositor_operator_get_type (void)
97 {
98   static GType compositor_operator_type = 0;
99
100   static const GEnumValue compositor_operator[] = {
101     {GST_D3D11_COMPOSITOR_OPERATOR_SOURCE, "Source", "source"},
102     {GST_D3D11_COMPOSITOR_OPERATOR_OVER, "Over", "over"},
103     {0, nullptr, nullptr},
104   };
105
106   if (!compositor_operator_type) {
107     compositor_operator_type =
108         g_enum_register_static ("GstD3D11CompositorOperator",
109         compositor_operator);
110   }
111   return compositor_operator_type;
112 }
113
114 typedef enum
115 {
116   GST_D3D11_COMPOSITOR_SIZING_POLICY_NONE,
117   GST_D3D11_COMPOSITOR_SIZING_POLICY_KEEP_ASPECT_RATIO,
118 } GstD3D11CompositorSizingPolicy;
119
120 #define GST_TYPE_D3D11_COMPOSITOR_SIZING_POLICY (gst_d3d11_compositor_sizing_policy_get_type())
121 static GType
122 gst_d3d11_compositor_sizing_policy_get_type (void)
123 {
124   static GType sizing_policy_type = 0;
125
126   static const GEnumValue sizing_polices[] = {
127     {GST_D3D11_COMPOSITOR_SIZING_POLICY_NONE,
128         "None: Image is scaled to fill configured destination rectangle without "
129           "padding or keeping the aspect ratio", "none"},
130     {GST_D3D11_COMPOSITOR_SIZING_POLICY_KEEP_ASPECT_RATIO,
131           "Keep Aspect Ratio: Image is scaled to fit destination rectangle "
132           "specified by GstCompositorPad:{xpos, ypos, width, height} "
133           "with preserved aspect ratio. Resulting image will be centered in "
134           "the destination rectangle with padding if necessary",
135         "keep-aspect-ratio"},
136     {0, nullptr, nullptr},
137   };
138
139   if (!sizing_policy_type) {
140     sizing_policy_type =
141         g_enum_register_static ("GstD3D11CompositorSizingPolicy",
142         sizing_polices);
143   }
144   return sizing_policy_type;
145 }
146
147 /* *INDENT-OFF* */
148 static const gchar checker_vs_src[] =
149     "struct VS_INPUT\n"
150     "{\n"
151     "  float4 Position : POSITION;\n"
152     "};\n"
153     "\n"
154     "struct VS_OUTPUT\n"
155     "{\n"
156     "  float4 Position: SV_POSITION;\n"
157     "};\n"
158     "\n"
159     "VS_OUTPUT main(VS_INPUT input)\n"
160     "{\n"
161     "  return input;\n"
162     "}\n";
163
164 static const gchar checker_ps_src_rgb[] =
165     "static const float blocksize = 8.0;\n"
166     "static const float4 high = float4(0.667, 0.667, 0.667, 1.0);\n"
167     "static const float4 low = float4(0.333, 0.333, 0.333, 1.0);\n"
168     "struct PS_INPUT\n"
169     "{\n"
170     "  float4 Position: SV_POSITION;\n"
171     "};\n"
172     "struct PS_OUTPUT\n"
173     "{\n"
174     "  float4 Plane: SV_TARGET;\n"
175     "};\n"
176     "PS_OUTPUT main(PS_INPUT input)\n"
177     "{\n"
178     "  PS_OUTPUT output;\n"
179     "  if ((input.Position.x % (blocksize * 2.0)) >= blocksize) {\n"
180     "    if ((input.Position.y % (blocksize * 2.0)) >= blocksize)\n"
181     "      output.Plane = low;\n"
182     "    else\n"
183     "      output.Plane = high;\n"
184     "  } else {\n"
185     "    if ((input.Position.y % (blocksize * 2.0)) < blocksize)\n"
186     "      output.Plane = low;\n"
187     "    else\n"
188     "      output.Plane = high;\n"
189     "  }\n"
190     "  return output;\n"
191     "}\n";
192
193 static const gchar checker_ps_src_vuya[] =
194     "static const float blocksize = 8.0;\n"
195     "static const float4 high = float4(0.5, 0.5, 0.667, 1.0);\n"
196     "static const float4 low = float4(0.5, 0.5, 0.333, 1.0);\n"
197     "struct PS_INPUT\n"
198     "{\n"
199     "  float4 Position: SV_POSITION;\n"
200     "};\n"
201     "struct PS_OUTPUT\n"
202     "{\n"
203     "  float4 Plane: SV_TARGET;\n"
204     "};\n"
205     "PS_OUTPUT main(PS_INPUT input)\n"
206     "{\n"
207     "  PS_OUTPUT output;\n"
208     "  if ((input.Position.x % (blocksize * 2.0)) >= blocksize) {\n"
209     "    if ((input.Position.y % (blocksize * 2.0)) >= blocksize)\n"
210     "      output.Plane = low;\n"
211     "    else\n"
212     "      output.Plane = high;\n"
213     "  } else {\n"
214     "    if ((input.Position.y % (blocksize * 2.0)) < blocksize)\n"
215     "      output.Plane = low;\n"
216     "    else\n"
217     "      output.Plane = high;\n"
218     "  }\n"
219     "  return output;\n"
220     "}\n";
221
222 static const gchar checker_ps_src_luma[] =
223     "static const float blocksize = 8.0;\n"
224     "static const float4 high = float4(0.667, 0.0, 0.0, 1.0);\n"
225     "static const float4 low = float4(0.333, 0.0, 0.0, 1.0);\n"
226     "struct PS_INPUT\n"
227     "{\n"
228     "  float4 Position: SV_POSITION;\n"
229     "};\n"
230     "struct PS_OUTPUT\n"
231     "{\n"
232     "  float4 Plane: SV_TARGET;\n"
233     "};\n"
234     "PS_OUTPUT main(PS_INPUT input)\n"
235     "{\n"
236     "  PS_OUTPUT output;\n"
237     "  if ((input.Position.x % (blocksize * 2.0)) >= blocksize) {\n"
238     "    if ((input.Position.y % (blocksize * 2.0)) >= blocksize)\n"
239     "      output.Plane = low;\n"
240     "    else\n"
241     "      output.Plane = high;\n"
242     "  } else {\n"
243     "    if ((input.Position.y % (blocksize * 2.0)) < blocksize)\n"
244     "      output.Plane = low;\n"
245     "    else\n"
246     "      output.Plane = high;\n"
247     "  }\n"
248     "  return output;\n"
249     "}\n";
250
251 static D3D11_RENDER_TARGET_BLEND_DESC blend_templ[] = {
252   /* SOURCE */
253   {
254     TRUE,
255     D3D11_BLEND_ONE, D3D11_BLEND_ZERO, D3D11_BLEND_OP_ADD,
256     D3D11_BLEND_ONE, D3D11_BLEND_ZERO, D3D11_BLEND_OP_ADD,
257     D3D11_COLOR_WRITE_ENABLE_ALL
258   },
259   /* OVER */
260   {
261     TRUE,
262     D3D11_BLEND_SRC_ALPHA, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD,
263     D3D11_BLEND_ONE, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD,
264     D3D11_COLOR_WRITE_ENABLE_ALL,
265   },
266 };
267 /* *INDENT-ON* */
268
269 struct _GstD3D11CompositorPad
270 {
271   GstVideoAggregatorConvertPad parent;
272
273   GstD3D11Converter *convert;
274
275   gboolean position_updated;
276   gboolean alpha_updated;
277   gboolean blend_desc_updated;
278   gboolean config_updated;
279   ID3D11BlendState *blend;
280
281   D3D11_RENDER_TARGET_BLEND_DESC desc;
282
283   /* properties */
284   gint xpos;
285   gint ypos;
286   gint width;
287   gint height;
288   gdouble alpha;
289   GstD3D11CompositorOperator op;
290   GstD3D11CompositorSizingPolicy sizing_policy;
291   GstVideoGammaMode gamma_mode;
292   GstVideoPrimariesMode primaries_mode;
293 };
294
295 typedef struct
296 {
297   ID3D11PixelShader *ps;
298   ID3D11VertexShader *vs;
299   ID3D11InputLayout *layout;
300   ID3D11Buffer *vertex_buffer;
301   ID3D11Buffer *index_buffer;
302   D3D11_VIEWPORT viewport;
303 } GstD3D11CompositorQuad;
304
305 typedef struct
306 {
307   /* [rtv][colors] */
308   FLOAT color[4][4];
309 } GstD3D11CompositorClearColor;
310
311 struct _GstD3D11Compositor
312 {
313   GstVideoAggregator parent;
314
315   GstD3D11Device *device;
316
317   GstBuffer *fallback_buf;
318
319   GstD3D11CompositorQuad *checker_background;
320   /* black/white/transparent */
321   GstD3D11CompositorClearColor clear_color[3];
322
323   gboolean downstream_supports_d3d11;
324
325   /* properties */
326   gint adapter;
327   GstD3D11CompositorBackground background;
328 };
329
330 enum
331 {
332   PROP_PAD_0,
333   PROP_PAD_XPOS,
334   PROP_PAD_YPOS,
335   PROP_PAD_WIDTH,
336   PROP_PAD_HEIGHT,
337   PROP_PAD_ALPHA,
338   PROP_PAD_OPERATOR,
339   PROP_PAD_SIZING_POLICY,
340   PROP_PAD_GAMMA_MODE,
341   PROP_PAD_PRIMARIES_MODE,
342 };
343
344 #define DEFAULT_PAD_XPOS   0
345 #define DEFAULT_PAD_YPOS   0
346 #define DEFAULT_PAD_WIDTH  0
347 #define DEFAULT_PAD_HEIGHT 0
348 #define DEFAULT_PAD_ALPHA  1.0
349 #define DEFAULT_PAD_OPERATOR GST_D3D11_COMPOSITOR_OPERATOR_OVER
350 #define DEFAULT_PAD_SIZING_POLICY GST_D3D11_COMPOSITOR_SIZING_POLICY_NONE
351 #define DEFAULT_PAD_GAMMA_MODE GST_VIDEO_GAMMA_MODE_NONE
352 #define DEFAULT_PAD_PRIMARIES_MODE GST_VIDEO_PRIMARIES_MODE_NONE
353
354 static void gst_d3d11_compositor_pad_set_property (GObject * object,
355     guint prop_id, const GValue * value, GParamSpec * pspec);
356 static void gst_d3d11_compositor_pad_get_property (GObject * object,
357     guint prop_id, GValue * value, GParamSpec * pspec);
358 static gboolean
359 gst_d3d11_compositor_pad_prepare_frame (GstVideoAggregatorPad * pad,
360     GstVideoAggregator * vagg, GstBuffer * buffer,
361     GstVideoFrame * prepared_frame);
362 static void gst_d3d11_compositor_pad_clean_frame (GstVideoAggregatorPad * vpad,
363     GstVideoAggregator * vagg, GstVideoFrame * prepared_frame);
364
365 #define gst_d3d11_compositor_pad_parent_class parent_pad_class
366 G_DEFINE_TYPE (GstD3D11CompositorPad, gst_d3d11_compositor_pad,
367     GST_TYPE_VIDEO_AGGREGATOR_PAD);
368
369 static void
370 gst_d3d11_compositor_pad_class_init (GstD3D11CompositorPadClass * klass)
371 {
372   GObjectClass *object_class = G_OBJECT_CLASS (klass);
373   GstVideoAggregatorPadClass *vagg_pad_class =
374       GST_VIDEO_AGGREGATOR_PAD_CLASS (klass);
375   GParamFlags param_flags = (GParamFlags)
376       (G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS);
377
378   object_class->set_property = gst_d3d11_compositor_pad_set_property;
379   object_class->get_property = gst_d3d11_compositor_pad_get_property;
380
381   g_object_class_install_property (object_class, PROP_PAD_XPOS,
382       g_param_spec_int ("xpos", "X Position", "X position of the picture",
383           G_MININT, G_MAXINT, DEFAULT_PAD_XPOS, param_flags));
384   g_object_class_install_property (object_class, PROP_PAD_YPOS,
385       g_param_spec_int ("ypos", "Y Position", "Y position of the picture",
386           G_MININT, G_MAXINT, DEFAULT_PAD_YPOS, param_flags));
387   g_object_class_install_property (object_class, PROP_PAD_WIDTH,
388       g_param_spec_int ("width", "Width", "Width of the picture",
389           G_MININT, G_MAXINT, DEFAULT_PAD_WIDTH, param_flags));
390   g_object_class_install_property (object_class, PROP_PAD_HEIGHT,
391       g_param_spec_int ("height", "Height", "Height of the picture",
392           G_MININT, G_MAXINT, DEFAULT_PAD_HEIGHT, param_flags));
393   g_object_class_install_property (object_class, PROP_PAD_ALPHA,
394       g_param_spec_double ("alpha", "Alpha", "Alpha of the picture", 0.0, 1.0,
395           DEFAULT_PAD_ALPHA, param_flags));
396   g_object_class_install_property (object_class, PROP_PAD_OPERATOR,
397       g_param_spec_enum ("operator", "Operator",
398           "Blending operator to use for blending this pad over the previous ones",
399           GST_TYPE_D3D11_COMPOSITOR_OPERATOR, DEFAULT_PAD_OPERATOR,
400           param_flags));
401   g_object_class_install_property (object_class, PROP_PAD_SIZING_POLICY,
402       g_param_spec_enum ("sizing-policy", "Sizing policy",
403           "Sizing policy to use for image scaling",
404           GST_TYPE_D3D11_COMPOSITOR_SIZING_POLICY, DEFAULT_PAD_SIZING_POLICY,
405           param_flags));
406
407   /**
408    * GstD3D11CompositorPad:gamma-mode:
409    *
410    * Gamma conversion mode
411    *
412    * Since: 1.22
413    */
414   g_object_class_install_property (object_class, PROP_PAD_GAMMA_MODE,
415       g_param_spec_enum ("gamma-mode", "Gamma mode",
416           "Gamma conversion mode", GST_TYPE_VIDEO_GAMMA_MODE,
417           DEFAULT_PAD_GAMMA_MODE, param_flags));
418
419   /**
420    * GstD3D11CompositorPad:primaries-mode:
421    *
422    * Primaries conversion mode
423    *
424    * Since: 1.22
425    */
426   g_object_class_install_property (object_class, PROP_PAD_PRIMARIES_MODE,
427       g_param_spec_enum ("primaries-mode", "Primaries Mode",
428           "Primaries conversion mode", GST_TYPE_VIDEO_PRIMARIES_MODE,
429           DEFAULT_PAD_PRIMARIES_MODE, param_flags));
430
431   vagg_pad_class->prepare_frame =
432       GST_DEBUG_FUNCPTR (gst_d3d11_compositor_pad_prepare_frame);
433   vagg_pad_class->clean_frame =
434       GST_DEBUG_FUNCPTR (gst_d3d11_compositor_pad_clean_frame);
435
436   gst_type_mark_as_plugin_api (GST_TYPE_D3D11_COMPOSITOR_OPERATOR,
437       (GstPluginAPIFlags) 0);
438   gst_type_mark_as_plugin_api (GST_TYPE_D3D11_COMPOSITOR_SIZING_POLICY,
439       (GstPluginAPIFlags) 0);
440 }
441
442 static void
443 gst_d3d11_compositor_pad_init (GstD3D11CompositorPad * pad)
444 {
445   pad->xpos = DEFAULT_PAD_XPOS;
446   pad->ypos = DEFAULT_PAD_YPOS;
447   pad->width = DEFAULT_PAD_WIDTH;
448   pad->height = DEFAULT_PAD_HEIGHT;
449   pad->alpha = DEFAULT_PAD_ALPHA;
450   pad->op = DEFAULT_PAD_OPERATOR;
451   pad->sizing_policy = DEFAULT_PAD_SIZING_POLICY;
452   pad->desc = blend_templ[DEFAULT_PAD_OPERATOR];
453   pad->gamma_mode = DEFAULT_PAD_GAMMA_MODE;
454   pad->primaries_mode = DEFAULT_PAD_PRIMARIES_MODE;
455 }
456
457 static void
458 gst_d3d11_compositor_pad_update_position (GstD3D11CompositorPad * self,
459     gint * old, const GValue * value)
460 {
461   gint tmp = g_value_get_int (value);
462
463   if (*old != tmp) {
464     *old = tmp;
465     self->position_updated = TRUE;
466   }
467 }
468
469 static void
470 gst_d3d11_compositor_pad_set_property (GObject * object, guint prop_id,
471     const GValue * value, GParamSpec * pspec)
472 {
473   GstD3D11CompositorPad *pad = GST_D3D11_COMPOSITOR_PAD (object);
474
475   switch (prop_id) {
476     case PROP_PAD_XPOS:
477       gst_d3d11_compositor_pad_update_position (pad, &pad->xpos, value);
478       break;
479     case PROP_PAD_YPOS:
480       gst_d3d11_compositor_pad_update_position (pad, &pad->ypos, value);
481       break;
482     case PROP_PAD_WIDTH:
483       gst_d3d11_compositor_pad_update_position (pad, &pad->width, value);
484       break;
485     case PROP_PAD_HEIGHT:
486       gst_d3d11_compositor_pad_update_position (pad, &pad->height, value);
487       break;
488     case PROP_PAD_ALPHA:{
489       gdouble alpha = g_value_get_double (value);
490       if (pad->alpha != alpha) {
491         pad->alpha_updated = TRUE;
492         pad->alpha = alpha;
493       }
494       break;
495     }
496     case PROP_PAD_OPERATOR:{
497       GstD3D11CompositorOperator op =
498           (GstD3D11CompositorOperator) g_value_get_enum (value);
499       if (op != pad->op) {
500         pad->op = op;
501         pad->desc = blend_templ[op];
502         pad->blend_desc_updated = TRUE;
503       }
504       break;
505     }
506     case PROP_PAD_SIZING_POLICY:{
507       GstD3D11CompositorSizingPolicy policy =
508           (GstD3D11CompositorSizingPolicy) g_value_get_enum (value);
509       if (pad->sizing_policy != policy) {
510         pad->sizing_policy = policy;
511         pad->position_updated = TRUE;
512       }
513       break;
514     }
515     case PROP_PAD_GAMMA_MODE:{
516       GstVideoGammaMode mode = (GstVideoGammaMode) g_value_get_enum (value);
517       if (pad->gamma_mode != mode) {
518         pad->gamma_mode = mode;
519         pad->config_updated = TRUE;
520       }
521       break;
522     }
523     case PROP_PAD_PRIMARIES_MODE:{
524       GstVideoPrimariesMode mode =
525           (GstVideoPrimariesMode) g_value_get_enum (value);
526       if (pad->primaries_mode != mode) {
527         pad->primaries_mode = mode;
528         pad->config_updated = TRUE;
529       }
530       break;
531     }
532     default:
533       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
534       break;
535   }
536 }
537
538 static void
539 gst_d3d11_compositor_pad_get_property (GObject * object, guint prop_id,
540     GValue * value, GParamSpec * pspec)
541 {
542   GstD3D11CompositorPad *pad = GST_D3D11_COMPOSITOR_PAD (object);
543
544   switch (prop_id) {
545     case PROP_PAD_XPOS:
546       g_value_set_int (value, pad->xpos);
547       break;
548     case PROP_PAD_YPOS:
549       g_value_set_int (value, pad->ypos);
550       break;
551     case PROP_PAD_WIDTH:
552       g_value_set_int (value, pad->width);
553       break;
554     case PROP_PAD_HEIGHT:
555       g_value_set_int (value, pad->height);
556       break;
557     case PROP_PAD_ALPHA:
558       g_value_set_double (value, pad->alpha);
559       break;
560     case PROP_PAD_OPERATOR:
561       g_value_set_enum (value, pad->op);
562       break;
563     case PROP_PAD_SIZING_POLICY:
564       g_value_set_enum (value, pad->sizing_policy);
565       break;
566     case PROP_PAD_GAMMA_MODE:
567       g_value_set_enum (value, pad->gamma_mode);
568       break;
569     case PROP_PAD_PRIMARIES_MODE:
570       g_value_set_enum (value, pad->primaries_mode);
571       break;
572     default:
573       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
574       break;
575   }
576 }
577
578 static void
579 gst_d3d11_compositor_pad_get_output_size (GstD3D11CompositorPad * comp_pad,
580     gint out_par_n, gint out_par_d, gint * width, gint * height,
581     gint * x_offset, gint * y_offset)
582 {
583   GstVideoAggregatorPad *vagg_pad = GST_VIDEO_AGGREGATOR_PAD (comp_pad);
584   gint pad_width, pad_height;
585   guint dar_n, dar_d;
586
587   *x_offset = 0;
588   *y_offset = 0;
589   *width = 0;
590   *height = 0;
591
592   /* FIXME: Anything better we can do here? */
593   if (!vagg_pad->info.finfo
594       || vagg_pad->info.finfo->format == GST_VIDEO_FORMAT_UNKNOWN) {
595     GST_DEBUG_OBJECT (comp_pad, "Have no caps yet");
596     return;
597   }
598
599   pad_width =
600       comp_pad->width <=
601       0 ? GST_VIDEO_INFO_WIDTH (&vagg_pad->info) : comp_pad->width;
602   pad_height =
603       comp_pad->height <=
604       0 ? GST_VIDEO_INFO_HEIGHT (&vagg_pad->info) : comp_pad->height;
605
606   if (pad_width == 0 || pad_height == 0)
607     return;
608
609   if (!gst_video_calculate_display_ratio (&dar_n, &dar_d, pad_width, pad_height,
610           GST_VIDEO_INFO_PAR_N (&vagg_pad->info),
611           GST_VIDEO_INFO_PAR_D (&vagg_pad->info), out_par_n, out_par_d)) {
612     GST_WARNING_OBJECT (comp_pad, "Cannot calculate display aspect ratio");
613     return;
614   }
615
616   GST_TRACE_OBJECT (comp_pad, "scaling %ux%u by %u/%u (%u/%u / %u/%u)",
617       pad_width, pad_height, dar_n, dar_d,
618       GST_VIDEO_INFO_PAR_N (&vagg_pad->info),
619       GST_VIDEO_INFO_PAR_D (&vagg_pad->info), out_par_n, out_par_d);
620
621   switch (comp_pad->sizing_policy) {
622     case GST_D3D11_COMPOSITOR_SIZING_POLICY_NONE:
623       /* Pick either height or width, whichever is an integer multiple of the
624        * display aspect ratio. However, prefer preserving the height to account
625        * for interlaced video. */
626       if (pad_height % dar_n == 0) {
627         pad_width = gst_util_uint64_scale_int (pad_height, dar_n, dar_d);
628       } else if (pad_width % dar_d == 0) {
629         pad_height = gst_util_uint64_scale_int (pad_width, dar_d, dar_n);
630       } else {
631         pad_width = gst_util_uint64_scale_int (pad_height, dar_n, dar_d);
632       }
633       break;
634     case GST_D3D11_COMPOSITOR_SIZING_POLICY_KEEP_ASPECT_RATIO:{
635       gint from_dar_n, from_dar_d, to_dar_n, to_dar_d, num, den;
636
637       /* Calculate DAR again with actual video size */
638       if (!gst_util_fraction_multiply (GST_VIDEO_INFO_WIDTH (&vagg_pad->info),
639               GST_VIDEO_INFO_HEIGHT (&vagg_pad->info),
640               GST_VIDEO_INFO_PAR_N (&vagg_pad->info),
641               GST_VIDEO_INFO_PAR_D (&vagg_pad->info), &from_dar_n,
642               &from_dar_d)) {
643         from_dar_n = from_dar_d = -1;
644       }
645
646       if (!gst_util_fraction_multiply (pad_width, pad_height,
647               out_par_n, out_par_d, &to_dar_n, &to_dar_d)) {
648         to_dar_n = to_dar_d = -1;
649       }
650
651       if (from_dar_n != to_dar_n || from_dar_d != to_dar_d) {
652         /* Calculate new output resolution */
653         if (from_dar_n != -1 && from_dar_d != -1
654             && gst_util_fraction_multiply (from_dar_n, from_dar_d,
655                 out_par_d, out_par_n, &num, &den)) {
656           GstVideoRectangle src_rect, dst_rect, rst_rect;
657
658           src_rect.h = gst_util_uint64_scale_int (pad_width, den, num);
659           if (src_rect.h == 0) {
660             pad_width = 0;
661             pad_height = 0;
662             break;
663           }
664
665           src_rect.x = src_rect.y = 0;
666           src_rect.w = pad_width;
667
668           dst_rect.x = dst_rect.y = 0;
669           dst_rect.w = pad_width;
670           dst_rect.h = pad_height;
671
672           /* Scale rect to be centered in destination rect */
673           gst_video_center_rect (&src_rect, &dst_rect, &rst_rect, TRUE);
674
675           GST_LOG_OBJECT (comp_pad,
676               "Re-calculated size %dx%d -> %dx%d (x-offset %d, y-offset %d)",
677               pad_width, pad_height, rst_rect.w, rst_rect.h, rst_rect.x,
678               rst_rect.h);
679
680           *x_offset = rst_rect.x;
681           *y_offset = rst_rect.y;
682           pad_width = rst_rect.w;
683           pad_height = rst_rect.h;
684         } else {
685           GST_WARNING_OBJECT (comp_pad, "Failed to calculate output size");
686
687           *x_offset = 0;
688           *y_offset = 0;
689           pad_width = 0;
690           pad_height = 0;
691         }
692       }
693       break;
694     }
695   }
696
697   *width = pad_width;
698   *height = pad_height;
699 }
700
701 static GstVideoRectangle
702 clamp_rectangle (gint x, gint y, gint w, gint h, gint outer_width,
703     gint outer_height)
704 {
705   gint x2 = x + w;
706   gint y2 = y + h;
707   GstVideoRectangle clamped;
708
709   /* Clamp the x/y coordinates of this frame to the output boundaries to cover
710    * the case where (say, with negative xpos/ypos or w/h greater than the output
711    * size) the non-obscured portion of the frame could be outside the bounds of
712    * the video itself and hence not visible at all */
713   clamped.x = CLAMP (x, 0, outer_width);
714   clamped.y = CLAMP (y, 0, outer_height);
715   clamped.w = CLAMP (x2, 0, outer_width) - clamped.x;
716   clamped.h = CLAMP (y2, 0, outer_height) - clamped.y;
717
718   return clamped;
719 }
720
721 static gboolean
722 gst_d3d11_compositor_pad_check_frame_obscured (GstVideoAggregatorPad * pad,
723     GstVideoAggregator * vagg)
724 {
725   GstD3D11CompositorPad *cpad = GST_D3D11_COMPOSITOR_PAD (pad);
726   gint width, height;
727   GstVideoInfo *info = &vagg->info;
728   /* The rectangle representing this frame, clamped to the video's boundaries.
729    * Due to the clamping, this is different from the frame width/height above. */
730   GstVideoRectangle frame_rect;
731   gint x_offset, y_offset;
732
733   /* There's three types of width/height here:
734    * 1. GST_VIDEO_FRAME_WIDTH/HEIGHT:
735    *     The frame width/height (same as pad->info.height/width;
736    *     see gst_video_frame_map())
737    * 2. cpad->width/height:
738    *     The optional pad property for scaling the frame (if zero, the video is
739    *     left unscaled)
740    */
741
742   gst_d3d11_compositor_pad_get_output_size (cpad, GST_VIDEO_INFO_PAR_N (info),
743       GST_VIDEO_INFO_PAR_D (info), &width, &height, &x_offset, &y_offset);
744
745   frame_rect = clamp_rectangle (cpad->xpos + x_offset, cpad->ypos + y_offset,
746       width, height, GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info));
747
748   if (frame_rect.w == 0 || frame_rect.h == 0) {
749     GST_DEBUG_OBJECT (pad, "Resulting frame is zero-width or zero-height "
750         "(w: %i, h: %i), skipping", frame_rect.w, frame_rect.h);
751     return TRUE;
752   }
753
754   return FALSE;
755 }
756
757 static gboolean
758 gst_d3d11_compositor_pad_prepare_frame (GstVideoAggregatorPad * pad,
759     GstVideoAggregator * vagg, GstBuffer * buffer,
760     GstVideoFrame * prepared_frame)
761 {
762   /* Skip this frame */
763   if (gst_d3d11_compositor_pad_check_frame_obscured (pad, vagg))
764     return TRUE;
765
766   /* don't map/upload now, it will happen in converter object.
767    * Just mark this frame is preparted instead */
768   prepared_frame->buffer = buffer;
769
770   return TRUE;
771 }
772
773 static void
774 gst_d3d11_compositor_pad_clean_frame (GstVideoAggregatorPad * vpad,
775     GstVideoAggregator * vagg, GstVideoFrame * prepared_frame)
776 {
777   memset (prepared_frame, 0, sizeof (GstVideoFrame));
778 }
779
780 static gboolean
781 gst_d3d11_compositor_pad_setup_converter (GstVideoAggregatorPad * pad,
782     GstVideoAggregator * vagg)
783 {
784   GstD3D11CompositorPad *cpad = GST_D3D11_COMPOSITOR_PAD (pad);
785   GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (vagg);
786   gint width, height;
787   GstVideoInfo *info = &vagg->info;
788   GstVideoRectangle frame_rect;
789   gboolean is_first = FALSE;
790   gboolean output_has_alpha_comp = FALSE;
791   gint x_offset, y_offset;
792 #ifndef GST_DISABLE_GST_DEBUG
793   guint zorder = 0;
794 #endif
795   static const D3D11_RENDER_TARGET_BLEND_DESC blend_over_no_alpha = {
796     TRUE,
797     D3D11_BLEND_BLEND_FACTOR, D3D11_BLEND_INV_BLEND_FACTOR, D3D11_BLEND_OP_ADD,
798     D3D11_BLEND_BLEND_FACTOR, D3D11_BLEND_INV_BLEND_FACTOR, D3D11_BLEND_OP_ADD,
799     D3D11_COLOR_WRITE_ENABLE_ALL,
800   };
801
802   if (GST_VIDEO_INFO_HAS_ALPHA (info) ||
803       GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_BGRx ||
804       GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_RGBx) {
805     output_has_alpha_comp = TRUE;
806   }
807
808   if (cpad->config_updated) {
809     gst_clear_object (&cpad->convert);
810     cpad->config_updated = FALSE;
811   }
812
813   if (!cpad->convert) {
814     GstStructure *config = gst_structure_new ("converter-config",
815         GST_D3D11_CONVERTER_OPT_GAMMA_MODE,
816         GST_TYPE_VIDEO_GAMMA_MODE, cpad->gamma_mode,
817         GST_D3D11_CONVERTER_OPT_PRIMARIES_MODE,
818         GST_TYPE_VIDEO_PRIMARIES_MODE, cpad->primaries_mode, nullptr);
819
820     cpad->convert = gst_d3d11_converter_new (self->device, &pad->info, info,
821         config);
822     if (!cpad->convert) {
823       GST_ERROR_OBJECT (pad, "Couldn't create converter");
824       return FALSE;
825     }
826
827     is_first = TRUE;
828   }
829
830   if (cpad->alpha_updated || is_first) {
831     if (output_has_alpha_comp) {
832       g_object_set (cpad->convert, "alpha", cpad->alpha, nullptr);
833     } else {
834       gfloat blend_factor = cpad->alpha;
835
836       g_object_set (cpad->convert,
837           "blend-factor-red", blend_factor,
838           "blend-factor-green", blend_factor,
839           "blend-factor-blue", blend_factor,
840           "blend-factor-alpha", blend_factor, nullptr);
841     }
842
843     cpad->alpha_updated = FALSE;
844   }
845
846   if (!cpad->blend || cpad->blend_desc_updated || is_first) {
847     HRESULT hr;
848     D3D11_BLEND_DESC desc = { 0, };
849     ID3D11BlendState *blend = nullptr;
850     ID3D11Device *device_handle =
851         gst_d3d11_device_get_device_handle (self->device);
852     gfloat blend_factor = 1.0f;
853
854     GST_D3D11_CLEAR_COM (cpad->blend);
855
856     desc.AlphaToCoverageEnable = FALSE;
857     desc.IndependentBlendEnable = FALSE;
858     desc.RenderTarget[0] = cpad->desc;
859     if (!output_has_alpha_comp &&
860         cpad->op == GST_D3D11_COMPOSITOR_OPERATOR_OVER) {
861       desc.RenderTarget[0] = blend_over_no_alpha;
862       blend_factor = cpad->alpha;
863     }
864
865     hr = device_handle->CreateBlendState (&desc, &blend);
866     if (!gst_d3d11_result (hr, self->device)) {
867       GST_ERROR_OBJECT (pad, "Couldn't create blend staten, hr: 0x%x",
868           (guint) hr);
869       return FALSE;
870     }
871
872     cpad->blend = blend;
873     g_object_set (cpad->convert, "blend-state", blend,
874         "blend-factor-red", blend_factor,
875         "blend-factor-green", blend_factor,
876         "blend-factor-blue", blend_factor,
877         "blend-factor-alpha", blend_factor, nullptr);
878
879     cpad->blend_desc_updated = FALSE;
880   }
881
882   if (!is_first && !cpad->position_updated)
883     return TRUE;
884
885   gst_d3d11_compositor_pad_get_output_size (cpad, GST_VIDEO_INFO_PAR_N (info),
886       GST_VIDEO_INFO_PAR_D (info), &width, &height, &x_offset, &y_offset);
887
888   frame_rect = clamp_rectangle (cpad->xpos + x_offset, cpad->ypos + y_offset,
889       width, height, GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info));
890
891 #ifndef GST_DISABLE_GST_DEBUG
892   g_object_get (pad, "zorder", &zorder, nullptr);
893
894   GST_LOG_OBJECT (pad, "Update position, pad-xpos %d, pad-ypos %d, "
895       "pad-zorder %d, pad-width %d, pad-height %d, in-resolution %dx%d, "
896       "out-resoution %dx%d, dst-{x,y,width,height} %d-%d-%d-%d",
897       cpad->xpos, cpad->ypos, zorder, cpad->width, cpad->height,
898       GST_VIDEO_INFO_WIDTH (&pad->info), GST_VIDEO_INFO_HEIGHT (&pad->info),
899       GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info),
900       frame_rect.x, frame_rect.y, frame_rect.w, frame_rect.h);
901 #endif
902
903   cpad->position_updated = FALSE;
904
905   g_object_set (cpad->convert, "dest-x", frame_rect.x,
906       "dest-y", frame_rect.y, "dest-width", frame_rect.w,
907       "dest-height", frame_rect.h, nullptr);
908
909   return TRUE;
910 }
911
912 static GstStaticCaps sink_pad_template_caps =
913     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
914     (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, GST_D3D11_SINK_FORMATS) "; "
915     GST_VIDEO_CAPS_MAKE (GST_D3D11_SINK_FORMATS));
916
917 /* formats we can output without conversion.
918  * Excludes 10/12 bits planar YUV (needs bitshift) and
919  * AYUV/AYUV64 (d3d11 runtime does not understand the ayuv order) */
920 #define COMPOSITOR_SRC_FORMATS \
921     "{ RGBA64_LE, RGB10A2_LE, BGRA, RGBA, BGRx, RGBx, VUYA, NV12, NV21, " \
922     "P010_10LE, P012_LE, P016_LE, I420, YV12, Y42B, Y444, Y444_16LE, " \
923     "GRAY8, GRAY16_LE }"
924
925 static GstStaticCaps src_pad_template_caps =
926     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
927     (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, COMPOSITOR_SRC_FORMATS) "; "
928     GST_VIDEO_CAPS_MAKE (COMPOSITOR_SRC_FORMATS));
929
930 enum
931 {
932   PROP_0,
933   PROP_ADAPTER,
934   PROP_BACKGROUND,
935 };
936
937 #define DEFAULT_ADAPTER -1
938 #define DEFAULT_BACKGROUND GST_D3D11_COMPOSITOR_BACKGROUND_CHECKER
939
940 static void gst_d3d11_compositor_child_proxy_init (gpointer g_iface,
941     gpointer iface_data);
942 static void gst_d3d11_compositor_dispose (GObject * object);
943 static void gst_d3d11_compositor_set_property (GObject * object,
944     guint prop_id, const GValue * value, GParamSpec * pspec);
945 static void gst_d3d11_compositor_get_property (GObject * object,
946     guint prop_id, GValue * value, GParamSpec * pspec);
947
948 static GstPad *gst_d3d11_compositor_request_new_pad (GstElement * element,
949     GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
950 static void gst_d3d11_compositor_release_pad (GstElement * element,
951     GstPad * pad);
952 static void gst_d3d11_compositor_set_context (GstElement * element,
953     GstContext * context);
954
955 static gboolean gst_d3d11_compositor_start (GstAggregator * agg);
956 static gboolean gst_d3d11_compositor_stop (GstAggregator * agg);
957 static gboolean gst_d3d11_compositor_sink_query (GstAggregator * agg,
958     GstAggregatorPad * pad, GstQuery * query);
959 static gboolean gst_d3d11_compositor_src_query (GstAggregator * agg,
960     GstQuery * query);
961 static GstCaps *gst_d3d11_compositor_fixate_src_caps (GstAggregator * agg,
962     GstCaps * caps);
963 static gboolean gst_d3d11_compositor_negotiated_src_caps (GstAggregator * agg,
964     GstCaps * caps);
965 static gboolean
966 gst_d3d11_compositor_propose_allocation (GstAggregator * agg,
967     GstAggregatorPad * pad, GstQuery * decide_query, GstQuery * query);
968 static gboolean gst_d3d11_compositor_decide_allocation (GstAggregator * agg,
969     GstQuery * query);
970 static GstFlowReturn
971 gst_d3d11_compositor_aggregate_frames (GstVideoAggregator * vagg,
972     GstBuffer * outbuf);
973 static GstFlowReturn
974 gst_d3d11_compositor_create_output_buffer (GstVideoAggregator * vagg,
975     GstBuffer ** outbuffer);
976 static void gst_d3d11_compositor_quad_free (GstD3D11CompositorQuad * quad);
977
978 #define gst_d3d11_compositor_parent_class parent_class
979 G_DEFINE_TYPE_WITH_CODE (GstD3D11Compositor, gst_d3d11_compositor,
980     GST_TYPE_VIDEO_AGGREGATOR, G_IMPLEMENT_INTERFACE (GST_TYPE_CHILD_PROXY,
981         gst_d3d11_compositor_child_proxy_init));
982
983 static void
984 gst_d3d11_compositor_class_init (GstD3D11CompositorClass * klass)
985 {
986   GObjectClass *object_class = G_OBJECT_CLASS (klass);
987   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
988   GstAggregatorClass *agg_class = GST_AGGREGATOR_CLASS (klass);
989   GstVideoAggregatorClass *vagg_class = GST_VIDEO_AGGREGATOR_CLASS (klass);
990   GstCaps *caps;
991
992   object_class->dispose = gst_d3d11_compositor_dispose;
993   object_class->set_property = gst_d3d11_compositor_set_property;
994   object_class->get_property = gst_d3d11_compositor_get_property;
995
996   g_object_class_install_property (object_class, PROP_ADAPTER,
997       g_param_spec_int ("adapter", "Adapter",
998           "Adapter index for creating device (-1 for default)",
999           -1, G_MAXINT32, DEFAULT_ADAPTER,
1000           (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY |
1001               G_PARAM_STATIC_STRINGS)));
1002
1003   g_object_class_install_property (object_class, PROP_BACKGROUND,
1004       g_param_spec_enum ("background", "Background", "Background type",
1005           GST_TYPE_D3D11_COMPOSITOR_BACKGROUND,
1006           DEFAULT_BACKGROUND,
1007           (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
1008
1009   element_class->request_new_pad =
1010       GST_DEBUG_FUNCPTR (gst_d3d11_compositor_request_new_pad);
1011   element_class->release_pad =
1012       GST_DEBUG_FUNCPTR (gst_d3d11_compositor_release_pad);
1013   element_class->set_context =
1014       GST_DEBUG_FUNCPTR (gst_d3d11_compositor_set_context);
1015
1016   agg_class->start = GST_DEBUG_FUNCPTR (gst_d3d11_compositor_start);
1017   agg_class->stop = GST_DEBUG_FUNCPTR (gst_d3d11_compositor_stop);
1018   agg_class->sink_query = GST_DEBUG_FUNCPTR (gst_d3d11_compositor_sink_query);
1019   agg_class->src_query = GST_DEBUG_FUNCPTR (gst_d3d11_compositor_src_query);
1020   agg_class->fixate_src_caps =
1021       GST_DEBUG_FUNCPTR (gst_d3d11_compositor_fixate_src_caps);
1022   agg_class->negotiated_src_caps =
1023       GST_DEBUG_FUNCPTR (gst_d3d11_compositor_negotiated_src_caps);
1024   agg_class->propose_allocation =
1025       GST_DEBUG_FUNCPTR (gst_d3d11_compositor_propose_allocation);
1026   agg_class->decide_allocation =
1027       GST_DEBUG_FUNCPTR (gst_d3d11_compositor_decide_allocation);
1028
1029   vagg_class->aggregate_frames =
1030       GST_DEBUG_FUNCPTR (gst_d3d11_compositor_aggregate_frames);
1031   vagg_class->create_output_buffer =
1032       GST_DEBUG_FUNCPTR (gst_d3d11_compositor_create_output_buffer);
1033
1034   caps = gst_d3d11_get_updated_template_caps (&sink_pad_template_caps);
1035   gst_element_class_add_pad_template (element_class,
1036       gst_pad_template_new_with_gtype ("sink_%u", GST_PAD_SINK, GST_PAD_REQUEST,
1037           caps, GST_TYPE_D3D11_COMPOSITOR_PAD));
1038   gst_caps_unref (caps);
1039
1040   caps = gst_d3d11_get_updated_template_caps (&src_pad_template_caps);
1041   gst_element_class_add_pad_template (element_class,
1042       gst_pad_template_new_with_gtype ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
1043           caps, GST_TYPE_AGGREGATOR_PAD));
1044   gst_caps_unref (caps);
1045
1046   gst_element_class_set_static_metadata (element_class, "Direct3D11 Compositor",
1047       "Filter/Editor/Video/Compositor", "A Direct3D11 compositor",
1048       "Seungha Yang <seungha@centricular.com>");
1049
1050   gst_type_mark_as_plugin_api (GST_TYPE_D3D11_COMPOSITOR_BACKGROUND,
1051       (GstPluginAPIFlags) 0);
1052   gst_type_mark_as_plugin_api (GST_TYPE_D3D11_COMPOSITOR_PAD,
1053       (GstPluginAPIFlags) 0);
1054
1055   GST_DEBUG_CATEGORY_INIT (gst_d3d11_compositor_debug,
1056       "d3d11compositor", 0, "d3d11compositor element");
1057 }
1058
1059 static void
1060 gst_d3d11_compositor_init (GstD3D11Compositor * self)
1061 {
1062   self->adapter = DEFAULT_ADAPTER;
1063   self->background = DEFAULT_BACKGROUND;
1064 }
1065
1066 static void
1067 gst_d3d11_compositor_dispose (GObject * object)
1068 {
1069   GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (object);
1070
1071   gst_clear_object (&self->device);
1072   gst_clear_buffer (&self->fallback_buf);
1073   g_clear_pointer (&self->checker_background, gst_d3d11_compositor_quad_free);
1074
1075   G_OBJECT_CLASS (parent_class)->dispose (object);
1076 }
1077
1078 static void
1079 gst_d3d11_compositor_set_property (GObject * object,
1080     guint prop_id, const GValue * value, GParamSpec * pspec)
1081 {
1082   GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (object);
1083
1084   switch (prop_id) {
1085     case PROP_ADAPTER:
1086       self->adapter = g_value_get_int (value);
1087       break;
1088     case PROP_BACKGROUND:
1089       self->background =
1090           (GstD3D11CompositorBackground) g_value_get_enum (value);
1091       break;
1092     default:
1093       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1094       break;
1095   }
1096 }
1097
1098 static void
1099 gst_d3d11_compositor_get_property (GObject * object,
1100     guint prop_id, GValue * value, GParamSpec * pspec)
1101 {
1102   GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (object);
1103
1104   switch (prop_id) {
1105     case PROP_ADAPTER:
1106       g_value_set_int (value, self->adapter);
1107       break;
1108     case PROP_BACKGROUND:
1109       g_value_set_enum (value, self->background);
1110       break;
1111     default:
1112       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1113       break;
1114   }
1115 }
1116
1117 static GObject *
1118 gst_d3d11_compositor_child_proxy_get_child_by_index (GstChildProxy * proxy,
1119     guint index)
1120 {
1121   GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (proxy);
1122   GObject *obj = nullptr;
1123
1124   GST_OBJECT_LOCK (self);
1125   obj = (GObject *) g_list_nth_data (GST_ELEMENT_CAST (self)->sinkpads, index);
1126   if (obj)
1127     gst_object_ref (obj);
1128   GST_OBJECT_UNLOCK (self);
1129
1130   return obj;
1131 }
1132
1133 static guint
1134 gst_d3d11_compositor_child_proxy_get_children_count (GstChildProxy * proxy)
1135 {
1136   GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (proxy);
1137   guint count = 0;
1138
1139   GST_OBJECT_LOCK (self);
1140   count = GST_ELEMENT_CAST (self)->numsinkpads;
1141   GST_OBJECT_UNLOCK (self);
1142   GST_INFO_OBJECT (self, "Children Count: %d", count);
1143
1144   return count;
1145 }
1146
1147 static void
1148 gst_d3d11_compositor_child_proxy_init (gpointer g_iface, gpointer iface_data)
1149 {
1150   GstChildProxyInterface *iface = (GstChildProxyInterface *) g_iface;
1151
1152   iface->get_child_by_index =
1153       gst_d3d11_compositor_child_proxy_get_child_by_index;
1154   iface->get_children_count =
1155       gst_d3d11_compositor_child_proxy_get_children_count;
1156 }
1157
1158 static GstPad *
1159 gst_d3d11_compositor_request_new_pad (GstElement * element,
1160     GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
1161 {
1162   GstPad *pad;
1163
1164   pad = GST_ELEMENT_CLASS (parent_class)->request_new_pad (element,
1165       templ, name, caps);
1166
1167   if (!pad) {
1168     GST_DEBUG_OBJECT (element, "could not create/add pad");
1169     return nullptr;
1170   }
1171
1172   gst_child_proxy_child_added (GST_CHILD_PROXY (element), G_OBJECT (pad),
1173       GST_OBJECT_NAME (pad));
1174
1175   GST_DEBUG_OBJECT (element, "Created new pad %s:%s", GST_DEBUG_PAD_NAME (pad));
1176
1177   return pad;
1178 }
1179
1180 static gboolean
1181 gst_d3d11_compositor_pad_clear_resource (GstD3D11Compositor * self,
1182     GstD3D11CompositorPad * cpad, gpointer user_data)
1183 {
1184   gst_clear_object (&cpad->convert);
1185   GST_D3D11_CLEAR_COM (cpad->blend);
1186
1187   return TRUE;
1188 }
1189
1190 static void
1191 gst_d3d11_compositor_release_pad (GstElement * element, GstPad * pad)
1192 {
1193   GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (element);
1194   GstD3D11CompositorPad *cpad = GST_D3D11_COMPOSITOR_PAD (pad);
1195
1196   GST_DEBUG_OBJECT (self, "Releasing pad %s:%s", GST_DEBUG_PAD_NAME (pad));
1197
1198   gst_child_proxy_child_removed (GST_CHILD_PROXY (self), G_OBJECT (pad),
1199       GST_OBJECT_NAME (pad));
1200
1201   gst_d3d11_compositor_pad_clear_resource (self, cpad, nullptr);
1202
1203   GST_ELEMENT_CLASS (parent_class)->release_pad (element, pad);
1204 }
1205
1206 static void
1207 gst_d3d11_compositor_set_context (GstElement * element, GstContext * context)
1208 {
1209   GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (element);
1210
1211   gst_d3d11_handle_set_context (element, context, self->adapter, &self->device);
1212
1213   GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
1214 }
1215
1216 static gboolean
1217 gst_d3d11_compositor_start (GstAggregator * agg)
1218 {
1219   GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (agg);
1220
1221   if (!gst_d3d11_ensure_element_data (GST_ELEMENT_CAST (self),
1222           self->adapter, &self->device)) {
1223     GST_ERROR_OBJECT (self, "Failed to get D3D11 device");
1224     return FALSE;
1225   }
1226
1227   return GST_AGGREGATOR_CLASS (parent_class)->start (agg);
1228 }
1229
1230 static gboolean
1231 gst_d3d11_compositor_stop (GstAggregator * agg)
1232 {
1233   GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (agg);
1234
1235   g_clear_pointer (&self->checker_background, gst_d3d11_compositor_quad_free);
1236   gst_clear_object (&self->device);
1237
1238   return GST_AGGREGATOR_CLASS (parent_class)->stop (agg);
1239 }
1240
1241 static GstCaps *
1242 gst_d3d11_compositor_sink_getcaps (GstPad * pad, GstCaps * filter)
1243 {
1244   GstCaps *sinkcaps;
1245   GstCaps *template_caps;
1246   GstCaps *filtered_caps;
1247   GstCaps *returned_caps;
1248
1249   template_caps = gst_pad_get_pad_template_caps (pad);
1250
1251   sinkcaps = gst_pad_get_current_caps (pad);
1252   if (sinkcaps == nullptr) {
1253     sinkcaps = gst_caps_ref (template_caps);
1254   } else {
1255     sinkcaps = gst_caps_merge (sinkcaps, gst_caps_ref (template_caps));
1256   }
1257
1258   if (filter) {
1259     filtered_caps = gst_caps_intersect (sinkcaps, filter);
1260     gst_caps_unref (sinkcaps);
1261   } else {
1262     filtered_caps = sinkcaps;   /* pass ownership */
1263   }
1264
1265   returned_caps = gst_caps_intersect (filtered_caps, template_caps);
1266
1267   gst_caps_unref (template_caps);
1268   gst_caps_unref (filtered_caps);
1269
1270   GST_DEBUG_OBJECT (pad, "returning %" GST_PTR_FORMAT, returned_caps);
1271
1272   return returned_caps;
1273 }
1274
1275 static gboolean
1276 gst_d3d11_compositor_sink_acceptcaps (GstPad * pad, GstCaps * caps)
1277 {
1278   gboolean ret;
1279   GstCaps *template_caps;
1280
1281   GST_DEBUG_OBJECT (pad, "try accept caps of %" GST_PTR_FORMAT, caps);
1282
1283   template_caps = gst_pad_get_pad_template_caps (pad);
1284   template_caps = gst_caps_make_writable (template_caps);
1285
1286   ret = gst_caps_can_intersect (caps, template_caps);
1287   GST_DEBUG_OBJECT (pad, "%saccepted caps %" GST_PTR_FORMAT,
1288       (ret ? "" : "not "), caps);
1289   gst_caps_unref (template_caps);
1290
1291   return ret;
1292 }
1293
1294 static gboolean
1295 gst_d3d11_compositor_sink_query (GstAggregator * agg,
1296     GstAggregatorPad * pad, GstQuery * query)
1297 {
1298   GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (agg);
1299
1300   switch (GST_QUERY_TYPE (query)) {
1301     case GST_QUERY_CONTEXT:
1302       if (gst_d3d11_handle_context_query (GST_ELEMENT (agg), query,
1303               self->device)) {
1304         return TRUE;
1305       }
1306       break;
1307     case GST_QUERY_CAPS:{
1308       GstCaps *filter, *caps;
1309
1310       gst_query_parse_caps (query, &filter);
1311       caps = gst_d3d11_compositor_sink_getcaps (GST_PAD (pad), filter);
1312       gst_query_set_caps_result (query, caps);
1313       gst_caps_unref (caps);
1314       return TRUE;
1315     }
1316     case GST_QUERY_ACCEPT_CAPS:{
1317       GstCaps *caps;
1318       gboolean ret;
1319
1320       gst_query_parse_accept_caps (query, &caps);
1321       ret = gst_d3d11_compositor_sink_acceptcaps (GST_PAD (pad), caps);
1322       gst_query_set_accept_caps_result (query, ret);
1323       return TRUE;
1324     }
1325     default:
1326       break;
1327   }
1328
1329   return GST_AGGREGATOR_CLASS (parent_class)->sink_query (agg, pad, query);
1330 }
1331
1332 static gboolean
1333 gst_d3d11_compositor_src_query (GstAggregator * agg, GstQuery * query)
1334 {
1335   GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (agg);
1336
1337   switch (GST_QUERY_TYPE (query)) {
1338     case GST_QUERY_CONTEXT:
1339       if (gst_d3d11_handle_context_query (GST_ELEMENT (agg), query,
1340               self->device)) {
1341         return TRUE;
1342       }
1343       break;
1344     default:
1345       break;
1346   }
1347
1348   return GST_AGGREGATOR_CLASS (parent_class)->src_query (agg, query);
1349 }
1350
1351 static GstCaps *
1352 gst_d3d11_compositor_fixate_src_caps (GstAggregator * agg, GstCaps * caps)
1353 {
1354   GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (agg);
1355   GList *l;
1356   gint best_width = -1, best_height = -1;
1357   gint best_fps_n = -1, best_fps_d = -1;
1358   gint par_n, par_d;
1359   gdouble best_fps = 0.;
1360   GstCaps *ret = nullptr;
1361   GstStructure *s;
1362
1363   ret = gst_caps_make_writable (caps);
1364
1365   /* we need this to calculate how large to make the output frame */
1366   s = gst_caps_get_structure (ret, 0);
1367   if (gst_structure_has_field (s, "pixel-aspect-ratio")) {
1368     gst_structure_fixate_field_nearest_fraction (s, "pixel-aspect-ratio", 1, 1);
1369     gst_structure_get_fraction (s, "pixel-aspect-ratio", &par_n, &par_d);
1370   } else {
1371     par_n = par_d = 1;
1372   }
1373
1374   GST_OBJECT_LOCK (vagg);
1375   for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) {
1376     GstVideoAggregatorPad *vaggpad = GST_VIDEO_AGGREGATOR_PAD (l->data);
1377     GstD3D11CompositorPad *cpad = GST_D3D11_COMPOSITOR_PAD (vaggpad);
1378     gint this_width, this_height;
1379     gint width, height;
1380     gint fps_n, fps_d;
1381     gdouble cur_fps;
1382     gint x_offset;
1383     gint y_offset;
1384
1385     fps_n = GST_VIDEO_INFO_FPS_N (&vaggpad->info);
1386     fps_d = GST_VIDEO_INFO_FPS_D (&vaggpad->info);
1387     gst_d3d11_compositor_pad_get_output_size (cpad,
1388         par_n, par_d, &width, &height, &x_offset, &y_offset);
1389
1390     if (width == 0 || height == 0)
1391       continue;
1392
1393     /* {x,y}_offset represent padding size of each top and left area.
1394      * To calculate total resolution, count bottom and right padding area
1395      * as well here */
1396     this_width = width + MAX (cpad->xpos + 2 * x_offset, 0);
1397     this_height = height + MAX (cpad->ypos + 2 * y_offset, 0);
1398
1399     if (best_width < this_width)
1400       best_width = this_width;
1401     if (best_height < this_height)
1402       best_height = this_height;
1403
1404     if (fps_d == 0)
1405       cur_fps = 0.0;
1406     else
1407       gst_util_fraction_to_double (fps_n, fps_d, &cur_fps);
1408
1409     if (best_fps < cur_fps) {
1410       best_fps = cur_fps;
1411       best_fps_n = fps_n;
1412       best_fps_d = fps_d;
1413     }
1414   }
1415   GST_OBJECT_UNLOCK (vagg);
1416
1417   if (best_fps_n <= 0 || best_fps_d <= 0 || best_fps == 0.0) {
1418     best_fps_n = 25;
1419     best_fps_d = 1;
1420     best_fps = 25.0;
1421   }
1422
1423   gst_structure_fixate_field_nearest_int (s, "width", best_width);
1424   gst_structure_fixate_field_nearest_int (s, "height", best_height);
1425   gst_structure_fixate_field_nearest_fraction (s, "framerate", best_fps_n,
1426       best_fps_d);
1427   ret = gst_caps_fixate (ret);
1428
1429   GST_LOG_OBJECT (agg, "Fixated caps %" GST_PTR_FORMAT, ret);
1430
1431   return ret;
1432 }
1433
1434 static void
1435 convert_info_gray_to_yuv (const GstVideoInfo * gray, GstVideoInfo * yuv)
1436 {
1437   GstVideoInfo tmp;
1438
1439   if (GST_VIDEO_INFO_IS_YUV (gray)) {
1440     *yuv = *gray;
1441     return;
1442   }
1443
1444   if (gray->finfo->depth[0] == 8) {
1445     gst_video_info_set_format (&tmp,
1446         GST_VIDEO_FORMAT_Y444, gray->width, gray->height);
1447   } else {
1448     gst_video_info_set_format (&tmp,
1449         GST_VIDEO_FORMAT_Y444_16LE, gray->width, gray->height);
1450   }
1451
1452   tmp.colorimetry.range = gray->colorimetry.range;
1453   if (tmp.colorimetry.range == GST_VIDEO_COLOR_RANGE_UNKNOWN)
1454     tmp.colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
1455
1456   tmp.colorimetry.primaries = gray->colorimetry.primaries;
1457   if (tmp.colorimetry.primaries == GST_VIDEO_COLOR_PRIMARIES_UNKNOWN)
1458     tmp.colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
1459
1460   tmp.colorimetry.transfer = gray->colorimetry.transfer;
1461   if (tmp.colorimetry.transfer == GST_VIDEO_TRANSFER_UNKNOWN)
1462     tmp.colorimetry.transfer = GST_VIDEO_TRANSFER_BT709;
1463
1464   tmp.colorimetry.matrix = gray->colorimetry.matrix;
1465   if (tmp.colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_UNKNOWN)
1466     tmp.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT709;
1467
1468   *yuv = tmp;
1469 }
1470
1471 static void
1472 gst_d3d11_compositor_calculate_background_color (GstD3D11Compositor * self,
1473     const GstVideoInfo * info)
1474 {
1475   GstD3D11ColorMatrix clear_color_matrix;
1476   gdouble rgb[3];
1477   gdouble converted[3];
1478   GstVideoFormat format = GST_VIDEO_INFO_FORMAT (info);
1479
1480   if (GST_VIDEO_INFO_IS_RGB (info)) {
1481     GstVideoInfo rgb_info = *info;
1482     rgb_info.colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
1483
1484     gst_d3d11_color_range_adjust_matrix_unorm (&rgb_info, info,
1485         &clear_color_matrix);
1486   } else {
1487     GstVideoInfo rgb_info;
1488     GstVideoInfo yuv_info;
1489
1490     gst_video_info_set_format (&rgb_info, GST_VIDEO_FORMAT_RGBA64_LE,
1491         info->width, info->height);
1492     convert_info_gray_to_yuv (info, &yuv_info);
1493
1494     if (yuv_info.colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_UNKNOWN ||
1495         yuv_info.colorimetry.matrix == GST_VIDEO_COLOR_MATRIX_RGB) {
1496       GST_WARNING_OBJECT (self, "Invalid matrix is detected");
1497       yuv_info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT709;
1498     }
1499
1500     gst_d3d11_rgb_to_yuv_matrix_unorm (&rgb_info,
1501         &yuv_info, &clear_color_matrix);
1502   }
1503
1504   /* Calculate black and white color values */
1505   for (guint i = 0; i < 2; i++) {
1506     GstD3D11CompositorClearColor *clear_color = &self->clear_color[i];
1507     rgb[0] = rgb[1] = rgb[2] = (gdouble) i;
1508
1509     for (guint j = 0; j < 3; j++) {
1510       converted[j] = 0;
1511       for (guint k = 0; k < 3; k++) {
1512         converted[j] += clear_color_matrix.matrix[j][k] * rgb[k];
1513       }
1514       converted[j] += clear_color_matrix.offset[j];
1515       converted[j] = CLAMP (converted[j],
1516           clear_color_matrix.min[j], clear_color_matrix.max[j]);
1517     }
1518
1519     GST_DEBUG_OBJECT (self, "Calculated background color RGB: %f, %f, %f",
1520         converted[0], converted[1], converted[2]);
1521
1522     if (GST_VIDEO_INFO_IS_RGB (info) || GST_VIDEO_INFO_IS_GRAY (info)) {
1523       for (guint j = 0; j < 3; j++)
1524         clear_color->color[0][j] = converted[j];
1525       clear_color->color[0][3] = 1.0;
1526     } else {
1527       switch (format) {
1528         case GST_VIDEO_FORMAT_VUYA:
1529           clear_color->color[0][0] = converted[2];
1530           clear_color->color[0][1] = converted[1];
1531           clear_color->color[0][2] = converted[0];
1532           clear_color->color[0][3] = 1.0;
1533           break;
1534         case GST_VIDEO_FORMAT_NV12:
1535         case GST_VIDEO_FORMAT_NV21:
1536         case GST_VIDEO_FORMAT_P010_10LE:
1537         case GST_VIDEO_FORMAT_P012_LE:
1538         case GST_VIDEO_FORMAT_P016_LE:
1539           clear_color->color[0][0] = converted[0];
1540           clear_color->color[0][1] = 0;
1541           clear_color->color[0][2] = 0;
1542           clear_color->color[0][3] = 1.0;
1543           if (format == GST_VIDEO_FORMAT_NV21) {
1544             clear_color->color[1][0] = converted[2];
1545             clear_color->color[1][1] = converted[1];
1546           } else {
1547             clear_color->color[1][0] = converted[1];
1548             clear_color->color[1][1] = converted[2];
1549           }
1550           clear_color->color[1][2] = 0;
1551           clear_color->color[1][3] = 1.0;
1552           break;
1553         case GST_VIDEO_FORMAT_I420:
1554         case GST_VIDEO_FORMAT_YV12:
1555         case GST_VIDEO_FORMAT_I420_10LE:
1556         case GST_VIDEO_FORMAT_I420_12LE:
1557         case GST_VIDEO_FORMAT_Y42B:
1558         case GST_VIDEO_FORMAT_I422_10LE:
1559         case GST_VIDEO_FORMAT_I422_12LE:
1560         case GST_VIDEO_FORMAT_Y444:
1561         case GST_VIDEO_FORMAT_Y444_10LE:
1562         case GST_VIDEO_FORMAT_Y444_12LE:
1563         case GST_VIDEO_FORMAT_Y444_16LE:
1564           clear_color->color[0][0] = converted[0];
1565           clear_color->color[0][1] = 0;
1566           clear_color->color[0][2] = 0;
1567           clear_color->color[0][3] = 1.0;
1568           if (format == GST_VIDEO_FORMAT_YV12) {
1569             clear_color->color[1][0] = converted[2];
1570             clear_color->color[2][0] = converted[1];
1571           } else {
1572             clear_color->color[1][0] = converted[1];
1573             clear_color->color[2][0] = converted[2];
1574           }
1575           clear_color->color[1][1] = 0;
1576           clear_color->color[1][2] = 0;
1577           clear_color->color[1][3] = 1.0;
1578           clear_color->color[2][1] = 0;
1579           clear_color->color[2][2] = 0;
1580           clear_color->color[2][3] = 1.0;
1581           break;
1582         default:
1583           g_assert_not_reached ();
1584           break;
1585       }
1586     }
1587   }
1588 }
1589
1590 static gboolean
1591 gst_d3d11_compositor_negotiated_src_caps (GstAggregator * agg, GstCaps * caps)
1592 {
1593   GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (agg);
1594   GstCapsFeatures *features;
1595   GstVideoInfo info;
1596
1597   if (!gst_video_info_from_caps (&info, caps)) {
1598     GST_ERROR_OBJECT (self, "Failed to convert caps to info");
1599     return FALSE;
1600   }
1601
1602   features = gst_caps_get_features (caps, 0);
1603   if (features
1604       && gst_caps_features_contains (features,
1605           GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY)) {
1606     GST_DEBUG_OBJECT (self, "Negotiated with D3D11 memory caps");
1607     self->downstream_supports_d3d11 = TRUE;
1608   } else {
1609     GST_DEBUG_OBJECT (self, "Negotiated with system memory caps");
1610     self->downstream_supports_d3d11 = FALSE;
1611   }
1612
1613   gst_element_foreach_sink_pad (GST_ELEMENT_CAST (self),
1614       (GstElementForeachPadFunc) gst_d3d11_compositor_pad_clear_resource,
1615       nullptr);
1616
1617   gst_clear_buffer (&self->fallback_buf);
1618   g_clear_pointer (&self->checker_background, gst_d3d11_compositor_quad_free);
1619
1620   gst_d3d11_compositor_calculate_background_color (self, &info);
1621
1622   if (!self->downstream_supports_d3d11) {
1623     GstD3D11AllocationParams *d3d11_params;
1624     GstBufferPool *pool;
1625     GstFlowReturn flow_ret;
1626
1627     d3d11_params = gst_d3d11_allocation_params_new (self->device,
1628         &info, GST_D3D11_ALLOCATION_FLAG_DEFAULT,
1629         D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET, 0);
1630
1631     pool = gst_d3d11_buffer_pool_new_with_options (self->device,
1632         caps, d3d11_params, 0, 0);
1633     gst_d3d11_allocation_params_free (d3d11_params);
1634
1635     if (!pool) {
1636       GST_ERROR_OBJECT (self, "Failed to create pool");
1637       return FALSE;
1638     }
1639
1640     if (!gst_buffer_pool_set_active (pool, TRUE)) {
1641       GST_ERROR_OBJECT (self, "Failed to set active");
1642       gst_object_unref (pool);
1643       return FALSE;
1644     }
1645
1646     flow_ret = gst_buffer_pool_acquire_buffer (pool, &self->fallback_buf,
1647         nullptr);
1648     if (flow_ret != GST_FLOW_OK) {
1649       GST_ERROR_OBJECT (self, "Failed to acquire buffer");
1650       gst_object_unref (pool);
1651       return FALSE;
1652     }
1653
1654     gst_buffer_pool_set_active (pool, FALSE);
1655     gst_object_unref (pool);
1656   }
1657
1658   return GST_AGGREGATOR_CLASS (parent_class)->negotiated_src_caps (agg, caps);
1659 }
1660
1661 static gboolean
1662 gst_d3d11_compositor_propose_allocation (GstAggregator * agg,
1663     GstAggregatorPad * pad, GstQuery * decide_query, GstQuery * query)
1664 {
1665   GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (agg);
1666   GstVideoInfo info;
1667   GstBufferPool *pool;
1668   GstCaps *caps;
1669   guint size;
1670
1671   gst_query_parse_allocation (query, &caps, nullptr);
1672
1673   if (caps == nullptr)
1674     return FALSE;
1675
1676   if (!gst_video_info_from_caps (&info, caps))
1677     return FALSE;
1678
1679   if (gst_query_get_n_allocation_pools (query) == 0) {
1680     GstCapsFeatures *features;
1681     GstStructure *config;
1682     gboolean is_d3d11 = FALSE;
1683
1684     features = gst_caps_get_features (caps, 0);
1685     if (features
1686         && gst_caps_features_contains (features,
1687             GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY)) {
1688       GST_DEBUG_OBJECT (pad, "upstream support d3d11 memory");
1689       pool = gst_d3d11_buffer_pool_new (self->device);
1690       is_d3d11 = TRUE;
1691     } else {
1692       pool = gst_video_buffer_pool_new ();
1693     }
1694
1695     if (!pool) {
1696       GST_ERROR_OBJECT (self, "Failed to create buffer pool");
1697       return FALSE;
1698     }
1699
1700     config = gst_buffer_pool_get_config (pool);
1701     gst_buffer_pool_config_add_option (config,
1702         GST_BUFFER_POOL_OPTION_VIDEO_META);
1703
1704     size = GST_VIDEO_INFO_SIZE (&info);
1705     if (is_d3d11) {
1706       GstD3D11AllocationParams *d3d11_params;
1707
1708       d3d11_params =
1709           gst_d3d11_allocation_params_new (self->device,
1710           &info, GST_D3D11_ALLOCATION_FLAG_DEFAULT, D3D11_BIND_SHADER_RESOURCE,
1711           0);
1712
1713       gst_buffer_pool_config_set_d3d11_allocation_params (config, d3d11_params);
1714       gst_d3d11_allocation_params_free (d3d11_params);
1715     } else {
1716       gst_buffer_pool_config_add_option (config,
1717           GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
1718     }
1719
1720     gst_buffer_pool_config_set_params (config, caps, (guint) size, 0, 0);
1721
1722     if (!gst_buffer_pool_set_config (pool, config)) {
1723       GST_ERROR_OBJECT (pool, "Couldn't set config");
1724       gst_object_unref (pool);
1725
1726       return FALSE;
1727     }
1728
1729     /* d3d11 buffer pool will update buffer size based on allocated texture,
1730      * get size from config again */
1731     config = gst_buffer_pool_get_config (pool);
1732     gst_buffer_pool_config_get_params (config,
1733         nullptr, &size, nullptr, nullptr);
1734     gst_structure_free (config);
1735
1736     gst_query_add_allocation_pool (query, pool, size, 0, 0);
1737     gst_object_unref (pool);
1738   }
1739
1740   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, nullptr);
1741   gst_query_add_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE, nullptr);
1742
1743   return TRUE;
1744 }
1745
1746 static gboolean
1747 gst_d3d11_compositor_decide_allocation (GstAggregator * agg, GstQuery * query)
1748 {
1749   GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (agg);
1750   GstCaps *caps;
1751   GstBufferPool *pool = nullptr;
1752   guint n, size, min, max;
1753   GstVideoInfo info;
1754   GstStructure *config;
1755   gboolean use_d3d11_pool;
1756
1757   gst_query_parse_allocation (query, &caps, nullptr);
1758
1759   if (!caps) {
1760     GST_DEBUG_OBJECT (self, "No output caps");
1761     return FALSE;
1762   }
1763
1764   if (!gst_video_info_from_caps (&info, caps)) {
1765     GST_ERROR_OBJECT (self, "Invalid caps");
1766     return FALSE;
1767   }
1768
1769   use_d3d11_pool = self->downstream_supports_d3d11;
1770
1771   n = gst_query_get_n_allocation_pools (query);
1772   if (n > 0)
1773     gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
1774
1775   /* create our own pool */
1776   if (pool && use_d3d11_pool) {
1777     if (!GST_IS_D3D11_BUFFER_POOL (pool)) {
1778       GST_DEBUG_OBJECT (self,
1779           "Downstream pool is not d3d11, will create new one");
1780       gst_clear_object (&pool);
1781     } else {
1782       GstD3D11BufferPool *dpool = GST_D3D11_BUFFER_POOL (pool);
1783       if (dpool->device != self->device) {
1784         GST_DEBUG_OBJECT (self, "Different device, will create new one");
1785         gst_clear_object (&pool);
1786       }
1787     }
1788   }
1789
1790   size = (guint) info.size;
1791
1792   if (!pool) {
1793     if (use_d3d11_pool)
1794       pool = gst_d3d11_buffer_pool_new (self->device);
1795     else
1796       pool = gst_video_buffer_pool_new ();
1797
1798     min = 0;
1799     max = 0;
1800   }
1801
1802   config = gst_buffer_pool_get_config (pool);
1803   gst_buffer_pool_config_set_params (config, caps, size, min, max);
1804   gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
1805
1806   if (use_d3d11_pool) {
1807     GstD3D11AllocationParams *d3d11_params;
1808
1809     d3d11_params = gst_buffer_pool_config_get_d3d11_allocation_params (config);
1810     if (!d3d11_params) {
1811       d3d11_params = gst_d3d11_allocation_params_new (self->device,
1812           &info, GST_D3D11_ALLOCATION_FLAG_DEFAULT, D3D11_BIND_RENDER_TARGET,
1813           0);
1814     } else {
1815       guint i;
1816
1817       for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&info); i++) {
1818         d3d11_params->desc[i].BindFlags |= D3D11_BIND_RENDER_TARGET;
1819       }
1820     }
1821
1822     gst_buffer_pool_config_set_d3d11_allocation_params (config, d3d11_params);
1823     gst_d3d11_allocation_params_free (d3d11_params);
1824   }
1825
1826   gst_buffer_pool_set_config (pool, config);
1827
1828   /* d3d11 buffer pool will update buffer size based on allocated texture,
1829    * get size from config again */
1830   config = gst_buffer_pool_get_config (pool);
1831   gst_buffer_pool_config_get_params (config, nullptr, &size, nullptr, nullptr);
1832   gst_structure_free (config);
1833
1834   if (n > 0)
1835     gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
1836   else
1837     gst_query_add_allocation_pool (query, pool, size, min, max);
1838   gst_object_unref (pool);
1839
1840   return TRUE;
1841 }
1842
1843 typedef struct
1844 {
1845   struct
1846   {
1847     FLOAT x;
1848     FLOAT y;
1849     FLOAT z;
1850   } position;
1851   struct
1852   {
1853     FLOAT u;
1854     FLOAT v;
1855   } texture;
1856 } VertexData;
1857
1858 static GstD3D11CompositorQuad *
1859 gst_d3d11_compositor_create_checker_quad (GstD3D11Compositor * self,
1860     const GstVideoInfo * info)
1861 {
1862   GstD3D11CompositorQuad *quad = nullptr;
1863   VertexData *vertex_data;
1864   WORD *indices;
1865   ID3D11Device *device_handle;
1866   ID3D11DeviceContext *context_handle;
1867   D3D11_MAPPED_SUBRESOURCE map;
1868   D3D11_INPUT_ELEMENT_DESC input_desc;
1869   D3D11_BUFFER_DESC buffer_desc;
1870   ComPtr < ID3D11Buffer > vertex_buffer;
1871   ComPtr < ID3D11Buffer > index_buffer;
1872   ComPtr < ID3D11PixelShader > ps;
1873   ComPtr < ID3D11VertexShader > vs;
1874   ComPtr < ID3D11InputLayout > layout;
1875   HRESULT hr;
1876   const gchar *ps_src;
1877
1878   device_handle = gst_d3d11_device_get_device_handle (self->device);
1879   context_handle = gst_d3d11_device_get_device_context_handle (self->device);
1880
1881   if (GST_VIDEO_INFO_IS_RGB (info)) {
1882     ps_src = checker_ps_src_rgb;
1883   } else if (GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_VUYA) {
1884     ps_src = checker_ps_src_vuya;
1885   } else {
1886     ps_src = checker_ps_src_luma;
1887   }
1888
1889   hr = gst_d3d11_create_pixel_shader_simple (self->device, ps_src, "main", &ps);
1890   if (!gst_d3d11_result (hr, self->device)) {
1891     GST_ERROR_OBJECT (self, "Couldn't setup pixel shader");
1892     return nullptr;
1893   }
1894
1895   memset (&input_desc, 0, sizeof (D3D11_INPUT_ELEMENT_DESC));
1896   input_desc.SemanticName = "POSITION";
1897   input_desc.SemanticIndex = 0;
1898   input_desc.Format = DXGI_FORMAT_R32G32B32_FLOAT;
1899   input_desc.InputSlot = 0;
1900   input_desc.AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
1901   input_desc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
1902   input_desc.InstanceDataStepRate = 0;
1903
1904   hr = gst_d3d11_create_vertex_shader_simple (self->device, checker_vs_src,
1905       "main", &input_desc, 1, &vs, &layout);
1906   if (!gst_d3d11_result (hr, self->device)) {
1907     GST_ERROR_OBJECT (self, "Couldn't setup vertex shader");
1908     return nullptr;
1909   }
1910
1911   memset (&buffer_desc, 0, sizeof (D3D11_BUFFER_DESC));
1912   buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
1913   buffer_desc.ByteWidth = sizeof (VertexData) * 4;
1914   buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
1915   buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1916
1917   hr = device_handle->CreateBuffer (&buffer_desc, nullptr, &vertex_buffer);
1918   if (!gst_d3d11_result (hr, self->device)) {
1919     GST_ERROR_OBJECT (self,
1920         "Couldn't create vertex buffer, hr: 0x%x", (guint) hr);
1921     return nullptr;
1922   }
1923
1924   hr = context_handle->Map (vertex_buffer.Get (),
1925       0, D3D11_MAP_WRITE_DISCARD, 0, &map);
1926
1927   if (!gst_d3d11_result (hr, self->device)) {
1928     GST_ERROR_OBJECT (self, "Couldn't map vertex buffer, hr: 0x%x", (guint) hr);
1929     return nullptr;
1930   }
1931
1932   vertex_data = (VertexData *) map.pData;
1933   /* bottom left */
1934   vertex_data[0].position.x = -1.0f;
1935   vertex_data[0].position.y = -1.0f;
1936   vertex_data[0].position.z = 0.0f;
1937   vertex_data[0].texture.u = 0.0f;
1938   vertex_data[0].texture.v = 1.0f;
1939
1940   /* top left */
1941   vertex_data[1].position.x = -1.0f;
1942   vertex_data[1].position.y = 1.0f;
1943   vertex_data[1].position.z = 0.0f;
1944   vertex_data[1].texture.u = 0.0f;
1945   vertex_data[1].texture.v = 0.0f;
1946
1947   /* top right */
1948   vertex_data[2].position.x = 1.0f;
1949   vertex_data[2].position.y = 1.0f;
1950   vertex_data[2].position.z = 0.0f;
1951   vertex_data[2].texture.u = 1.0f;
1952   vertex_data[2].texture.v = 0.0f;
1953
1954   /* bottom right */
1955   vertex_data[3].position.x = 1.0f;
1956   vertex_data[3].position.y = -1.0f;
1957   vertex_data[3].position.z = 0.0f;
1958   vertex_data[3].texture.u = 1.0f;
1959   vertex_data[3].texture.v = 1.0f;
1960
1961   context_handle->Unmap (vertex_buffer.Get (), 0);
1962
1963   buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
1964   buffer_desc.ByteWidth = sizeof (WORD) * 6;
1965   buffer_desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
1966   buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1967
1968   hr = device_handle->CreateBuffer (&buffer_desc, nullptr, &index_buffer);
1969   if (!gst_d3d11_result (hr, self->device)) {
1970     GST_ERROR_OBJECT (self,
1971         "Couldn't create index buffer, hr: 0x%x", (guint) hr);
1972     return nullptr;
1973   }
1974
1975   hr = context_handle->Map (index_buffer.Get (),
1976       0, D3D11_MAP_WRITE_DISCARD, 0, &map);
1977
1978   if (!gst_d3d11_result (hr, self->device)) {
1979     GST_ERROR_OBJECT (self, "Couldn't map index buffer, hr: 0x%x", (guint) hr);
1980     return nullptr;
1981   }
1982
1983   indices = (WORD *) map.pData;
1984
1985   /* clockwise indexing */
1986   indices[0] = 0;               /* bottom left */
1987   indices[1] = 1;               /* top left */
1988   indices[2] = 2;               /* top right */
1989
1990   indices[3] = 3;               /* bottom right */
1991   indices[4] = 0;               /* bottom left  */
1992   indices[5] = 2;               /* top right */
1993
1994   context_handle->Unmap (index_buffer.Get (), 0);
1995   quad = g_new0 (GstD3D11CompositorQuad, 1);
1996   quad->ps = ps.Detach ();
1997   quad->vs = vs.Detach ();
1998   quad->layout = layout.Detach ();
1999   quad->vertex_buffer = vertex_buffer.Detach ();
2000   quad->index_buffer = index_buffer.Detach ();
2001
2002   quad->viewport.TopLeftX = 0;
2003   quad->viewport.TopLeftY = 0;
2004   quad->viewport.Width = GST_VIDEO_INFO_WIDTH (info);
2005   quad->viewport.Height = GST_VIDEO_INFO_HEIGHT (info);
2006   quad->viewport.MinDepth = 0.0f;
2007   quad->viewport.MaxDepth = 1.0f;
2008
2009   return quad;
2010 }
2011
2012 static void
2013 gst_d3d11_compositor_quad_free (GstD3D11CompositorQuad * quad)
2014 {
2015   if (!quad)
2016     return;
2017
2018   GST_D3D11_CLEAR_COM (quad->ps);
2019   GST_D3D11_CLEAR_COM (quad->vs);
2020   GST_D3D11_CLEAR_COM (quad->layout);
2021   GST_D3D11_CLEAR_COM (quad->vertex_buffer);
2022   GST_D3D11_CLEAR_COM (quad->index_buffer);
2023
2024   g_free (quad);
2025 }
2026
2027 static gboolean
2028 gst_d3d11_compositor_draw_background_checker (GstD3D11Compositor * self,
2029     ID3D11RenderTargetView * rtv)
2030 {
2031   ID3D11DeviceContext *context =
2032       gst_d3d11_device_get_device_context_handle (self->device);
2033   UINT offsets = 0;
2034   UINT strides = sizeof (VertexData);
2035   GstD3D11CompositorQuad *quad;
2036
2037   if (!self->checker_background) {
2038     GstVideoInfo *info = &GST_VIDEO_AGGREGATOR_CAST (self)->info;
2039
2040     self->checker_background =
2041         gst_d3d11_compositor_create_checker_quad (self, info);
2042     if (!self->checker_background)
2043       return FALSE;
2044   }
2045
2046   quad = self->checker_background;
2047   context->IASetPrimitiveTopology (D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
2048   context->IASetInputLayout (quad->layout);
2049   context->IASetVertexBuffers (0, 1, &quad->vertex_buffer, &strides, &offsets);
2050   context->IASetIndexBuffer (quad->index_buffer, DXGI_FORMAT_R16_UINT, 0);
2051   context->VSSetShader (quad->vs, nullptr, 0);
2052   context->PSSetShader (quad->ps, nullptr, 0);
2053   context->RSSetViewports (1, &quad->viewport);
2054   context->OMSetRenderTargets (1, &rtv, nullptr);
2055   context->OMSetBlendState (nullptr, nullptr, 0xffffffff);
2056   context->DrawIndexed (6, 0, 0);
2057   context->OMSetRenderTargets (0, nullptr, nullptr);
2058
2059   return TRUE;
2060 }
2061
2062 /* Must be called with d3d11 device lock */
2063 static gboolean
2064 gst_d3d11_compositor_draw_background (GstD3D11Compositor * self,
2065     ID3D11RenderTargetView * rtv[GST_VIDEO_MAX_PLANES], guint num_rtv)
2066 {
2067   ID3D11DeviceContext *context =
2068       gst_d3d11_device_get_device_context_handle (self->device);
2069   GstD3D11CompositorClearColor *color = &self->clear_color[0];
2070
2071   if (self->background == GST_D3D11_COMPOSITOR_BACKGROUND_CHECKER) {
2072     if (!gst_d3d11_compositor_draw_background_checker (self, rtv[0]))
2073       return FALSE;
2074
2075     /* clear U and V components if needed */
2076     for (guint i = 1; i < num_rtv; i++)
2077       context->ClearRenderTargetView (rtv[i], color->color[i]);
2078
2079     return TRUE;
2080   }
2081
2082   switch (self->background) {
2083     case GST_D3D11_COMPOSITOR_BACKGROUND_BLACK:
2084       color = &self->clear_color[0];
2085       break;
2086     case GST_D3D11_COMPOSITOR_BACKGROUND_WHITE:
2087       color = &self->clear_color[1];
2088       break;
2089     case GST_D3D11_COMPOSITOR_BACKGROUND_TRANSPARENT:
2090       color = &self->clear_color[2];
2091       break;
2092     default:
2093       g_assert_not_reached ();
2094       return FALSE;
2095   }
2096
2097   for (guint i = 0; i < num_rtv; i++)
2098     context->ClearRenderTargetView (rtv[i], color->color[i]);
2099
2100   return TRUE;
2101 }
2102
2103 static GstFlowReturn
2104 gst_d3d11_compositor_aggregate_frames (GstVideoAggregator * vagg,
2105     GstBuffer * outbuf)
2106 {
2107   GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (vagg);
2108   GList *iter;
2109   GstBuffer *target_buf = outbuf;
2110   GstFlowReturn ret = GST_FLOW_OK;
2111   ID3D11RenderTargetView *rtv[GST_VIDEO_MAX_PLANES] = { nullptr, };
2112   GstVideoFrame target_frame;
2113   guint num_rtv = GST_VIDEO_INFO_N_PLANES (&vagg->info);
2114   GstD3D11DeviceLockGuard lk (self->device);
2115
2116   if (!self->downstream_supports_d3d11)
2117     target_buf = self->fallback_buf;
2118
2119   if (!gst_video_frame_map (&target_frame, &vagg->info, target_buf,
2120           (GstMapFlags) (GST_MAP_WRITE | GST_MAP_D3D11))) {
2121     GST_ERROR_OBJECT (self, "Failed to map render target frame");
2122     return GST_FLOW_ERROR;
2123   }
2124
2125   if (!gst_d3d11_buffer_get_render_target_view (target_buf, rtv)) {
2126     GST_ERROR_OBJECT (self, "RTV is unavailable");
2127     gst_video_frame_unmap (&target_frame);
2128     return GST_FLOW_ERROR;
2129   }
2130
2131   if (!gst_d3d11_compositor_draw_background (self, rtv, num_rtv)) {
2132     GST_ERROR_OBJECT (self, "Couldn't draw background");
2133     gst_video_frame_unmap (&target_frame);
2134     return GST_FLOW_ERROR;
2135   }
2136
2137   gst_video_frame_unmap (&target_frame);
2138
2139   GST_OBJECT_LOCK (self);
2140   for (iter = GST_ELEMENT (vagg)->sinkpads; iter; iter = g_list_next (iter)) {
2141     GstVideoAggregatorPad *pad = GST_VIDEO_AGGREGATOR_PAD (iter->data);
2142     GstD3D11CompositorPad *cpad = GST_D3D11_COMPOSITOR_PAD (pad);
2143     GstVideoFrame *prepared_frame =
2144         gst_video_aggregator_pad_get_prepared_frame (pad);
2145     gint x, y, w, h;
2146     GstVideoCropMeta *crop_meta;
2147
2148     if (!prepared_frame)
2149       continue;
2150
2151     if (!gst_d3d11_compositor_pad_setup_converter (pad, vagg)) {
2152       GST_ERROR_OBJECT (self, "Couldn't setup converter");
2153       ret = GST_FLOW_ERROR;
2154       break;
2155     }
2156
2157     crop_meta = gst_buffer_get_video_crop_meta (prepared_frame->buffer);
2158     if (crop_meta) {
2159       x = crop_meta->x;
2160       y = crop_meta->y;
2161       w = crop_meta->width;
2162       h = crop_meta->height;
2163     } else {
2164       x = y = 0;
2165       w = pad->info.width;
2166       h = pad->info.height;
2167     }
2168
2169     g_object_set (cpad->convert, "src-x", x, "src-y", y, "src-width", w,
2170         "src-height", h, nullptr);
2171
2172     if (!gst_d3d11_converter_convert_buffer_unlocked (cpad->convert,
2173             prepared_frame->buffer, target_buf)) {
2174       GST_ERROR_OBJECT (self, "Couldn't convert frame");
2175       ret = GST_FLOW_ERROR;
2176       break;
2177     }
2178   }
2179   GST_OBJECT_UNLOCK (self);
2180
2181   if (ret != GST_FLOW_OK)
2182     return ret;
2183
2184   if (!self->downstream_supports_d3d11) {
2185     if (!gst_d3d11_buffer_copy_into (outbuf, self->fallback_buf, &vagg->info)) {
2186       GST_ERROR_OBJECT (self, "Couldn't copy input buffer to fallback buffer");
2187       return GST_FLOW_ERROR;
2188     }
2189   }
2190
2191   return GST_FLOW_OK;
2192 }
2193
2194 typedef struct
2195 {
2196   /* without holding ref */
2197   GstD3D11Device *other_device;
2198   gboolean have_same_device;
2199 } DeviceCheckData;
2200
2201 static gboolean
2202 gst_d3d11_compositor_check_device_update (GstElement * agg,
2203     GstVideoAggregatorPad * vpad, DeviceCheckData * data)
2204 {
2205   GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (agg);
2206   GstBuffer *buf;
2207   GstMemory *mem;
2208   GstD3D11Memory *dmem;
2209   gboolean update_device = FALSE;
2210
2211   buf = gst_video_aggregator_pad_get_current_buffer (vpad);
2212   if (!buf)
2213     return TRUE;
2214
2215   /* Ignore gap buffer */
2216   if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_GAP) ||
2217       gst_buffer_get_size (buf) == 0) {
2218     return TRUE;
2219   }
2220
2221   mem = gst_buffer_peek_memory (buf, 0);
2222   if (!gst_is_d3d11_memory (mem))
2223     return TRUE;
2224
2225   dmem = GST_D3D11_MEMORY_CAST (mem);
2226
2227   /* We can use existing device */
2228   if (dmem->device == self->device) {
2229     data->have_same_device = TRUE;
2230     return FALSE;
2231   }
2232
2233   if (self->adapter < 0) {
2234     update_device = TRUE;
2235   } else {
2236     guint adapter = 0;
2237
2238     g_object_get (dmem->device, "adapter", &adapter, nullptr);
2239     /* The same GPU as what user wanted, update */
2240     if (adapter == (guint) self->adapter)
2241       update_device = TRUE;
2242   }
2243
2244   if (!update_device)
2245     return TRUE;
2246
2247   data->other_device = dmem->device;
2248
2249   /* Keep iterate since there might be one buffer which holds the same device
2250    * as ours */
2251   return TRUE;
2252 }
2253
2254 static GstFlowReturn
2255 gst_d3d11_compositor_create_output_buffer (GstVideoAggregator * vagg,
2256     GstBuffer ** outbuffer)
2257 {
2258   GstD3D11Compositor *self = GST_D3D11_COMPOSITOR (vagg);
2259   DeviceCheckData data;
2260
2261   /* Check whether there is at least one sinkpad which holds d3d11 buffer
2262    * with compatible device, and if not, update our device */
2263   data.other_device = nullptr;
2264   data.have_same_device = FALSE;
2265
2266   gst_element_foreach_sink_pad (GST_ELEMENT_CAST (vagg),
2267       (GstElementForeachPadFunc) gst_d3d11_compositor_check_device_update,
2268       &data);
2269
2270   if (data.have_same_device || !data.other_device) {
2271     return
2272         GST_VIDEO_AGGREGATOR_CLASS (parent_class)->create_output_buffer (vagg,
2273         outbuffer);
2274   }
2275
2276   /* Clear all device dependent resources */
2277   gst_element_foreach_sink_pad (GST_ELEMENT_CAST (vagg),
2278       (GstElementForeachPadFunc) gst_d3d11_compositor_pad_clear_resource,
2279       nullptr);
2280
2281   gst_clear_buffer (&self->fallback_buf);
2282   g_clear_pointer (&self->checker_background, gst_d3d11_compositor_quad_free);
2283
2284   GST_INFO_OBJECT (self, "Updating device %" GST_PTR_FORMAT " -> %"
2285       GST_PTR_FORMAT, self->device, data.other_device);
2286   gst_object_unref (self->device);
2287   self->device = (GstD3D11Device *) gst_object_ref (data.other_device);
2288
2289   /* We cannot call gst_aggregator_negotiate() here, since GstVideoAggregator
2290    * is holding GST_VIDEO_AGGREGATOR_LOCK() already.
2291    * Mark reconfigure and do reconfigure later */
2292   gst_pad_mark_reconfigure (GST_AGGREGATOR_SRC_PAD (vagg));
2293
2294   return GST_AGGREGATOR_FLOW_NEED_DATA;
2295 }