d3d11converter: Fix alpha factor update
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / sys / d3d11 / gstd3d11compositorbin.cpp
1 /*
2  * GStreamer
3  * Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
4  * Copyright (C) 2020 Seungha Yang <seungha@centricular.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 /**
23  * SECTION:element-d3d11compositor
24  * @title: d3d11compositor
25  *
26  * A convenient bin which wraps #d3d11compositorelement for video composition
27  * with other helper elements to handle color conversion and memory transfer
28  * between Direct3D11 and system memory space.
29  *
30  * ## Example launch line
31  * ```
32  * gst-launch-1.0 d3d11compositor name=c ! d3d11videosink \
33  *     videotestsrc ! video/x-raw,width=320,height=240 ! c. \
34  *     videotestsrc pattern=ball ! video/x-raw,width=100,height=100 ! c.
35  * ```
36  *
37  * Since: 1.20
38  *
39  */
40
41 #ifdef HAVE_CONFIG_H
42 #include "config.h"
43 #endif
44
45 #include <gst/controller/gstproxycontrolbinding.h>
46 #include "gstd3d11compositorbin.h"
47 #include "gstd3d11compositor.h"
48 #include "gstd3d11pluginutils.h"
49
50 GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_compositor_debug);
51 #define GST_CAT_DEFAULT gst_d3d11_compositor_debug
52
53 /****************************
54  * GstD3D11CompositorBinPad *
55  ****************************/
56
57 enum
58 {
59   PROP_PAD_0,
60   /* GstAggregatorPad */
61   PROP_PAD_EMIT_SIGNALS,
62 };
63
64 /* GstAggregatorPad */
65 #define DEFAULT_PAD_EMIT_SIGNALS FALSE
66
67 enum
68 {
69   /* GstAggregatorPad */
70   SIGNAL_PAD_BUFFER_CONSUMED = 0,
71   SIGNAL_PAD_LAST,
72 };
73
74 static guint gst_d3d11_compositor_bin_pad_signals[SIGNAL_PAD_LAST] = { 0 };
75
76 /**
77  * GstD3D11CompositorBinPad:
78  *
79  * Since: 1.20
80  */
81 struct _GstD3D11CompositorBinPad
82 {
83   GstGhostPad parent;
84
85   /* Holds ref */
86   GstPad *target;
87   gulong sig_id;
88 };
89
90 static void gst_d3d11_compositor_bin_pad_dispose (GObject * object);
91 static void gst_d3d11_compositor_bin_pad_set_property (GObject * object,
92     guint prop_id, const GValue * value, GParamSpec * pspec);
93 static void gst_d3d11_compositor_bin_pad_get_property (GObject * object,
94     guint prop_id, GValue * value, GParamSpec * pspec);
95 static void
96 gst_d3d11_compositor_bin_pad_set_target_default (GstD3D11CompositorBinPad * pad,
97     GstPad * target);
98
99 G_DEFINE_TYPE (GstD3D11CompositorBinPad, gst_d3d11_compositor_bin_pad,
100     GST_TYPE_GHOST_PAD);
101
102 static void
103 gst_d3d11_compositor_bin_pad_class_init (GstD3D11CompositorBinPadClass * klass)
104 {
105   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
106
107   gobject_class->dispose = gst_d3d11_compositor_bin_pad_dispose;
108   gobject_class->set_property = gst_d3d11_compositor_bin_pad_set_property;
109   gobject_class->get_property = gst_d3d11_compositor_bin_pad_get_property;
110
111   /* GstAggregatorPad */
112   g_object_class_install_property (gobject_class, PROP_PAD_EMIT_SIGNALS,
113       g_param_spec_boolean ("emit-signals", "Emit signals",
114           "Send signals to signal data consumption",
115           DEFAULT_PAD_EMIT_SIGNALS,
116           (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
117
118   gst_d3d11_compositor_bin_pad_signals[SIGNAL_PAD_BUFFER_CONSUMED] =
119       g_signal_new ("buffer-consumed", G_TYPE_FROM_CLASS (klass),
120       G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_BUFFER);
121
122   klass->set_target =
123       GST_DEBUG_FUNCPTR (gst_d3d11_compositor_bin_pad_set_target_default);
124 }
125
126 static void
127 gst_d3d11_compositor_bin_pad_init (GstD3D11CompositorBinPad * self)
128 {
129 }
130
131 static void
132 gst_d3d11_compositor_bin_pad_dispose (GObject * object)
133 {
134   GstD3D11CompositorBinPad *self = GST_D3D11_COMPOSITOR_BIN_PAD (object);
135
136   gst_clear_object (&self->target);
137
138   G_OBJECT_CLASS (gst_d3d11_compositor_bin_pad_parent_class)->dispose (object);
139 }
140
141 static void
142 gst_d3d11_compositor_bin_pad_set_property (GObject * object,
143     guint prop_id, const GValue * value, GParamSpec * pspec)
144 {
145   GstD3D11CompositorBinPad *self = GST_D3D11_COMPOSITOR_BIN_PAD (object);
146
147   if (self->target)
148     g_object_set_property (G_OBJECT (self->target), pspec->name, value);
149 }
150
151 static void
152 gst_d3d11_compositor_bin_pad_get_property (GObject * object,
153     guint prop_id, GValue * value, GParamSpec * pspec)
154 {
155   GstD3D11CompositorBinPad *self = GST_D3D11_COMPOSITOR_BIN_PAD (object);
156
157   if (self->target)
158     g_object_get_property (G_OBJECT (self->target), pspec->name, value);
159 }
160
161 static void
162 gst_d3d11_compositor_bin_pad_on_buffer_consumed (GstAggregatorPad * pad,
163     GstBuffer * buffer, GstD3D11CompositorBinPad * self)
164 {
165   g_signal_emit (self,
166       gst_d3d11_compositor_bin_pad_signals[SIGNAL_PAD_BUFFER_CONSUMED],
167       0, buffer);
168 }
169
170 /**
171  * gst_d3d11_compositor_bin_pad_set_target:
172  * @self: a #GstD3D11CompositorBinPad
173  * @target: (transfer full): a #GstAggregatorPad
174  */
175 static void
176 gst_d3d11_compositor_bin_pad_set_target (GstD3D11CompositorBinPad * pad,
177     GstPad * target)
178 {
179   GstD3D11CompositorBinPadClass *klass =
180       GST_D3D11_COMPOSITOR_BIN_PAD_GET_CLASS (pad);
181
182   klass->set_target (pad, target);
183 }
184
185 static void
186 gst_d3d11_compositor_bin_pad_set_target_default (GstD3D11CompositorBinPad * pad,
187     GstPad * target)
188 {
189   pad->target = target;
190   pad->sig_id = g_signal_connect (target, "buffer-consumed",
191       G_CALLBACK (gst_d3d11_compositor_bin_pad_on_buffer_consumed), pad);
192 }
193
194 static void
195 gst_d3d11_compositor_bin_pad_unset_target (GstD3D11CompositorBinPad * self)
196 {
197   if (!self->target)
198     return;
199
200   if (self->sig_id)
201     g_signal_handler_disconnect (self->target, self->sig_id);
202   self->sig_id = 0;
203   gst_clear_object (&self->target);
204 }
205
206 /******************************
207  * GstD3D11CompositorBinInput *
208  ******************************/
209
210 enum
211 {
212   PROP_INPUT_0,
213   /* GstVideoAggregatorPad */
214   PROP_INPUT_ZORDER,
215   PROP_INPUT_REPEAT_AFTER_EOS,
216   PROP_INPUT_MAX_LAST_BUFFER_REPEAT,
217   /* GstD3D11CompositorPad */
218   PROP_INPUT_XPOS,
219   PROP_INPUT_YPOS,
220   PROP_INPUT_WIDTH,
221   PROP_INPUT_HEIGHT,
222   PROP_INPUT_ALPHA,
223   PROP_INPUT_BLEND_OP_RGB,
224   PROP_INPUT_BLEND_OP_ALPHA,
225   PROP_INPUT_BLEND_SRC_RGB,
226   PROP_INPUT_BLEND_SRC_ALPHA,
227   PROP_INPUT_BLEND_DEST_RGB,
228   PROP_INPUT_BLEND_DEST_ALPHA,
229   PROP_INPUT_BLEND_FACTOR_RED,
230   PROP_INPUT_BLEND_FACTOR_GREEN,
231   PROP_INPUT_BLEND_FACTOR_BLUE,
232   PROP_INPUT_BLEND_FACTOR_ALPHA,
233   PROP_INPUT_SIZING_POLICY,
234 };
235
236 /* GstVideoAggregatorPad */
237 #define DEFAULT_INPUT_ZORDER 0
238 #define DEFAULT_INPUT_REPEAT_AFTER_EOS FALSE
239 #define DEFAULT_INPUT_MAX_LAST_BUFFER_REPEAT GST_CLOCK_TIME_NONE
240 /* GstD3D11CompositorPad */
241 #define DEFAULT_INPUT_XPOS   0
242 #define DEFAULT_INPUT_YPOS   0
243 #define DEFAULT_INPUT_WIDTH  0
244 #define DEFAULT_INPUT_HEIGHT 0
245 #define DEFAULT_INPUT_ALPHA  1.0
246 #define DEFAULT_INPUT_BLEND_OP_RGB GST_D3D11_COMPOSITOR_BLEND_OP_ADD
247 #define DEFAULT_INPUT_BLEND_OP_ALPHA GST_D3D11_COMPOSITOR_BLEND_OP_ADD
248 #define DEFAULT_INPUT_BLEND_SRC_RGB GST_D3D11_COMPOSITOR_BLEND_SRC_ALPHA
249 #define DEFAULT_INPUT_BLEND_SRC_ALPHA GST_D3D11_COMPOSITOR_BLEND_ONE
250 #define DEFAULT_INPUT_BLEND_DEST_RGB GST_D3D11_COMPOSITOR_BLEND_INV_SRC_ALPHA
251 #define DEFAULT_INPUT_BLEND_DEST_ALPHA GST_D3D11_COMPOSITOR_BLEND_INV_SRC_ALPHA
252 #define DEFAULT_INPUT_SIZING_POLICY GST_D3D11_COMPOSITOR_SIZING_POLICY_NONE
253
254 /**
255  * GstD3D11CompositorBinInput:
256  *
257  * Since: 1.20
258  */
259 struct _GstD3D11CompositorBinInput
260 {
261   GstD3D11CompositorBinPad parent;
262 };
263
264 static void gst_d3d11_compositor_bin_input_set_property (GObject * object,
265     guint prop_id, const GValue * value, GParamSpec * pspec);
266 static void gst_d3d11_compositor_bin_input_get_property (GObject * object,
267     guint prop_id, GValue * value, GParamSpec * pspec);
268 static void
269 gst_d3d11_compositor_bin_input_set_target (GstD3D11CompositorBinPad * pad,
270     GstPad * target);
271
272 #define gst_d3d11_compositor_bin_input_parent_class input_parent_class
273 G_DEFINE_TYPE (GstD3D11CompositorBinInput, gst_d3d11_compositor_bin_input,
274     GST_TYPE_D3D11_COMPOSITOR_BIN_PAD);
275
276 static void
277 gst_d3d11_compositor_bin_input_class_init (GstD3D11CompositorBinInputClass *
278     klass)
279 {
280   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
281   GstD3D11CompositorBinPadClass *pad_class =
282       GST_D3D11_COMPOSITOR_BIN_PAD_CLASS (klass);
283
284   gobject_class->set_property = gst_d3d11_compositor_bin_input_set_property;
285   gobject_class->get_property = gst_d3d11_compositor_bin_input_get_property;
286
287   /* GstVideoAggregatorPad */
288   g_object_class_install_property (gobject_class, PROP_INPUT_ZORDER,
289       g_param_spec_uint ("zorder", "Z-Order", "Z Order of the picture",
290           0, G_MAXUINT, DEFAULT_INPUT_ZORDER,
291           (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE |
292               G_PARAM_STATIC_STRINGS)));
293
294   g_object_class_install_property (gobject_class, PROP_INPUT_REPEAT_AFTER_EOS,
295       g_param_spec_boolean ("repeat-after-eos", "Repeat After EOS",
296           "Repeat the " "last frame after EOS until all pads are EOS",
297           DEFAULT_INPUT_REPEAT_AFTER_EOS,
298           (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE |
299               G_PARAM_STATIC_STRINGS)));
300
301   g_object_class_install_property (gobject_class,
302       PROP_INPUT_MAX_LAST_BUFFER_REPEAT,
303       g_param_spec_uint64 ("max-last-buffer-repeat", "Max Last Buffer Repeat",
304           "Repeat last buffer for time (in ns, -1=until EOS), "
305           "behaviour on EOS is not affected", 0, G_MAXUINT64,
306           DEFAULT_INPUT_MAX_LAST_BUFFER_REPEAT,
307           (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
308               G_PARAM_STATIC_STRINGS)));
309
310   /* GstD3D11CompositorPad */
311   g_object_class_install_property (gobject_class, PROP_INPUT_XPOS,
312       g_param_spec_int ("xpos", "X Position", "X position of the picture",
313           G_MININT, G_MAXINT, DEFAULT_INPUT_XPOS,
314           (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE |
315               G_PARAM_STATIC_STRINGS)));
316
317   g_object_class_install_property (gobject_class, PROP_INPUT_YPOS,
318       g_param_spec_int ("ypos", "Y Position", "Y position of the picture",
319           G_MININT, G_MAXINT, DEFAULT_INPUT_YPOS,
320           (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE |
321               G_PARAM_STATIC_STRINGS)));
322
323   g_object_class_install_property (gobject_class, PROP_INPUT_WIDTH,
324       g_param_spec_int ("width", "Width", "Width of the picture",
325           G_MININT, G_MAXINT, DEFAULT_INPUT_WIDTH,
326           (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE |
327               G_PARAM_STATIC_STRINGS)));
328
329   g_object_class_install_property (gobject_class, PROP_INPUT_HEIGHT,
330       g_param_spec_int ("height", "Height", "Height of the picture",
331           G_MININT, G_MAXINT, DEFAULT_INPUT_HEIGHT,
332           (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE |
333               G_PARAM_STATIC_STRINGS)));
334
335   g_object_class_install_property (gobject_class, PROP_INPUT_ALPHA,
336       g_param_spec_double ("alpha", "Alpha", "Alpha of the picture", 0.0, 1.0,
337           DEFAULT_INPUT_ALPHA,
338           (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE |
339               G_PARAM_STATIC_STRINGS)));
340
341   g_object_class_install_property (gobject_class, PROP_INPUT_BLEND_OP_RGB,
342       g_param_spec_enum ("blend-op-rgb", "Blend Operation RGB",
343           "Blend equation for RGB", GST_TYPE_D3D11_COMPOSITOR_BLEND_OPERATION,
344           DEFAULT_INPUT_BLEND_OP_RGB,
345           (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE |
346               G_PARAM_STATIC_STRINGS)));
347
348   g_object_class_install_property (gobject_class, PROP_INPUT_BLEND_OP_ALPHA,
349       g_param_spec_enum ("blend-op-alpha", "Blend Operation Alpha",
350           "Blend equation for alpha", GST_TYPE_D3D11_COMPOSITOR_BLEND_OPERATION,
351           DEFAULT_INPUT_BLEND_OP_ALPHA,
352           (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE |
353               G_PARAM_STATIC_STRINGS)));
354
355   g_object_class_install_property (gobject_class,
356       PROP_INPUT_BLEND_SRC_RGB,
357       g_param_spec_enum ("blend-src-rgb", "Blend Source RGB",
358           "Blend factor for source RGB",
359           GST_TYPE_D3D11_COMPOSITOR_BLEND,
360           DEFAULT_INPUT_BLEND_SRC_RGB,
361           (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE |
362               G_PARAM_STATIC_STRINGS)));
363
364   g_object_class_install_property (gobject_class,
365       PROP_INPUT_BLEND_SRC_ALPHA,
366       g_param_spec_enum ("blend-src-alpha",
367           "Blend Source Alpha",
368           "Blend factor for source alpha, \"*-color\" values are not allowed",
369           GST_TYPE_D3D11_COMPOSITOR_BLEND,
370           DEFAULT_INPUT_BLEND_SRC_ALPHA,
371           (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE |
372               G_PARAM_STATIC_STRINGS)));
373
374   g_object_class_install_property (gobject_class,
375       PROP_INPUT_BLEND_DEST_RGB,
376       g_param_spec_enum ("blend-dest-rgb",
377           "Blend Destination RGB",
378           "Blend factor for destination RGB",
379           GST_TYPE_D3D11_COMPOSITOR_BLEND,
380           DEFAULT_INPUT_BLEND_DEST_RGB,
381           (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE |
382               G_PARAM_STATIC_STRINGS)));
383
384   g_object_class_install_property (gobject_class,
385       PROP_INPUT_BLEND_DEST_ALPHA,
386       g_param_spec_enum ("blend-dest-alpha",
387           "Blend Destination Alpha",
388           "Blend factor for destination alpha, "
389           "\"*-color\" values are not allowed",
390           GST_TYPE_D3D11_COMPOSITOR_BLEND,
391           DEFAULT_INPUT_BLEND_DEST_ALPHA,
392           (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE |
393               G_PARAM_STATIC_STRINGS)));
394
395   g_object_class_install_property (gobject_class, PROP_INPUT_BLEND_FACTOR_RED,
396       g_param_spec_float ("blend-factor-red", "Blend Factor Red",
397           "Blend factor for red component "
398           "when blend type is \"blend-factor\" or \"inv-blend-factor\"",
399           0.0, 1.0, 1.0,
400           (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE |
401               G_PARAM_STATIC_STRINGS)));
402
403   g_object_class_install_property (gobject_class, PROP_INPUT_BLEND_FACTOR_GREEN,
404       g_param_spec_float ("blend-factor-green", "Blend Factor Green",
405           "Blend factor for green component "
406           "when blend type is \"blend-factor\" or \"inv-blend-factor\"",
407           0.0, 1.0, 1.0,
408           (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE |
409               G_PARAM_STATIC_STRINGS)));
410
411   g_object_class_install_property (gobject_class, PROP_INPUT_BLEND_FACTOR_BLUE,
412       g_param_spec_float ("blend-factor-blue", "Blend Factor Blue",
413           "Blend factor for blue component "
414           "when blend type is \"blend-factor\" or \"inv-blend-factor\"",
415           0.0, 1.0, 1.0,
416           (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE |
417               G_PARAM_STATIC_STRINGS)));
418
419   g_object_class_install_property (gobject_class, PROP_INPUT_BLEND_FACTOR_ALPHA,
420       g_param_spec_float ("blend-factor-alpha", "Blend Factor Alpha",
421           "Blend factor for alpha component "
422           "when blend type is \"blend-factor\" or \"inv-blend-factor\"",
423           0.0, 1.0, 1.0,
424           (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE |
425               G_PARAM_STATIC_STRINGS)));
426
427   g_object_class_install_property (gobject_class, PROP_INPUT_SIZING_POLICY,
428       g_param_spec_enum ("sizing-policy", "Sizing policy",
429           "Sizing policy to use for image scaling",
430           GST_TYPE_D3D11_COMPOSITOR_SIZING_POLICY, DEFAULT_INPUT_SIZING_POLICY,
431           (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE |
432               G_PARAM_STATIC_STRINGS)));
433
434   pad_class->set_target =
435       GST_DEBUG_FUNCPTR (gst_d3d11_compositor_bin_input_set_target);
436 }
437
438 static void
439 gst_d3d11_compositor_bin_input_init (GstD3D11CompositorBinInput * self)
440 {
441 }
442
443 static void
444 gst_d3d11_compositor_bin_input_set_property (GObject * object,
445     guint prop_id, const GValue * value, GParamSpec * pspec)
446 {
447   GstD3D11CompositorBinPad *pad = GST_D3D11_COMPOSITOR_BIN_PAD (object);
448
449   if (pad->target)
450     g_object_set_property (G_OBJECT (pad->target), pspec->name, value);
451 }
452
453 static void
454 gst_d3d11_compositor_bin_input_get_property (GObject * object,
455     guint prop_id, GValue * value, GParamSpec * pspec)
456 {
457   GstD3D11CompositorBinPad *pad = GST_D3D11_COMPOSITOR_BIN_PAD (object);
458
459   if (pad->target)
460     g_object_get_property (G_OBJECT (pad->target), pspec->name, value);
461 }
462
463 static void
464 gst_d3d11_compositor_bin_input_set_target (GstD3D11CompositorBinPad * pad,
465     GstPad * target)
466 {
467   GST_D3D11_COMPOSITOR_BIN_PAD_CLASS (input_parent_class)->set_target (pad,
468       target);
469
470 #define ADD_BINDING(obj,ref,prop) \
471     gst_object_add_control_binding (GST_OBJECT (obj), \
472         gst_proxy_control_binding_new (GST_OBJECT (obj), prop, \
473             GST_OBJECT (ref), prop));
474   /* GstVideoAggregatorPad */
475   ADD_BINDING (target, pad, "zorder");
476   ADD_BINDING (target, pad, "repeat-after-eos");
477   /* GstD3D11CompositorPad */
478   ADD_BINDING (target, pad, "xpos");
479   ADD_BINDING (target, pad, "ypos");
480   ADD_BINDING (target, pad, "width");
481   ADD_BINDING (target, pad, "height");
482   ADD_BINDING (target, pad, "alpha");
483   ADD_BINDING (target, pad, "blend-op-rgb");
484   ADD_BINDING (target, pad, "blend-op-alpha");
485   ADD_BINDING (target, pad, "blend-src-rgb");
486   ADD_BINDING (target, pad, "blend-src-alpha");
487   ADD_BINDING (target, pad, "blend-dest-rgb");
488   ADD_BINDING (target, pad, "blend-dest-alpha");
489   ADD_BINDING (target, pad, "blend-factor-red");
490   ADD_BINDING (target, pad, "blend-factor-green");
491   ADD_BINDING (target, pad, "blend-factor-blue");
492   ADD_BINDING (target, pad, "blend-factor-alpha");
493   ADD_BINDING (target, pad, "sizing-policy");
494 #undef ADD_BINDING
495 }
496
497 /*************************
498  * GstD3D11CompositorBin *
499  *************************/
500
501 static GstStaticCaps sink_template_caps =
502     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
503     (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, GST_D3D11_SINK_FORMATS) ";"
504     GST_VIDEO_CAPS_MAKE (GST_D3D11_SINK_FORMATS));
505
506 static GstStaticCaps src_template_caps =
507     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
508     (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, GST_D3D11_SRC_FORMATS) ";"
509     GST_VIDEO_CAPS_MAKE (GST_D3D11_SRC_FORMATS));
510
511 enum
512 {
513   PROP_0,
514   PROP_MIXER,
515   /* GstAggregator */
516   PROP_LATENCY,
517   PROP_MIN_UPSTREAM_LATENCY,
518   PROP_START_TIME_SELECTION,
519   PROP_START_TIME,
520   PROP_EMIT_SIGNALS,
521   /* GstD3D11Compositor */
522   PROP_ADAPTER,
523   PROP_BACKGROUND,
524   PROP_LAST
525 };
526
527 /* GstAggregator */
528 #define DEFAULT_LATENCY              0
529 #define DEFAULT_MIN_UPSTREAM_LATENCY 0
530 #define DEFAULT_START_TIME_SELECTION GST_AGGREGATOR_START_TIME_SELECTION_ZERO
531 #define DEFAULT_START_TIME           (-1)
532 #define DEFAULT_EMIT_SIGNALS         FALSE
533
534 /* GstD3D11Compositor */
535 #define DEFAULT_ADAPTER -1
536 #define DEFAULT_BACKGROUND GST_D3D11_COMPOSITOR_BACKGROUND_CHECKER
537
538 typedef struct _GstD3D11CompositorBinChain
539 {
540   /* without ref */
541   GstD3D11CompositorBin *self;
542   GstD3D11CompositorBinPad *ghost_pad;
543   GstElement *upload;
544   GstElement *convert;
545
546   gulong probe_id;
547 } GstD3D11CompositorBinChain;
548
549 struct _GstD3D11CompositorBin
550 {
551   GstBin parent;
552
553   GstElement *compositor;
554
555   GList *input_chains;
556   gboolean running;
557
558   gint adapter;
559 };
560
561 static void gst_d3d11_compositor_bin_child_proxy_init (gpointer g_iface,
562     gpointer iface_data);
563 static void gst_d3d11_compositor_bin_dispose (GObject * object);
564 static void gst_d3d11_compositor_bin_set_property (GObject * object,
565     guint prop_id, const GValue * value, GParamSpec * pspec);
566 static void gst_d3d11_compositor_bin_get_property (GObject * object,
567     guint prop_id, GValue * value, GParamSpec * pspec);
568
569 static GstStateChangeReturn
570 gst_d3d11_compositor_bin_change_state (GstElement * element,
571     GstStateChange transition);
572 static GstPad *gst_d3d11_compositor_bin_request_new_pad (GstElement * element,
573     GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
574 static void gst_d3d11_compositor_bin_release_pad (GstElement * element,
575     GstPad * pad);
576
577 #define gst_d3d11_compositor_bin_parent_class parent_class
578 G_DEFINE_TYPE_WITH_CODE (GstD3D11CompositorBin, gst_d3d11_compositor_bin,
579     GST_TYPE_BIN, G_IMPLEMENT_INTERFACE (GST_TYPE_CHILD_PROXY,
580         gst_d3d11_compositor_bin_child_proxy_init));
581
582 static void
583 gst_d3d11_compositor_bin_class_init (GstD3D11CompositorBinClass * klass)
584 {
585   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
586   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
587   GstCaps *caps;
588
589   gobject_class->dispose = gst_d3d11_compositor_bin_dispose;
590   gobject_class->set_property = gst_d3d11_compositor_bin_set_property;
591   gobject_class->get_property = gst_d3d11_compositor_bin_get_property;
592
593   element_class->change_state =
594       GST_DEBUG_FUNCPTR (gst_d3d11_compositor_bin_change_state);
595   element_class->request_new_pad =
596       GST_DEBUG_FUNCPTR (gst_d3d11_compositor_bin_request_new_pad);
597   element_class->release_pad =
598       GST_DEBUG_FUNCPTR (gst_d3d11_compositor_bin_release_pad);
599
600   gst_element_class_set_static_metadata (element_class,
601       "Direct3D11 Compositor Bin",
602       "Filter/Editor/Video/Compositor",
603       "A Direct3D11 compositor bin", "Seungha Yang <seungha@centricular.com>");
604
605   caps = gst_d3d11_get_updated_template_caps (&sink_template_caps);
606   gst_element_class_add_pad_template (element_class,
607       gst_pad_template_new_with_gtype ("sink_%u", GST_PAD_SINK, GST_PAD_REQUEST,
608           caps, GST_TYPE_D3D11_COMPOSITOR_BIN_INPUT));
609   gst_caps_unref (caps);
610
611   caps = gst_d3d11_get_updated_template_caps (&src_template_caps);
612   gst_element_class_add_pad_template (element_class,
613       gst_pad_template_new_with_gtype ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
614           caps, GST_TYPE_D3D11_COMPOSITOR_BIN_PAD));
615   gst_caps_unref (caps);
616
617   g_object_class_install_property (gobject_class, PROP_MIXER,
618       g_param_spec_object ("mixer", "D3D11 mixer element",
619           "The d3d11 mixer chain to use",
620           GST_TYPE_ELEMENT,
621           (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
622
623   /*GstAggregator */
624   g_object_class_install_property (gobject_class, PROP_LATENCY,
625       g_param_spec_uint64 ("latency", "Buffer latency",
626           "Additional latency in live mode to allow upstream "
627           "to take longer to produce buffers for the current "
628           "position (in nanoseconds)", 0, G_MAXUINT64,
629           DEFAULT_LATENCY,
630           (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
631
632   g_object_class_install_property (gobject_class, PROP_MIN_UPSTREAM_LATENCY,
633       g_param_spec_uint64 ("min-upstream-latency", "Buffer latency",
634           "When sources with a higher latency are expected to be plugged "
635           "in dynamically after the aggregator has started playing, "
636           "this allows overriding the minimum latency reported by the "
637           "initial source(s). This is only taken into account when larger "
638           "than the actually reported minimum latency. (nanoseconds)",
639           0, G_MAXUINT64,
640           DEFAULT_LATENCY,
641           (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
642
643   g_object_class_install_property (gobject_class, PROP_START_TIME_SELECTION,
644       g_param_spec_enum ("start-time-selection", "Start Time Selection",
645           "Decides which start time is output",
646           gst_aggregator_start_time_selection_get_type (),
647           DEFAULT_START_TIME_SELECTION,
648           (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
649
650   g_object_class_install_property (gobject_class, PROP_START_TIME,
651       g_param_spec_uint64 ("start-time", "Start Time",
652           "Start time to use if start-time-selection=set", 0,
653           G_MAXUINT64,
654           DEFAULT_START_TIME,
655           (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
656
657   g_object_class_install_property (gobject_class, PROP_EMIT_SIGNALS,
658       g_param_spec_boolean ("emit-signals", "Emit signals",
659           "Send signals", DEFAULT_EMIT_SIGNALS,
660           (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
661
662   /* GstD3D11Compositor */
663   g_object_class_install_property (gobject_class, PROP_ADAPTER,
664       g_param_spec_int ("adapter", "Adapter",
665           "Adapter index for creating device (-1 for default)",
666           -1, G_MAXINT32, DEFAULT_ADAPTER,
667           (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY |
668               G_PARAM_STATIC_STRINGS)));
669
670   g_object_class_install_property (gobject_class, PROP_BACKGROUND,
671       g_param_spec_enum ("background", "Background", "Background type",
672           GST_TYPE_D3D11_COMPOSITOR_BACKGROUND,
673           DEFAULT_BACKGROUND,
674           (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
675
676   gst_type_mark_as_plugin_api (GST_TYPE_D3D11_COMPOSITOR_BIN_PAD,
677       (GstPluginAPIFlags) 0);
678   gst_type_mark_as_plugin_api (GST_TYPE_D3D11_COMPOSITOR_BIN_INPUT,
679       (GstPluginAPIFlags) 0);
680 }
681
682 static void
683 gst_d3d11_compositor_bin_init (GstD3D11CompositorBin * self)
684 {
685   GstPad *pad;
686   GstPad *gpad;
687   GstElement *out_convert, *download;
688
689   self->compositor = gst_element_factory_make ("d3d11compositorelement", NULL);
690   out_convert = gst_element_factory_make ("d3d11colorconvert", NULL);
691   download = gst_element_factory_make ("d3d11download", NULL);
692
693   gst_bin_add_many (GST_BIN (self),
694       self->compositor, out_convert, download, NULL);
695   gst_element_link_many (self->compositor, out_convert, download, NULL);
696
697   gpad = (GstPad *) g_object_new (GST_TYPE_D3D11_COMPOSITOR_BIN_PAD,
698       "name", "src", "direction", GST_PAD_SRC, NULL);
699   pad = gst_element_get_static_pad (self->compositor, "src");
700   /* GstD3D11CompositorBinPad will hold reference of this compositor srcpad */
701   gst_d3d11_compositor_bin_pad_set_target ((GstD3D11CompositorBinPad *) gpad,
702       pad);
703
704   pad = gst_element_get_static_pad (download, "src");
705   gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (gpad), pad);
706   gst_object_unref (pad);
707
708   gst_element_add_pad (GST_ELEMENT_CAST (self), gpad);
709 }
710
711 static void
712 gst_d3d11_compositor_bin_dispose (GObject * object)
713 {
714   GstD3D11CompositorBin *self = GST_D3D11_COMPOSITOR_BIN (object);
715   GList *iter;
716
717   for (iter = self->input_chains; iter; iter = g_list_next (iter)) {
718     GstD3D11CompositorBinChain *chain =
719         (GstD3D11CompositorBinChain *) iter->data;
720
721     if (self->compositor && chain->ghost_pad && chain->ghost_pad->target) {
722       gst_element_release_request_pad (GST_ELEMENT_CAST (self->compositor),
723           chain->ghost_pad->target);
724       gst_d3d11_compositor_bin_pad_unset_target (chain->ghost_pad);
725     }
726   }
727
728   if (self->input_chains)
729     g_list_free_full (self->input_chains, (GDestroyNotify) g_free);
730   self->input_chains = NULL;
731
732   G_OBJECT_CLASS (parent_class)->dispose (object);
733 }
734
735 static void
736 gst_d3d11_compositor_bin_set_property (GObject * object,
737     guint prop_id, const GValue * value, GParamSpec * pspec)
738 {
739   GstD3D11CompositorBin *self = GST_D3D11_COMPOSITOR_BIN (object);
740
741   switch (prop_id) {
742     case PROP_ADAPTER:
743       self->adapter = g_value_get_int (value);
744       /* fallthrough */
745     default:
746       g_object_set_property (G_OBJECT (self->compositor), pspec->name, value);
747       break;
748   }
749 }
750
751 static void
752 gst_d3d11_compositor_bin_get_property (GObject * object,
753     guint prop_id, GValue * value, GParamSpec * pspec)
754 {
755   GstD3D11CompositorBin *self = GST_D3D11_COMPOSITOR_BIN (object);
756
757   switch (prop_id) {
758     case PROP_MIXER:
759       g_value_set_object (value, self->compositor);
760       break;
761     case PROP_ADAPTER:
762       g_value_set_int (value, self->adapter);
763       break;
764     default:
765       g_object_get_property (G_OBJECT (self->compositor), pspec->name, value);
766       break;
767   }
768 }
769
770 static GstStateChangeReturn
771 gst_d3d11_compositor_bin_change_state (GstElement * element,
772     GstStateChange transition)
773 {
774   GstD3D11CompositorBin *self = GST_D3D11_COMPOSITOR_BIN (element);
775   GstStateChangeReturn ret;
776
777   switch (transition) {
778     case GST_STATE_CHANGE_NULL_TO_READY:
779       GST_OBJECT_LOCK (element);
780       self->running = TRUE;
781       GST_OBJECT_UNLOCK (element);
782       break;
783     default:
784       break;
785   }
786
787   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
788   if (ret == GST_STATE_CHANGE_FAILURE)
789     return ret;
790
791   switch (transition) {
792     case GST_STATE_CHANGE_READY_TO_NULL:
793       GST_OBJECT_LOCK (self);
794       self->running = FALSE;
795       GST_OBJECT_UNLOCK (self);
796     default:
797       break;
798   }
799
800   return ret;
801 }
802
803 static GstD3D11CompositorBinChain *
804 gst_d3d11_compositor_bin_input_chain_new (GstD3D11CompositorBin * self,
805     GstPad * compositor_pad)
806 {
807   GstD3D11CompositorBinChain *chain;
808   GstPad *pad;
809
810   chain = g_new0 (GstD3D11CompositorBinChain, 1);
811
812   chain->self = self;
813
814   chain->upload = gst_element_factory_make ("d3d11upload", NULL);
815   chain->convert = gst_element_factory_make ("d3d11colorconvert", NULL);
816
817   /* 1. Create child elements and like */
818   gst_bin_add_many (GST_BIN (self), chain->upload, chain->convert, NULL);
819
820   gst_element_link (chain->upload, chain->convert);
821   pad = gst_element_get_static_pad (chain->convert, "src");
822   gst_pad_link (pad, compositor_pad);
823   gst_object_unref (pad);
824
825   chain->ghost_pad = (GstD3D11CompositorBinPad *)
826       g_object_new (GST_TYPE_D3D11_COMPOSITOR_BIN_INPUT, "name",
827       GST_OBJECT_NAME (compositor_pad), "direction", GST_PAD_SINK, NULL);
828
829   /* transfer ownership of compositor pad */
830   gst_d3d11_compositor_bin_pad_set_target (chain->ghost_pad, compositor_pad);
831
832   pad = gst_element_get_static_pad (chain->upload, "sink");
833   gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (chain->ghost_pad), pad);
834   gst_object_unref (pad);
835
836   GST_OBJECT_LOCK (self);
837   if (self->running)
838     gst_pad_set_active (GST_PAD (chain->ghost_pad), TRUE);
839   GST_OBJECT_UNLOCK (self);
840
841   gst_element_add_pad (GST_ELEMENT_CAST (self),
842       GST_PAD_CAST (chain->ghost_pad));
843
844   gst_element_sync_state_with_parent (chain->upload);
845   gst_element_sync_state_with_parent (chain->convert);
846
847   return chain;
848 }
849
850 static void
851 gst_d3d11_compositor_bin_input_chain_free (GstD3D11CompositorBinChain * chain)
852 {
853   if (!chain)
854     return;
855
856   if (chain->ghost_pad && chain->probe_id) {
857     gst_pad_remove_probe (GST_PAD_CAST (chain->ghost_pad), chain->probe_id);
858     chain->probe_id = 0;
859   }
860
861   if (chain->upload) {
862     gst_element_set_state (chain->upload, GST_STATE_NULL);
863     gst_bin_remove (GST_BIN_CAST (chain->self), chain->upload);
864   }
865
866   if (chain->convert) {
867     gst_element_set_state (chain->convert, GST_STATE_NULL);
868     gst_bin_remove (GST_BIN_CAST (chain->self), chain->convert);
869   }
870
871   if (chain->ghost_pad && chain->ghost_pad->target) {
872     gst_element_release_request_pad (chain->self->compositor,
873         chain->ghost_pad->target);
874     gst_d3d11_compositor_bin_pad_unset_target (chain->ghost_pad);
875   }
876
877   g_free (chain);
878 }
879
880 static GstPad *
881 gst_d3d11_compositor_bin_request_new_pad (GstElement * element,
882     GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
883 {
884   GstD3D11CompositorBin *self = GST_D3D11_COMPOSITOR_BIN (element);
885   GstElementClass *compositor_class = GST_ELEMENT_GET_CLASS (self->compositor);
886   GstPad *compositor_pad;
887   GstD3D11CompositorBinChain *chain;
888   GstPadTemplate *compositor_templ = NULL;
889   GList *templ_list;
890   GList *iter;
891
892   templ_list = gst_element_class_get_pad_template_list (compositor_class);
893   for (iter = templ_list; iter; iter = g_list_next (iter)) {
894     GstPadTemplate *t = (GstPadTemplate *) iter->data;
895     if (GST_PAD_TEMPLATE_DIRECTION (t) != GST_PAD_SINK ||
896         GST_PAD_TEMPLATE_PRESENCE (t) != GST_PAD_REQUEST)
897       continue;
898
899     compositor_templ = t;
900     break;
901   }
902
903   g_assert (compositor_templ);
904
905   compositor_pad =
906       gst_element_request_pad (self->compositor, compositor_templ, name, caps);
907   if (!compositor_pad) {
908     GST_WARNING_OBJECT (self, "Failed to request pad");
909     return NULL;
910   }
911
912   chain = gst_d3d11_compositor_bin_input_chain_new (self, compositor_pad);
913   g_assert (chain);
914
915   GST_OBJECT_LOCK (self);
916   self->input_chains = g_list_append (self->input_chains, chain);
917   GST_OBJECT_UNLOCK (self);
918
919   gst_child_proxy_child_added (GST_CHILD_PROXY (self),
920       G_OBJECT (chain->ghost_pad), GST_OBJECT_NAME (chain->ghost_pad));
921
922   GST_DEBUG_OBJECT (element, "Created new pad %s:%s",
923       GST_DEBUG_PAD_NAME (chain->ghost_pad));
924
925   return GST_PAD_CAST (chain->ghost_pad);
926 }
927
928 static void
929 gst_d3d11_compositor_bin_release_pad (GstElement * element, GstPad * pad)
930 {
931   GstD3D11CompositorBin *self = GST_D3D11_COMPOSITOR_BIN (element);
932   GList *iter;
933   gboolean found = FALSE;
934
935   GST_DEBUG_OBJECT (self, "Releasing pad %s:%s", GST_DEBUG_PAD_NAME (pad));
936
937   GST_OBJECT_LOCK (self);
938   for (iter = self->input_chains; iter; iter = g_list_next (iter)) {
939     GstD3D11CompositorBinChain *chain =
940         (GstD3D11CompositorBinChain *) iter->data;
941
942     if (pad == GST_PAD_CAST (chain->ghost_pad)) {
943       self->input_chains = g_list_delete_link (self->input_chains, iter);
944       GST_OBJECT_UNLOCK (self);
945
946       gst_d3d11_compositor_bin_input_chain_free (chain);
947       found = TRUE;
948       break;
949     }
950   }
951
952   if (!found) {
953     GST_OBJECT_UNLOCK (self);
954     GST_WARNING_OBJECT (self, "Unknown pad to release %s:%s",
955         GST_DEBUG_PAD_NAME (pad));
956   }
957
958   gst_element_remove_pad (element, pad);
959 }
960
961 static GObject *
962 gst_d3d11_compositor_bin_child_proxy_get_child_by_index (GstChildProxy * proxy,
963     guint index)
964 {
965   GstD3D11CompositorBin *self = GST_D3D11_COMPOSITOR_BIN (proxy);
966   GstBin *bin = GST_BIN_CAST (proxy);
967   GObject *res = NULL;
968
969   GST_OBJECT_LOCK (self);
970   /* XXX: not exactly thread safe with ordering */
971   if (index < (guint) bin->numchildren) {
972     if ((res = (GObject *) g_list_nth_data (bin->children, index)))
973       gst_object_ref (res);
974   } else {
975     GstD3D11CompositorBinChain *chain;
976     if ((chain =
977             (GstD3D11CompositorBinChain *) g_list_nth_data (self->input_chains,
978                 index - bin->numchildren))) {
979       res = (GObject *) gst_object_ref (chain->ghost_pad);
980     }
981   }
982   GST_OBJECT_UNLOCK (self);
983
984   return res;
985 }
986
987 static guint
988 gst_d3d11_compositor_bin_child_proxy_get_children_count (GstChildProxy * proxy)
989 {
990   GstD3D11CompositorBin *self = GST_D3D11_COMPOSITOR_BIN (proxy);
991   guint count = 0;
992
993   GST_OBJECT_LOCK (self);
994   count = GST_BIN_CAST (self)->numchildren + g_list_length (self->input_chains);
995   GST_OBJECT_UNLOCK (self);
996   GST_INFO_OBJECT (self, "Children Count: %d", count);
997
998   return count;
999 }
1000
1001 static void
1002 gst_d3d11_compositor_bin_child_proxy_init (gpointer g_iface,
1003     gpointer iface_data)
1004 {
1005   GstChildProxyInterface *iface = (GstChildProxyInterface *) g_iface;
1006
1007   iface->get_child_by_index =
1008       gst_d3d11_compositor_bin_child_proxy_get_child_by_index;
1009   iface->get_children_count =
1010       gst_d3d11_compositor_bin_child_proxy_get_children_count;
1011 }