plugins: uddate gst_type_mark_as_plugin_api() calls
[platform/upstream/gstreamer.git] / ext / gl / gstglvideomixer.c
1 /*
2  * GStreamer
3  * Copyright (C) 2009 Julien Isorce <julien.isorce@gmail.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 /**
22  * SECTION:element-glvideomixer
23  * @title: glvideomixer
24  *
25  * Composites a number of streams into a single output scene using OpenGL in
26  * a similar fashion to compositor and videomixer. See the compositor plugin
27  * for documentation about the #GstGLVideoMixerPad properties.
28  *
29  * ## Examples
30  * |[
31  * gst-launch-1.0  glvideomixer name=m ! glimagesink \
32  *     videotestsrc ! video/x-raw, format=YUY2 ! glupload ! glcolorconvert ! m. \
33  *     videotestsrc pattern=12 ! video/x-raw, format=I420, framerate=5/1, width=100, height=200 ! queue ! \
34  *     glupload ! glcolorconvert ! m. \
35  *     videotestsrc ! glupload ! gleffects effect=2 ! queue ! m.  \
36  *     videotestsrc ! glupload ! glfiltercube ! queue ! m. \
37  *     videotestsrc ! glupload ! gleffects effect=6 ! queue ! m.
38  * ]|
39  *
40  */
41
42 #ifdef HAVE_CONFIG_H
43 #include "config.h"
44 #endif
45
46 #include <string.h>
47 #include <gst/controller/gstproxycontrolbinding.h>
48 #include <gst/gl/gstglfuncs.h>
49 #include <gst/video/gstvideoaffinetransformationmeta.h>
50
51 #include "gstglvideomixer.h"
52
53 #include "gstglmixerbin.h"
54 #include "gstglutils.h"
55
56 #define GST_CAT_DEFAULT gst_gl_video_mixer_debug
57 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
58
59 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink_%u",
60     GST_PAD_SINK,
61     GST_PAD_REQUEST,
62     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
63         (GST_CAPS_FEATURE_MEMORY_GL_MEMORY,
64             "RGBA"))
65     );
66
67 #define GST_TYPE_GL_VIDEO_MIXER_BACKGROUND (gst_gl_video_mixer_background_get_type())
68 static GType
69 gst_gl_video_mixer_background_get_type (void)
70 {
71   static GType mixer_background_type = 0;
72
73   static const GEnumValue mixer_background[] = {
74     {GST_GL_VIDEO_MIXER_BACKGROUND_CHECKER, "Checker pattern", "checker"},
75     {GST_GL_VIDEO_MIXER_BACKGROUND_BLACK, "Black", "black"},
76     {GST_GL_VIDEO_MIXER_BACKGROUND_WHITE, "White", "white"},
77     {GST_GL_VIDEO_MIXER_BACKGROUND_TRANSPARENT,
78         "Transparent Background to enable further compositing", "transparent"},
79     {0, NULL, NULL},
80   };
81
82   if (!mixer_background_type) {
83     mixer_background_type =
84         g_enum_register_static ("GstGLVideoMixerBackground", mixer_background);
85   }
86   return mixer_background_type;
87 }
88
89 #define GST_TYPE_GL_VIDEO_MIXER_BLEND_EQUATION (gst_gl_video_mixer_blend_equation_get_type())
90 static GType
91 gst_gl_video_mixer_blend_equation_get_type (void)
92 {
93   static GType mixer_blend_equation_type = 0;
94
95   static const GEnumValue mixer_blend_equations[] = {
96     {GST_GL_VIDEO_MIXER_BLEND_EQUATION_ADD, "Add", "add"},
97     {GST_GL_VIDEO_MIXER_BLEND_EQUATION_SUBTRACT, "Subtract", "subtract"},
98     {GST_GL_VIDEO_MIXER_BLEND_EQUATION_REVERSE_SUBTRACT, "Reverse Subtract",
99         "reverse-subtract"},
100     {0, NULL, NULL},
101   };
102
103   if (!mixer_blend_equation_type) {
104     mixer_blend_equation_type =
105         g_enum_register_static ("GstGLVideoMixerBlendEquation",
106         mixer_blend_equations);
107   }
108   return mixer_blend_equation_type;
109 }
110
111 #define GST_TYPE_GL_VIDEO_MIXER_BLEND_FUNCTION (gst_gl_video_mixer_blend_function_get_type())
112 static GType
113 gst_gl_video_mixer_blend_function_get_type (void)
114 {
115   static GType mixer_blend_function_type = 0;
116
117   static const GEnumValue mixer_blend_funcs[] = {
118     {GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ZERO, "Zero", "zero"},
119     {GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE, "One", "one"},
120     {GST_GL_VIDEO_MIXER_BLEND_FUNCTION_SRC_COLOR, "Source Color", "src-color"},
121     {GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_SRC_COLOR,
122         "One Minus Source Color", "one-minus-src-color"},
123     {GST_GL_VIDEO_MIXER_BLEND_FUNCTION_DST_COLOR, "Destination Color",
124         "dst-color"},
125     {GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_DST_COLOR,
126         "One Minus Destination Color", "one-minus-dst-color"},
127     {GST_GL_VIDEO_MIXER_BLEND_FUNCTION_SRC_ALPHA, "Source Alpha", "src-alpha"},
128     {GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_SRC_ALPHA,
129         "One Minus Source Alpha", "one-minus-src-alpha"},
130     {GST_GL_VIDEO_MIXER_BLEND_FUNCTION_DST_ALPHA, "Destination Alpha",
131         "dst-alpha"},
132     {GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_DST_ALPHA,
133         "One Minus Destination Alpha", "one-minus-dst-alpha"},
134     {GST_GL_VIDEO_MIXER_BLEND_FUNCTION_CONSTANT_COLOR, "Constant Color",
135         "constant-color"},
136     {GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_CONSTANT_COLOR,
137         "One Minus Constant Color", "one-minus-contant-color"},
138     {GST_GL_VIDEO_MIXER_BLEND_FUNCTION_CONSTANT_ALPHA, "Constant Alpha",
139         "constant-alpha"},
140     {GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_CONSTANT_ALPHA,
141         "One Minus Constant Alpha", "one-minus-contant-alpha"},
142     {GST_GL_VIDEO_MIXER_BLEND_FUNCTION_SRC_ALPHA_SATURATE,
143         "Source Alpha Saturate", "src-alpha-saturate"},
144     {0, NULL, NULL},
145   };
146
147   if (!mixer_blend_function_type) {
148     mixer_blend_function_type =
149         g_enum_register_static ("GstGLVideoMixerBlendFunction",
150         mixer_blend_funcs);
151   }
152   return mixer_blend_function_type;
153 }
154
155 #define DEFAULT_PAD_XPOS   0
156 #define DEFAULT_PAD_YPOS   0
157 #define DEFAULT_PAD_WIDTH  0
158 #define DEFAULT_PAD_HEIGHT 0
159 #define DEFAULT_PAD_ALPHA  1.0
160 #define DEFAULT_PAD_ZORDER 0
161 #define DEFAULT_PAD_REPEAT_AFTER_EOS FALSE
162 #define DEFAULT_PAD_BLEND_EQUATION_RGB GST_GL_VIDEO_MIXER_BLEND_EQUATION_ADD
163 #define DEFAULT_PAD_BLEND_EQUATION_ALPHA GST_GL_VIDEO_MIXER_BLEND_EQUATION_ADD
164 #define DEFAULT_PAD_BLEND_FUNCTION_SRC_RGB GST_GL_VIDEO_MIXER_BLEND_FUNCTION_SRC_ALPHA
165 #define DEFAULT_PAD_BLEND_FUNCTION_SRC_ALPHA GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE
166 #define DEFAULT_PAD_BLEND_FUNCTION_DST_RGB GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_SRC_ALPHA
167 #define DEFAULT_PAD_BLEND_FUNCTION_DST_ALPHA GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_SRC_ALPHA
168
169 enum
170 {
171   PROP_INPUT_0,
172   PROP_INPUT_XPOS,
173   PROP_INPUT_YPOS,
174   PROP_INPUT_WIDTH,
175   PROP_INPUT_HEIGHT,
176   PROP_INPUT_ALPHA,
177   PROP_INPUT_BLEND_EQUATION_RGB,
178   PROP_INPUT_BLEND_EQUATION_ALPHA,
179   PROP_INPUT_BLEND_FUNCTION_SRC_RGB,
180   PROP_INPUT_BLEND_FUNCTION_SRC_ALPHA,
181   PROP_INPUT_BLEND_FUNCTION_DST_RGB,
182   PROP_INPUT_BLEND_FUNCTION_DST_ALPHA,
183   PROP_INPUT_BLEND_FUNCTION_CONSTANT_COLOR_RED,
184   PROP_INPUT_BLEND_FUNCTION_CONSTANT_COLOR_GREEN,
185   PROP_INPUT_BLEND_FUNCTION_CONSTANT_COLOR_BLUE,
186   PROP_INPUT_BLEND_FUNCTION_CONSTANT_COLOR_ALPHA,
187   PROP_INPUT_ZORDER,
188   PROP_INPUT_REPEAT_AFTER_EOS,
189 };
190
191 static void gst_gl_video_mixer_input_get_property (GObject * object,
192     guint prop_id, GValue * value, GParamSpec * pspec);
193 static void gst_gl_video_mixer_input_set_property (GObject * object,
194     guint prop_id, const GValue * value, GParamSpec * pspec);
195
196 typedef struct _GstGLVideoMixerInput GstGLVideoMixerInput;
197 typedef GstGhostPadClass GstGLVideoMixerInputClass;
198
199 struct _GstGLVideoMixerInput
200 {
201   GstGhostPad parent;
202
203   GstSegment segment;
204
205   GstPad *mixer_pad;
206 };
207
208 GType gst_gl_video_mixer_input_get_type (void);
209 G_DEFINE_TYPE (GstGLVideoMixerInput, gst_gl_video_mixer_input,
210     GST_TYPE_GHOST_PAD);
211
212 static void
213 gst_gl_video_mixer_input_init (GstGLVideoMixerInput * self)
214 {
215 }
216
217 static void
218 gst_gl_video_mixer_input_class_init (GstGLVideoMixerInputClass * klass)
219 {
220   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
221
222   gobject_class->set_property = gst_gl_video_mixer_input_set_property;
223   gobject_class->get_property = gst_gl_video_mixer_input_get_property;
224
225   g_object_class_install_property (gobject_class, PROP_INPUT_ZORDER,
226       g_param_spec_uint ("zorder", "Z-Order", "Z Order of the picture",
227           0, 10000, DEFAULT_PAD_ZORDER,
228           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
229   g_object_class_install_property (gobject_class, PROP_INPUT_REPEAT_AFTER_EOS,
230       g_param_spec_boolean ("repeat-after-eos", "Repeat After EOS",
231           "Aggregate the last "
232           "frame on pads that are EOS till they are released",
233           DEFAULT_PAD_REPEAT_AFTER_EOS,
234           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
235   g_object_class_install_property (gobject_class, PROP_INPUT_XPOS,
236       g_param_spec_int ("xpos", "X Position", "X Position of the picture",
237           G_MININT, G_MAXINT, DEFAULT_PAD_XPOS,
238           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
239   g_object_class_install_property (gobject_class, PROP_INPUT_YPOS,
240       g_param_spec_int ("ypos", "Y Position", "Y Position of the picture",
241           G_MININT, G_MAXINT, DEFAULT_PAD_YPOS,
242           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
243   g_object_class_install_property (gobject_class, PROP_INPUT_WIDTH,
244       g_param_spec_int ("width", "Width", "Width of the picture", G_MININT,
245           G_MAXINT, DEFAULT_PAD_WIDTH,
246           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
247   g_object_class_install_property (gobject_class, PROP_INPUT_HEIGHT,
248       g_param_spec_int ("height", "Height", "Height of the picture", G_MININT,
249           G_MAXINT, DEFAULT_PAD_HEIGHT,
250           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
251   g_object_class_install_property (gobject_class, PROP_INPUT_ALPHA,
252       g_param_spec_double ("alpha", "Alpha", "Alpha of the picture", 0.0, 1.0,
253           DEFAULT_PAD_ALPHA,
254           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
255   g_object_class_install_property (gobject_class, PROP_INPUT_BLEND_EQUATION_RGB,
256       g_param_spec_enum ("blend-equation-rgb", "Blend Equation RGB",
257           "Blend Equation for RGB", GST_TYPE_GL_VIDEO_MIXER_BLEND_EQUATION,
258           DEFAULT_PAD_BLEND_EQUATION_RGB,
259           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
260   g_object_class_install_property (gobject_class,
261       PROP_INPUT_BLEND_EQUATION_ALPHA,
262       g_param_spec_enum ("blend-equation-alpha", "Blend Equation Alpha",
263           "Blend Equation for Alpha", GST_TYPE_GL_VIDEO_MIXER_BLEND_EQUATION,
264           DEFAULT_PAD_BLEND_EQUATION_ALPHA,
265           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
266   g_object_class_install_property (gobject_class,
267       PROP_INPUT_BLEND_FUNCTION_SRC_RGB,
268       g_param_spec_enum ("blend-function-src-rgb", "Blend Function Source RGB",
269           "Blend Function for Source RGB",
270           GST_TYPE_GL_VIDEO_MIXER_BLEND_FUNCTION,
271           DEFAULT_PAD_BLEND_FUNCTION_SRC_RGB,
272           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
273   g_object_class_install_property (gobject_class,
274       PROP_INPUT_BLEND_FUNCTION_SRC_ALPHA,
275       g_param_spec_enum ("blend-function-src-alpha",
276           "Blend Function Source Alpha", "Blend Function for Source Alpha",
277           GST_TYPE_GL_VIDEO_MIXER_BLEND_FUNCTION,
278           DEFAULT_PAD_BLEND_FUNCTION_SRC_ALPHA,
279           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
280   g_object_class_install_property (gobject_class,
281       PROP_INPUT_BLEND_FUNCTION_DST_RGB,
282       g_param_spec_enum ("blend-function-dst-rgb",
283           "Blend Function Destination RGB",
284           "Blend Function for Destination RGB",
285           GST_TYPE_GL_VIDEO_MIXER_BLEND_FUNCTION,
286           DEFAULT_PAD_BLEND_FUNCTION_DST_RGB,
287           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
288   g_object_class_install_property (gobject_class,
289       PROP_INPUT_BLEND_FUNCTION_DST_ALPHA,
290       g_param_spec_enum ("blend-function-dst-alpha",
291           "Blend Function Destination Alpha",
292           "Blend Function for Destination Alpha",
293           GST_TYPE_GL_VIDEO_MIXER_BLEND_FUNCTION,
294           DEFAULT_PAD_BLEND_FUNCTION_DST_ALPHA,
295           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
296   g_object_class_install_property (gobject_class,
297       PROP_INPUT_BLEND_FUNCTION_CONSTANT_COLOR_RED,
298       g_param_spec_double ("blend-constant-color-red",
299           "Blend Constant Color Red", "Blend Constant Color Red", 0.0, 1.0, 0.0,
300           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
301   g_object_class_install_property (gobject_class,
302       PROP_INPUT_BLEND_FUNCTION_CONSTANT_COLOR_GREEN,
303       g_param_spec_double ("blend-constant-color-green",
304           "Blend Constant Color Green", "Blend Constant Color Green", 0.0, 1.0,
305           0.0,
306           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
307   g_object_class_install_property (gobject_class,
308       PROP_INPUT_BLEND_FUNCTION_CONSTANT_COLOR_BLUE,
309       g_param_spec_double ("blend-constant-color-blue",
310           "Blend Constant Color Green", "Blend Constant Color Green", 0.0, 1.0,
311           0.0,
312           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
313   g_object_class_install_property (gobject_class,
314       PROP_INPUT_BLEND_FUNCTION_CONSTANT_COLOR_ALPHA,
315       g_param_spec_double ("blend-constant-color-alpha",
316           "Blend Constant Color Alpha", "Blend Constant Color Alpha", 0.0, 1.0,
317           0.0,
318           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
319 }
320
321 static void
322 gst_gl_video_mixer_input_get_property (GObject * object, guint prop_id,
323     GValue * value, GParamSpec * pspec)
324 {
325   GstGLVideoMixerInput *self = (GstGLVideoMixerInput *) object;
326
327   if (self->mixer_pad)
328     g_object_get_property (G_OBJECT (self->mixer_pad), pspec->name, value);
329 }
330
331 static void
332 gst_gl_video_mixer_input_set_property (GObject * object, guint prop_id,
333     const GValue * value, GParamSpec * pspec)
334 {
335   GstGLVideoMixerInput *self = (GstGLVideoMixerInput *) object;
336
337   if (self->mixer_pad)
338     g_object_set_property (G_OBJECT (self->mixer_pad), pspec->name, value);
339 }
340
341 static GstGhostPad *
342 _create_video_mixer_input (GstGLMixerBin * self, GstPad * mixer_pad)
343 {
344   GstGLVideoMixerInput *input =
345       g_object_new (gst_gl_video_mixer_input_get_type (), "name",
346       GST_OBJECT_NAME (mixer_pad), "direction", GST_PAD_DIRECTION (mixer_pad),
347       NULL);
348
349   if (!gst_ghost_pad_construct (GST_GHOST_PAD (input))) {
350     gst_object_unref (input);
351     return NULL;
352   }
353 #define ADD_BINDING(obj,ref,prop) \
354     gst_object_add_control_binding (GST_OBJECT (obj), \
355         gst_proxy_control_binding_new (GST_OBJECT (obj), prop, \
356             GST_OBJECT (ref), prop));
357   ADD_BINDING (mixer_pad, input, "zorder");
358   ADD_BINDING (mixer_pad, input, "xpos");
359   ADD_BINDING (mixer_pad, input, "ypos");
360   ADD_BINDING (mixer_pad, input, "width");
361   ADD_BINDING (mixer_pad, input, "height");
362   ADD_BINDING (mixer_pad, input, "alpha");
363   ADD_BINDING (mixer_pad, input, "blend-equation-rgb");
364   ADD_BINDING (mixer_pad, input, "blend-equation-alpha");
365   ADD_BINDING (mixer_pad, input, "blend-function-src-rgb");
366   ADD_BINDING (mixer_pad, input, "blend-function-src-alpha");
367   ADD_BINDING (mixer_pad, input, "blend-function-dst-rgb");
368   ADD_BINDING (mixer_pad, input, "blend-function-dst-alpha");
369   ADD_BINDING (mixer_pad, input, "blend-constant-color-red");
370   ADD_BINDING (mixer_pad, input, "blend-constant-color-green");
371   ADD_BINDING (mixer_pad, input, "blend-constant-color-blue");
372   ADD_BINDING (mixer_pad, input, "blend-constant-color-alpha");
373 #undef ADD_BINDING
374
375   input->mixer_pad = mixer_pad;
376
377   return GST_GHOST_PAD (input);
378 }
379
380 enum
381 {
382   PROP_BIN_0,
383   PROP_BIN_BACKGROUND,
384 };
385 #define DEFAULT_BACKGROUND GST_GL_VIDEO_MIXER_BACKGROUND_CHECKER
386
387 static void gst_gl_video_mixer_bin_get_property (GObject * object,
388     guint prop_id, GValue * value, GParamSpec * pspec);
389 static void gst_gl_video_mixer_bin_set_property (GObject * object,
390     guint prop_id, const GValue * value, GParamSpec * pspec);
391
392 typedef GstGLMixerBin GstGLVideoMixerBin;
393 typedef GstGLMixerBinClass GstGLVideoMixerBinClass;
394
395 G_DEFINE_TYPE (GstGLVideoMixerBin, gst_gl_video_mixer_bin,
396     GST_TYPE_GL_MIXER_BIN);
397
398 static void
399 gst_gl_video_mixer_bin_init (GstGLVideoMixerBin * self)
400 {
401   GstGLMixerBin *mix_bin = GST_GL_MIXER_BIN (self);
402
403   gst_gl_mixer_bin_finish_init_with_element (mix_bin,
404       g_object_new (GST_TYPE_GL_VIDEO_MIXER, NULL));
405 }
406
407 static void
408 gst_gl_video_mixer_bin_class_init (GstGLVideoMixerBinClass * klass)
409 {
410   GstGLMixerBinClass *mixer_class = GST_GL_MIXER_BIN_CLASS (klass);
411   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
412   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
413
414   mixer_class->create_input_pad = _create_video_mixer_input;
415
416   gobject_class->set_property = gst_gl_video_mixer_bin_set_property;
417   gobject_class->get_property = gst_gl_video_mixer_bin_get_property;
418
419   g_object_class_install_property (gobject_class, PROP_BIN_BACKGROUND,
420       g_param_spec_enum ("background", "Background", "Background type",
421           GST_TYPE_GL_VIDEO_MIXER_BACKGROUND,
422           DEFAULT_BACKGROUND, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
423
424   gst_element_class_set_metadata (element_class, "OpenGL video_mixer bin",
425       "Bin/Filter/Effect/Video/Compositor", "OpenGL video_mixer bin",
426       "Matthew Waters <matthew@centricular.com>");
427 }
428
429 static void
430 gst_gl_video_mixer_bin_get_property (GObject * object, guint prop_id,
431     GValue * value, GParamSpec * pspec)
432 {
433   GstGLMixerBin *self = GST_GL_MIXER_BIN (object);
434
435   if (self->mixer)
436     g_object_get_property (G_OBJECT (self->mixer), pspec->name, value);
437 }
438
439 static void
440 gst_gl_video_mixer_bin_set_property (GObject * object, guint prop_id,
441     const GValue * value, GParamSpec * pspec)
442 {
443   GstGLMixerBin *self = GST_GL_MIXER_BIN (object);
444
445   if (self->mixer)
446     g_object_set_property (G_OBJECT (self->mixer), pspec->name, value);
447 }
448
449 enum
450 {
451   PROP_0,
452   PROP_BACKGROUND,
453 };
454
455 static void gst_gl_video_mixer_child_proxy_init (gpointer g_iface,
456     gpointer iface_data);
457
458 #define DEBUG_INIT \
459     GST_DEBUG_CATEGORY_INIT (gst_gl_video_mixer_debug, "glvideomixer", 0, "glvideomixer element");
460
461 #define gst_gl_video_mixer_parent_class parent_class
462 G_DEFINE_TYPE_WITH_CODE (GstGLVideoMixer, gst_gl_video_mixer, GST_TYPE_GL_MIXER,
463     G_IMPLEMENT_INTERFACE (GST_TYPE_CHILD_PROXY,
464         gst_gl_video_mixer_child_proxy_init); DEBUG_INIT);
465
466 static void gst_gl_video_mixer_set_property (GObject * object, guint prop_id,
467     const GValue * value, GParamSpec * pspec);
468 static void gst_gl_video_mixer_get_property (GObject * object, guint prop_id,
469     GValue * value, GParamSpec * pspec);
470
471 static GstCaps *_update_caps (GstVideoAggregator * vagg, GstCaps * caps);
472 static GstCaps *_fixate_caps (GstAggregator * agg, GstCaps * caps);
473 static gboolean gst_gl_video_mixer_propose_allocation (GstAggregator *
474     agg, GstAggregatorPad * agg_pad, GstQuery * decide_query, GstQuery * query);
475 static gboolean gst_gl_video_mixer_gl_start (GstGLBaseMixer * base_mix);
476 static void gst_gl_video_mixer_gl_stop (GstGLBaseMixer * base_mix);
477 static gboolean gst_gl_video_mixer_set_caps (GstGLMixer * mixer,
478     GstCaps * outcaps);
479
480 static gboolean gst_gl_video_mixer_process_textures (GstGLMixer * mixer,
481     GstGLMemory * out_tex);
482 static gboolean gst_gl_video_mixer_callback (gpointer stuff);
483
484 /* *INDENT-OFF* */
485
486 /* fragment source */
487 static const gchar *video_mixer_f_src =
488     "uniform sampler2D texture;                     \n"
489     "uniform float alpha;\n"
490     "varying vec2 v_texcoord;                            \n"
491     "void main()                                         \n"
492     "{                                                   \n"
493     "  vec4 rgba = texture2D(texture, v_texcoord);\n"
494     "  gl_FragColor = vec4(rgba.rgb, rgba.a * alpha);\n"
495     "}                                                   \n";
496
497 /* checker vertex source */
498 static const gchar *checker_v_src =
499     "attribute vec4 a_position;\n"
500     "void main()\n"
501     "{\n"
502     "   gl_Position = a_position;\n"
503     "}\n";
504
505 /* checker fragment source */
506 static const gchar *checker_f_src =
507     "const float blocksize = 8.0;\n"
508     "void main ()\n"
509     "{\n"
510     "  vec4 high = vec4(0.667, 0.667, 0.667, 1.0);\n"
511     "  vec4 low = vec4(0.333, 0.333, 0.333, 1.0);\n"
512     "  if (mod(gl_FragCoord.x, blocksize * 2.0) >= blocksize) {\n"
513     "    if (mod(gl_FragCoord.y, blocksize * 2.0) >= blocksize)\n"
514     "      gl_FragColor = low;\n"
515     "    else\n"
516     "      gl_FragColor = high;\n"
517     "  } else {\n"
518     "    if (mod(gl_FragCoord.y, blocksize * 2.0) < blocksize)\n"
519     "      gl_FragColor = low;\n"
520     "    else\n"
521     "      gl_FragColor = high;\n"
522     "  }\n"
523     "}\n";
524 /* *INDENT-ON* */
525
526 #define GST_TYPE_GL_VIDEO_MIXER_PAD (gst_gl_video_mixer_pad_get_type())
527 #define GST_GL_VIDEO_MIXER_PAD(obj) \
528         (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_VIDEO_MIXER_PAD, GstGLVideoMixerPad))
529 #define GST_GL_VIDEO_MIXER_PAD_CLASS(klass) \
530         (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GL_VIDEO_MIXER_PAD, GstGLVideoMixerPadClass))
531 #define GST_IS_GL_VIDEO_MIXER_PAD(obj) \
532         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_VIDEO_MIXER_PAD))
533 #define GST_IS_GL_VIDEO_MIXER_PAD_CLASS(klass) \
534         (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GL_VIDEO_MIXER_PAD))
535
536 typedef struct _GstGLVideoMixerPad GstGLVideoMixerPad;
537 typedef struct _GstGLVideoMixerPadClass GstGLVideoMixerPadClass;
538 typedef struct _GstGLVideoMixerCollect GstGLVideoMixerCollect;
539
540 /**
541  * GstGLVideoMixerPad:
542  *
543  * The opaque #GstGLVideoMixerPad structure.
544  */
545 struct _GstGLVideoMixerPad
546 {
547   GstGLMixerPad parent;
548
549   /* properties */
550   gint xpos, ypos;
551   gint width, height;
552   gdouble alpha;
553
554   GstGLVideoMixerBlendEquation blend_equation_rgb;
555   GstGLVideoMixerBlendEquation blend_equation_alpha;
556   GstGLVideoMixerBlendFunction blend_function_src_rgb;
557   GstGLVideoMixerBlendFunction blend_function_src_alpha;
558   GstGLVideoMixerBlendFunction blend_function_dst_rgb;
559   GstGLVideoMixerBlendFunction blend_function_dst_alpha;
560   gdouble blend_constant_color_red;
561   gdouble blend_constant_color_green;
562   gdouble blend_constant_color_blue;
563   gdouble blend_constant_color_alpha;
564
565   gboolean geometry_change;
566   GLuint vertex_buffer;
567   gfloat m_matrix[16];
568 };
569
570 struct _GstGLVideoMixerPadClass
571 {
572   GstGLMixerPadClass parent_class;
573 };
574
575 GType gst_gl_video_mixer_pad_get_type (void);
576 G_DEFINE_TYPE (GstGLVideoMixerPad, gst_gl_video_mixer_pad,
577     GST_TYPE_GL_MIXER_PAD);
578
579 static void gst_gl_video_mixer_pad_set_property (GObject * object,
580     guint prop_id, const GValue * value, GParamSpec * pspec);
581 static void gst_gl_video_mixer_pad_get_property (GObject * object,
582     guint prop_id, GValue * value, GParamSpec * pspec);
583
584 enum
585 {
586   PROP_PAD_0,
587   PROP_PAD_XPOS,
588   PROP_PAD_YPOS,
589   PROP_PAD_WIDTH,
590   PROP_PAD_HEIGHT,
591   PROP_PAD_ALPHA,
592   PROP_PAD_BLEND_EQUATION_RGB,
593   PROP_PAD_BLEND_EQUATION_ALPHA,
594   PROP_PAD_BLEND_FUNCTION_SRC_RGB,
595   PROP_PAD_BLEND_FUNCTION_SRC_ALPHA,
596   PROP_PAD_BLEND_FUNCTION_DST_RGB,
597   PROP_PAD_BLEND_FUNCTION_DST_ALPHA,
598   PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_RED,
599   PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_GREEN,
600   PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_BLUE,
601   PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_ALPHA,
602 };
603
604 static void
605 gst_gl_video_mixer_pad_init (GstGLVideoMixerPad * pad)
606 {
607   pad->alpha = DEFAULT_PAD_ALPHA;
608   pad->blend_equation_rgb = DEFAULT_PAD_BLEND_EQUATION_RGB;
609   pad->blend_equation_alpha = DEFAULT_PAD_BLEND_EQUATION_ALPHA;
610   pad->blend_function_src_rgb = DEFAULT_PAD_BLEND_FUNCTION_SRC_RGB;
611   pad->blend_function_src_alpha = DEFAULT_PAD_BLEND_FUNCTION_SRC_ALPHA;
612   pad->blend_function_dst_rgb = DEFAULT_PAD_BLEND_FUNCTION_DST_RGB;
613   pad->blend_function_dst_alpha = DEFAULT_PAD_BLEND_FUNCTION_DST_ALPHA;
614   memset (pad->m_matrix, 0, sizeof (gfloat) * 4 * 4);
615   pad->m_matrix[0] = 1.0;
616   pad->m_matrix[5] = 1.0;
617   pad->m_matrix[10] = 1.0;
618   pad->m_matrix[15] = 1.0;
619 }
620
621 static void
622 gst_gl_video_mixer_pad_class_init (GstGLVideoMixerPadClass * klass)
623 {
624   GObjectClass *gobject_class = (GObjectClass *) klass;
625
626   gobject_class->set_property = gst_gl_video_mixer_pad_set_property;
627   gobject_class->get_property = gst_gl_video_mixer_pad_get_property;
628
629   g_object_class_install_property (gobject_class, PROP_PAD_XPOS,
630       g_param_spec_int ("xpos", "X Position", "X Position of the picture",
631           G_MININT, G_MAXINT, DEFAULT_PAD_XPOS,
632           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
633   g_object_class_install_property (gobject_class, PROP_PAD_YPOS,
634       g_param_spec_int ("ypos", "Y Position", "Y Position of the picture",
635           G_MININT, G_MAXINT, DEFAULT_PAD_YPOS,
636           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
637   g_object_class_install_property (gobject_class, PROP_PAD_WIDTH,
638       g_param_spec_int ("width", "Width", "Width of the picture",
639           G_MININT, G_MAXINT, DEFAULT_PAD_WIDTH,
640           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
641   g_object_class_install_property (gobject_class, PROP_PAD_HEIGHT,
642       g_param_spec_int ("height", "Height", "Height of the picture",
643           G_MININT, G_MAXINT, DEFAULT_PAD_HEIGHT,
644           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
645   g_object_class_install_property (gobject_class, PROP_PAD_ALPHA,
646       g_param_spec_double ("alpha", "Alpha", "Alpha of the picture", 0.0, 1.0,
647           DEFAULT_PAD_ALPHA,
648           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
649   g_object_class_install_property (gobject_class, PROP_INPUT_BLEND_EQUATION_RGB,
650       g_param_spec_enum ("blend-equation-rgb", "Blend Equation RGB",
651           "Blend Equation for RGB",
652           GST_TYPE_GL_VIDEO_MIXER_BLEND_EQUATION,
653           DEFAULT_PAD_BLEND_EQUATION_RGB,
654           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
655   g_object_class_install_property (gobject_class,
656       PROP_INPUT_BLEND_EQUATION_ALPHA,
657       g_param_spec_enum ("blend-equation-alpha", "Blend Equation Alpha",
658           "Blend Equation for Alpha", GST_TYPE_GL_VIDEO_MIXER_BLEND_EQUATION,
659           DEFAULT_PAD_BLEND_EQUATION_ALPHA,
660           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
661   g_object_class_install_property (gobject_class,
662       PROP_INPUT_BLEND_FUNCTION_SRC_RGB,
663       g_param_spec_enum ("blend-function-src-rgb", "Blend Function Source RGB",
664           "Blend Function for Source RGB",
665           GST_TYPE_GL_VIDEO_MIXER_BLEND_FUNCTION,
666           DEFAULT_PAD_BLEND_FUNCTION_SRC_RGB,
667           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
668   g_object_class_install_property (gobject_class,
669       PROP_INPUT_BLEND_FUNCTION_SRC_ALPHA,
670       g_param_spec_enum ("blend-function-src-alpha",
671           "Blend Function Source Alpha", "Blend Function for Source Alpha",
672           GST_TYPE_GL_VIDEO_MIXER_BLEND_FUNCTION,
673           DEFAULT_PAD_BLEND_FUNCTION_SRC_ALPHA,
674           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
675   g_object_class_install_property (gobject_class,
676       PROP_INPUT_BLEND_FUNCTION_DST_RGB,
677       g_param_spec_enum ("blend-function-dst-rgb",
678           "Blend Function Destination RGB",
679           "Blend Function for Destination RGB",
680           GST_TYPE_GL_VIDEO_MIXER_BLEND_FUNCTION,
681           DEFAULT_PAD_BLEND_FUNCTION_DST_RGB,
682           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
683   g_object_class_install_property (gobject_class,
684       PROP_INPUT_BLEND_FUNCTION_DST_ALPHA,
685       g_param_spec_enum ("blend-function-dst-alpha",
686           "Blend Function Destination Alpha",
687           "Blend Function for Destination Alpha",
688           GST_TYPE_GL_VIDEO_MIXER_BLEND_FUNCTION,
689           DEFAULT_PAD_BLEND_FUNCTION_DST_ALPHA,
690           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
691   g_object_class_install_property (gobject_class,
692       PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_RED,
693       g_param_spec_double ("blend-constant-color-red",
694           "Blend Constant Color Red", "Blend Constant Color Red", 0.0, 1.0, 0.0,
695           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
696   g_object_class_install_property (gobject_class,
697       PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_GREEN,
698       g_param_spec_double ("blend-constant-color-green",
699           "Blend Constant Color Green", "Blend Constant Color Green", 0.0, 1.0,
700           0.0,
701           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
702   g_object_class_install_property (gobject_class,
703       PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_BLUE,
704       g_param_spec_double ("blend-constant-color-blue",
705           "Blend Constant Color Green", "Blend Constant Color Green", 0.0, 1.0,
706           0.0,
707           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
708   g_object_class_install_property (gobject_class,
709       PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_ALPHA,
710       g_param_spec_double ("blend-constant-color-alpha",
711           "Blend Constant Color Alpha", "Blend Constant Color Alpha", 0.0, 1.0,
712           0.0,
713           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
714 }
715
716 static void
717 gst_gl_video_mixer_pad_get_property (GObject * object, guint prop_id,
718     GValue * value, GParamSpec * pspec)
719 {
720   GstGLVideoMixerPad *pad = GST_GL_VIDEO_MIXER_PAD (object);
721
722   switch (prop_id) {
723     case PROP_PAD_XPOS:
724       g_value_set_int (value, pad->xpos);
725       break;
726     case PROP_PAD_YPOS:
727       g_value_set_int (value, pad->ypos);
728       break;
729     case PROP_PAD_WIDTH:
730       g_value_set_int (value, pad->width);
731       break;
732     case PROP_PAD_HEIGHT:
733       g_value_set_int (value, pad->height);
734       break;
735     case PROP_PAD_ALPHA:
736       g_value_set_double (value, pad->alpha);
737       break;
738     case PROP_PAD_BLEND_EQUATION_RGB:
739       g_value_set_enum (value, pad->blend_equation_rgb);
740       break;
741     case PROP_PAD_BLEND_EQUATION_ALPHA:
742       g_value_set_enum (value, pad->blend_equation_alpha);
743       break;
744     case PROP_PAD_BLEND_FUNCTION_SRC_RGB:
745       g_value_set_enum (value, pad->blend_function_src_rgb);
746       break;
747     case PROP_PAD_BLEND_FUNCTION_SRC_ALPHA:
748       g_value_set_enum (value, pad->blend_function_src_alpha);
749       break;
750     case PROP_PAD_BLEND_FUNCTION_DST_RGB:
751       g_value_set_enum (value, pad->blend_function_dst_rgb);
752       break;
753     case PROP_PAD_BLEND_FUNCTION_DST_ALPHA:
754       g_value_set_enum (value, pad->blend_function_dst_alpha);
755       break;
756     case PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_RED:
757       g_value_set_double (value, pad->blend_constant_color_red);
758       break;
759     case PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_GREEN:
760       g_value_set_double (value, pad->blend_constant_color_green);
761       break;
762     case PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_BLUE:
763       g_value_set_double (value, pad->blend_constant_color_blue);
764       break;
765     case PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_ALPHA:
766       g_value_set_double (value, pad->blend_constant_color_alpha);
767       break;
768     default:
769       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
770       break;
771   }
772 }
773
774 static void
775 gst_gl_video_mixer_pad_set_property (GObject * object, guint prop_id,
776     const GValue * value, GParamSpec * pspec)
777 {
778   GstGLVideoMixerPad *pad = GST_GL_VIDEO_MIXER_PAD (object);
779   GstGLMixer *mix = GST_GL_MIXER (gst_pad_get_parent (GST_PAD (pad)));
780
781   switch (prop_id) {
782     case PROP_PAD_XPOS:
783       pad->xpos = g_value_get_int (value);
784       pad->geometry_change = TRUE;
785       break;
786     case PROP_PAD_YPOS:
787       pad->ypos = g_value_get_int (value);
788       pad->geometry_change = TRUE;
789       break;
790     case PROP_PAD_WIDTH:
791       pad->width = g_value_get_int (value);
792       pad->geometry_change = TRUE;
793       break;
794     case PROP_PAD_HEIGHT:
795       pad->height = g_value_get_int (value);
796       pad->geometry_change = TRUE;
797       break;
798     case PROP_PAD_ALPHA:
799       pad->alpha = g_value_get_double (value);
800       break;
801     case PROP_PAD_BLEND_EQUATION_RGB:
802       pad->blend_equation_rgb = g_value_get_enum (value);
803       break;
804     case PROP_PAD_BLEND_EQUATION_ALPHA:
805       pad->blend_equation_alpha = g_value_get_enum (value);
806       break;
807     case PROP_PAD_BLEND_FUNCTION_SRC_RGB:
808       pad->blend_function_src_rgb = g_value_get_enum (value);
809       break;
810     case PROP_PAD_BLEND_FUNCTION_SRC_ALPHA:
811       pad->blend_function_src_alpha = g_value_get_enum (value);
812       break;
813     case PROP_PAD_BLEND_FUNCTION_DST_RGB:
814       pad->blend_function_dst_rgb = g_value_get_enum (value);
815       break;
816     case PROP_PAD_BLEND_FUNCTION_DST_ALPHA:
817       pad->blend_function_dst_alpha = g_value_get_enum (value);
818       break;
819     case PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_RED:
820       pad->blend_constant_color_red = g_value_get_double (value);
821       break;
822     case PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_GREEN:
823       pad->blend_constant_color_green = g_value_get_double (value);
824       break;
825     case PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_BLUE:
826       pad->blend_constant_color_blue = g_value_get_double (value);
827       break;
828     case PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_ALPHA:
829       pad->blend_constant_color_alpha = g_value_get_double (value);
830       break;
831     default:
832       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
833       break;
834   }
835
836   gst_object_unref (mix);
837 }
838
839 static void
840 _del_buffer (GstGLContext * context, GLuint * pBuffer)
841 {
842   context->gl_vtable->DeleteBuffers (1, pBuffer);
843 }
844
845 static GstPad *
846 gst_gl_video_mixer_request_new_pad (GstElement * element,
847     GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps)
848 {
849   GstPad *newpad;
850
851   newpad = (GstPad *)
852       GST_ELEMENT_CLASS (parent_class)->request_new_pad (element,
853       templ, req_name, caps);
854
855   if (newpad == NULL)
856     goto could_not_create;
857
858   gst_child_proxy_child_added (GST_CHILD_PROXY (element), G_OBJECT (newpad),
859       GST_OBJECT_NAME (newpad));
860
861   return newpad;
862
863 could_not_create:
864   {
865     GST_DEBUG_OBJECT (element, "could not create/add  pad");
866     return NULL;
867   }
868 }
869
870 static void
871 gst_gl_video_mixer_release_pad (GstElement * element, GstPad * p)
872 {
873   GstGLVideoMixerPad *pad = GST_GL_VIDEO_MIXER_PAD (p);
874
875   gst_child_proxy_child_removed (GST_CHILD_PROXY (element), G_OBJECT (pad),
876       GST_OBJECT_NAME (pad));
877
878   /* we call the base class first as this will remove the pad from
879    * the aggregator, thus stopping misc callbacks from being called,
880    * one of which (process_textures) will recreate the vertex_buffer
881    * if it is destroyed */
882   GST_ELEMENT_CLASS (g_type_class_peek_parent (G_OBJECT_GET_CLASS (element)))
883       ->release_pad (element, p);
884
885   if (pad->vertex_buffer) {
886     GstGLBaseMixer *mix = GST_GL_BASE_MIXER (element);
887     gst_gl_context_thread_add (mix->context, (GstGLContextThreadFunc)
888         _del_buffer, &pad->vertex_buffer);
889     pad->vertex_buffer = 0;
890   }
891 }
892
893 static void
894 gst_gl_video_mixer_class_init (GstGLVideoMixerClass * klass)
895 {
896   GObjectClass *gobject_class;
897   GstElementClass *element_class;
898   GstAggregatorClass *agg_class = (GstAggregatorClass *) klass;
899   GstVideoAggregatorClass *vagg_class = (GstVideoAggregatorClass *) klass;
900
901   gobject_class = (GObjectClass *) klass;
902   element_class = GST_ELEMENT_CLASS (klass);
903   element_class->request_new_pad = gst_gl_video_mixer_request_new_pad;
904   element_class->release_pad = gst_gl_video_mixer_release_pad;
905
906   gobject_class->set_property = gst_gl_video_mixer_set_property;
907   gobject_class->get_property = gst_gl_video_mixer_get_property;
908
909   gst_element_class_set_metadata (element_class, "OpenGL video_mixer",
910       "Filter/Effect/Video/Compositor", "OpenGL video_mixer",
911       "Matthew Waters <matthew@centricular.com>");
912
913   gst_element_class_add_static_pad_template_with_gtype (element_class,
914       &sink_factory, GST_TYPE_GL_VIDEO_MIXER_PAD);
915
916   g_object_class_install_property (gobject_class, PROP_BACKGROUND,
917       g_param_spec_enum ("background", "Background", "Background type",
918           GST_TYPE_GL_VIDEO_MIXER_BACKGROUND,
919           DEFAULT_BACKGROUND, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
920
921   GST_GL_MIXER_CLASS (klass)->set_caps = gst_gl_video_mixer_set_caps;
922   GST_GL_MIXER_CLASS (klass)->process_textures =
923       gst_gl_video_mixer_process_textures;
924
925   GST_GL_BASE_MIXER_CLASS (klass)->gl_stop = gst_gl_video_mixer_gl_stop;
926   GST_GL_BASE_MIXER_CLASS (klass)->gl_start = gst_gl_video_mixer_gl_start;
927
928   vagg_class->update_caps = _update_caps;
929
930   agg_class->fixate_src_caps = _fixate_caps;
931   agg_class->propose_allocation = gst_gl_video_mixer_propose_allocation;
932
933   GST_GL_BASE_MIXER_CLASS (klass)->supported_gl_api =
934       GST_GL_API_OPENGL | GST_GL_API_OPENGL3 | GST_GL_API_GLES2;
935
936   gst_type_mark_as_plugin_api (GST_TYPE_GL_VIDEO_MIXER_BACKGROUND, 0);
937   gst_type_mark_as_plugin_api (GST_TYPE_GL_VIDEO_MIXER_PAD, 0);
938   gst_type_mark_as_plugin_api (GST_TYPE_GL_VIDEO_MIXER_BLEND_EQUATION, 0);
939   gst_type_mark_as_plugin_api (GST_TYPE_GL_VIDEO_MIXER_BLEND_FUNCTION, 0);
940 }
941
942 static void
943 gst_gl_video_mixer_init (GstGLVideoMixer * video_mixer)
944 {
945   video_mixer->background = DEFAULT_BACKGROUND;
946   video_mixer->shader = NULL;
947 }
948
949 static void
950 gst_gl_video_mixer_set_property (GObject * object, guint prop_id,
951     const GValue * value, GParamSpec * pspec)
952 {
953   GstGLVideoMixer *mixer = GST_GL_VIDEO_MIXER (object);
954
955   switch (prop_id) {
956     case PROP_BACKGROUND:
957       mixer->background = g_value_get_enum (value);
958       break;
959     default:
960       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
961       break;
962   }
963 }
964
965 static void
966 gst_gl_video_mixer_get_property (GObject * object, guint prop_id,
967     GValue * value, GParamSpec * pspec)
968 {
969   GstGLVideoMixer *mixer = GST_GL_VIDEO_MIXER (object);
970
971   switch (prop_id) {
972     case PROP_BACKGROUND:
973       g_value_set_enum (value, mixer->background);
974       break;
975     default:
976       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
977       break;
978   }
979 }
980
981 static gboolean
982 gst_gl_video_mixer_propose_allocation (GstAggregator * agg,
983     GstAggregatorPad * agg_pad, GstQuery * decide_query, GstQuery * query)
984 {
985   if (!GST_AGGREGATOR_CLASS (parent_class)->propose_allocation (agg,
986           agg_pad, decide_query, query))
987     return FALSE;
988
989   gst_query_add_allocation_meta (query,
990       GST_VIDEO_AFFINE_TRANSFORMATION_META_API_TYPE, 0);
991
992   return TRUE;
993 }
994
995 static void
996 _mixer_pad_get_output_size (GstGLVideoMixer * mix,
997     GstGLVideoMixerPad * mix_pad, gint out_par_n, gint out_par_d, gint * width,
998     gint * height)
999 {
1000   GstVideoAggregatorPad *vagg_pad = GST_VIDEO_AGGREGATOR_PAD (mix_pad);
1001   gint pad_width, pad_height;
1002   guint dar_n, dar_d;
1003
1004   /* FIXME: Anything better we can do here? */
1005   if (!vagg_pad->info.finfo
1006       || vagg_pad->info.finfo->format == GST_VIDEO_FORMAT_UNKNOWN) {
1007     GST_DEBUG_OBJECT (mix_pad, "Have no caps yet");
1008     *width = 0;
1009     *height = 0;
1010     return;
1011   }
1012
1013   pad_width =
1014       mix_pad->width <=
1015       0 ? GST_VIDEO_INFO_WIDTH (&vagg_pad->info) : mix_pad->width;
1016   pad_height =
1017       mix_pad->height <=
1018       0 ? GST_VIDEO_INFO_HEIGHT (&vagg_pad->info) : mix_pad->height;
1019
1020   if (!gst_video_calculate_display_ratio (&dar_n, &dar_d, pad_width, pad_height,
1021           GST_VIDEO_INFO_PAR_N (&vagg_pad->info),
1022           GST_VIDEO_INFO_PAR_D (&vagg_pad->info), out_par_n, out_par_d)) {
1023     GST_WARNING_OBJECT (mix_pad, "Cannot calculate display aspect ratio");
1024     *width = *height = 0;
1025     return;
1026   }
1027   GST_LOG_OBJECT (mix_pad, "scaling %ux%u by %u/%u (%u/%u / %u/%u)", pad_width,
1028       pad_height, dar_n, dar_d, GST_VIDEO_INFO_PAR_N (&vagg_pad->info),
1029       GST_VIDEO_INFO_PAR_D (&vagg_pad->info), out_par_n, out_par_d);
1030
1031   if (pad_height % dar_n == 0) {
1032     pad_width = gst_util_uint64_scale_int (pad_height, dar_n, dar_d);
1033   } else if (pad_width % dar_d == 0) {
1034     pad_height = gst_util_uint64_scale_int (pad_width, dar_d, dar_n);
1035   } else {
1036     pad_width = gst_util_uint64_scale_int (pad_height, dar_n, dar_d);
1037   }
1038
1039   *width = pad_width;
1040   *height = pad_height;
1041 }
1042
1043 static GstCaps *
1044 _update_caps (GstVideoAggregator * vagg, GstCaps * caps)
1045 {
1046   GstCaps *template_caps, *ret;
1047   GList *l;
1048
1049   GST_OBJECT_LOCK (vagg);
1050   for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) {
1051     GstVideoAggregatorPad *vaggpad = l->data;
1052
1053     if (!vaggpad->info.finfo)
1054       continue;
1055
1056     if (GST_VIDEO_INFO_FORMAT (&vaggpad->info) == GST_VIDEO_FORMAT_UNKNOWN)
1057       continue;
1058
1059     if (GST_VIDEO_INFO_MULTIVIEW_MODE (&vaggpad->info) !=
1060         GST_VIDEO_MULTIVIEW_MODE_NONE
1061         && GST_VIDEO_INFO_MULTIVIEW_MODE (&vaggpad->info) !=
1062         GST_VIDEO_MULTIVIEW_MODE_MONO) {
1063       GST_FIXME_OBJECT (vaggpad, "Multiview support is not implemented yet");
1064       GST_OBJECT_UNLOCK (vagg);
1065       return NULL;
1066     }
1067   }
1068
1069   GST_OBJECT_UNLOCK (vagg);
1070
1071   template_caps = gst_pad_get_pad_template_caps (GST_AGGREGATOR_SRC_PAD (vagg));
1072   ret = gst_caps_intersect (caps, template_caps);
1073
1074   return ret;
1075 }
1076
1077 static GstCaps *
1078 _fixate_caps (GstAggregator * agg, GstCaps * caps)
1079 {
1080   GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (agg);
1081   GstGLVideoMixer *mix = GST_GL_VIDEO_MIXER (vagg);
1082   gint best_width = 0, best_height = 0;
1083   gint best_fps_n = 0, best_fps_d = 0;
1084   gint par_n, par_d;
1085   gdouble best_fps = 0.;
1086   GstCaps *ret = NULL;
1087   GstStructure *s;
1088   GList *l;
1089
1090   ret = gst_caps_make_writable (caps);
1091
1092   /* we need this to calculate how large to make the output frame */
1093   s = gst_caps_get_structure (ret, 0);
1094   if (!gst_structure_has_field (s, "pixel-aspect-ratio")) {
1095     gst_structure_set (s, "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1, NULL);
1096   }
1097   gst_structure_fixate_field_nearest_fraction (s, "pixel-aspect-ratio", 1, 1);
1098   gst_structure_get_fraction (s, "pixel-aspect-ratio", &par_n, &par_d);
1099
1100   GST_OBJECT_LOCK (vagg);
1101   for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) {
1102     GstVideoAggregatorPad *vaggpad = l->data;
1103     GstGLVideoMixerPad *mixer_pad = GST_GL_VIDEO_MIXER_PAD (vaggpad);
1104     gint this_width, this_height;
1105     gint width, height;
1106     gint fps_n, fps_d;
1107     gdouble cur_fps;
1108
1109     fps_n = GST_VIDEO_INFO_FPS_N (&vaggpad->info);
1110     fps_d = GST_VIDEO_INFO_FPS_D (&vaggpad->info);
1111     _mixer_pad_get_output_size (mix, mixer_pad, par_n, par_d, &width, &height);
1112
1113     if (width == 0 || height == 0)
1114       continue;
1115
1116     this_width = width + MAX (mixer_pad->xpos, 0);
1117     this_height = height + MAX (mixer_pad->ypos, 0);
1118
1119     if (best_width < this_width)
1120       best_width = this_width;
1121     if (best_height < this_height)
1122       best_height = this_height;
1123
1124     if (fps_d == 0)
1125       cur_fps = 0.0;
1126     else
1127       gst_util_fraction_to_double (fps_n, fps_d, &cur_fps);
1128
1129     if (best_fps < cur_fps) {
1130       best_fps = cur_fps;
1131       best_fps_n = fps_n;
1132       best_fps_d = fps_d;
1133     }
1134   }
1135   GST_OBJECT_UNLOCK (vagg);
1136
1137   if (best_fps_n <= 0 || best_fps_d <= 0 || best_fps == 0.0) {
1138     best_fps_n = 25;
1139     best_fps_d = 1;
1140     best_fps = 25.0;
1141   }
1142
1143   s = gst_caps_get_structure (ret, 0);
1144   gst_structure_fixate_field_nearest_int (s, "width", best_width);
1145   gst_structure_fixate_field_nearest_int (s, "height", best_height);
1146   gst_structure_fixate_field_nearest_fraction (s, "framerate", best_fps_n,
1147       best_fps_d);
1148   ret = gst_caps_fixate (ret);
1149
1150   return ret;
1151 }
1152
1153 static gboolean
1154 _reset_pad_gl (GstElement * agg, GstPad * aggpad, gpointer udata)
1155 {
1156   const GstGLFuncs *gl = GST_GL_BASE_MIXER (agg)->context->gl_vtable;
1157   GstGLVideoMixerPad *pad = GST_GL_VIDEO_MIXER_PAD (aggpad);
1158
1159   if (pad->vertex_buffer) {
1160     gl->DeleteBuffers (1, &pad->vertex_buffer);
1161     pad->vertex_buffer = 0;
1162   }
1163
1164   return TRUE;
1165 }
1166
1167 static void
1168 _reset_gl (GstGLContext * context, GstGLVideoMixer * video_mixer)
1169 {
1170   const GstGLFuncs *gl = GST_GL_BASE_MIXER (video_mixer)->context->gl_vtable;
1171
1172   if (video_mixer->vao) {
1173     gl->DeleteVertexArrays (1, &video_mixer->vao);
1174     video_mixer->vao = 0;
1175   }
1176
1177   if (video_mixer->vbo_indices) {
1178     gl->DeleteBuffers (1, &video_mixer->vbo_indices);
1179     video_mixer->vbo_indices = 0;
1180   }
1181
1182   if (video_mixer->checker_vbo) {
1183     gl->DeleteBuffers (1, &video_mixer->checker_vbo);
1184     video_mixer->checker_vbo = 0;
1185   }
1186
1187   gst_element_foreach_sink_pad (GST_ELEMENT (video_mixer), _reset_pad_gl, NULL);
1188 }
1189
1190 static gboolean
1191 gst_gl_video_mixer_set_caps (GstGLMixer * mixer, GstCaps * outcaps)
1192 {
1193   GstGLVideoMixer *video_mixer = GST_GL_VIDEO_MIXER (mixer);
1194
1195   /* need reconfigure output geometry */
1196   video_mixer->output_geo_change = TRUE;
1197
1198   return TRUE;
1199 }
1200
1201 static void
1202 gst_gl_video_mixer_gl_stop (GstGLBaseMixer * base_mix)
1203 {
1204   GstGLVideoMixer *video_mixer = GST_GL_VIDEO_MIXER (base_mix);
1205
1206   gst_clear_object (&video_mixer->shader);
1207   gst_clear_object (&video_mixer->checker);
1208
1209   _reset_gl (base_mix->context, video_mixer);
1210
1211   GST_GL_BASE_MIXER_CLASS (parent_class)->gl_stop (base_mix);
1212 }
1213
1214 static gboolean
1215 gst_gl_video_mixer_gl_start (GstGLBaseMixer * base_mix)
1216 {
1217   GstGLVideoMixer *video_mixer = GST_GL_VIDEO_MIXER (base_mix);
1218
1219   if (!video_mixer->shader) {
1220     gchar *frag_str = g_strdup_printf ("%s%s",
1221         gst_gl_shader_string_get_highest_precision (base_mix->context,
1222             GST_GLSL_VERSION_NONE,
1223             GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY),
1224         video_mixer_f_src);
1225
1226     gst_gl_context_gen_shader (base_mix->context,
1227         gst_gl_shader_string_vertex_mat4_vertex_transform,
1228         frag_str, &video_mixer->shader);
1229     g_free (frag_str);
1230   }
1231
1232   return GST_GL_BASE_MIXER_CLASS (parent_class)->gl_start (base_mix);
1233 }
1234
1235 static void
1236 _video_mixer_process_gl (GstGLContext * context, GstGLVideoMixer * video_mixer)
1237 {
1238   GstGLMixer *mixer = GST_GL_MIXER (video_mixer);
1239
1240   gst_gl_framebuffer_draw_to_texture (mixer->fbo, video_mixer->out_tex,
1241       gst_gl_video_mixer_callback, video_mixer);
1242 }
1243
1244 static gboolean
1245 gst_gl_video_mixer_process_textures (GstGLMixer * mix, GstGLMemory * out_tex)
1246 {
1247   GstGLVideoMixer *video_mixer = GST_GL_VIDEO_MIXER (mix);
1248   GstGLContext *context = GST_GL_BASE_MIXER (mix)->context;
1249
1250   video_mixer->out_tex = out_tex;
1251
1252   gst_gl_context_thread_add (context,
1253       (GstGLContextThreadFunc) _video_mixer_process_gl, video_mixer);
1254
1255   return TRUE;
1256 }
1257
1258 static const GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
1259
1260 static void
1261 _init_vbo_indices (GstGLVideoMixer * mixer)
1262 {
1263   const GstGLFuncs *gl = GST_GL_BASE_MIXER (mixer)->context->gl_vtable;
1264
1265   if (!mixer->vbo_indices) {
1266     gl->GenBuffers (1, &mixer->vbo_indices);
1267     gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, mixer->vbo_indices);
1268     gl->BufferData (GL_ELEMENT_ARRAY_BUFFER, sizeof (indices), indices,
1269         GL_STATIC_DRAW);
1270   }
1271 }
1272
1273 static gboolean
1274 _draw_checker_background (GstGLVideoMixer * video_mixer)
1275 {
1276   GstGLMixer *mixer = GST_GL_MIXER (video_mixer);
1277   const GstGLFuncs *gl = GST_GL_BASE_MIXER (mixer)->context->gl_vtable;
1278   gint attr_position_loc = 0;
1279
1280   /* *INDENT-OFF* */
1281   gfloat v_vertices[] = {
1282     -1.0,-1.0, 0.0f,
1283      1.0,-1.0, 0.0f,
1284      1.0, 1.0, 0.0f,
1285     -1.0, 1.0, 0.0f,
1286   };
1287   /* *INDENT-ON* */
1288
1289   if (!video_mixer->checker) {
1290     gchar *frag_str;
1291
1292     frag_str =
1293         g_strdup_printf ("%s%s",
1294         gst_gl_shader_string_get_highest_precision (GST_GL_BASE_MIXER
1295             (mixer)->context, GST_GLSL_VERSION_NONE,
1296             GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY),
1297         checker_f_src);
1298
1299     if (!gst_gl_context_gen_shader (GST_GL_BASE_MIXER (mixer)->context,
1300             checker_v_src, frag_str, &video_mixer->checker)) {
1301       g_free (frag_str);
1302       return FALSE;
1303     }
1304     g_free (frag_str);
1305   }
1306
1307   gst_gl_shader_use (video_mixer->checker);
1308   attr_position_loc =
1309       gst_gl_shader_get_attribute_location (video_mixer->checker, "a_position");
1310
1311   _init_vbo_indices (video_mixer);
1312
1313   if (!video_mixer->checker_vbo) {
1314     gl->GenBuffers (1, &video_mixer->checker_vbo);
1315     gl->BindBuffer (GL_ARRAY_BUFFER, video_mixer->checker_vbo);
1316     gl->BufferData (GL_ARRAY_BUFFER, 4 * 3 * sizeof (GLfloat), v_vertices,
1317         GL_STATIC_DRAW);
1318   } else {
1319     gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, video_mixer->vbo_indices);
1320     gl->BindBuffer (GL_ARRAY_BUFFER, video_mixer->checker_vbo);
1321   }
1322
1323   gl->VertexAttribPointer (attr_position_loc, 3, GL_FLOAT,
1324       GL_FALSE, 3 * sizeof (GLfloat), (void *) 0);
1325
1326   gl->EnableVertexAttribArray (attr_position_loc);
1327
1328   gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
1329
1330   gl->DisableVertexAttribArray (attr_position_loc);
1331   gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);
1332   gl->BindBuffer (GL_ARRAY_BUFFER, 0);
1333
1334   return TRUE;
1335 }
1336
1337 static gboolean
1338 _draw_background (GstGLVideoMixer * video_mixer)
1339 {
1340   GstGLMixer *mixer = GST_GL_MIXER (video_mixer);
1341   const GstGLFuncs *gl = GST_GL_BASE_MIXER (mixer)->context->gl_vtable;
1342
1343   switch (video_mixer->background) {
1344     case GST_GL_VIDEO_MIXER_BACKGROUND_BLACK:
1345       gl->ClearColor (0.0, 0.0, 0.0, 1.0);
1346       gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1347       break;
1348     case GST_GL_VIDEO_MIXER_BACKGROUND_WHITE:
1349       gl->ClearColor (1.0, 1.0, 1.0, 1.0);
1350       gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1351       break;
1352     case GST_GL_VIDEO_MIXER_BACKGROUND_TRANSPARENT:
1353       gl->ClearColor (0.0, 0.0, 0.0, 0.0);
1354       gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1355       break;
1356     case GST_GL_VIDEO_MIXER_BACKGROUND_CHECKER:
1357       return _draw_checker_background (video_mixer);
1358       break;
1359     default:
1360       break;
1361   }
1362
1363   return TRUE;
1364 }
1365
1366 static guint
1367 _blend_equation_to_gl (GstGLVideoMixerBlendEquation equation)
1368 {
1369   switch (equation) {
1370     case GST_GL_VIDEO_MIXER_BLEND_EQUATION_ADD:
1371       return GL_FUNC_ADD;
1372     case GST_GL_VIDEO_MIXER_BLEND_EQUATION_SUBTRACT:
1373       return GL_FUNC_SUBTRACT;
1374     case GST_GL_VIDEO_MIXER_BLEND_EQUATION_REVERSE_SUBTRACT:
1375       return GL_FUNC_REVERSE_SUBTRACT;
1376     default:
1377       g_assert_not_reached ();
1378       return 0;
1379   }
1380 }
1381
1382 static guint
1383 _blend_function_to_gl (GstGLVideoMixerBlendFunction equation)
1384 {
1385   switch (equation) {
1386     case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ZERO:
1387       return GL_ZERO;
1388     case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE:
1389       return GL_ONE;
1390     case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_SRC_COLOR:
1391       return GL_SRC_COLOR;
1392     case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_SRC_COLOR:
1393       return GL_ONE_MINUS_SRC_COLOR;
1394     case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_DST_COLOR:
1395       return GL_DST_COLOR;
1396     case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_DST_COLOR:
1397       return GL_ONE_MINUS_DST_COLOR;
1398     case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_SRC_ALPHA:
1399       return GL_SRC_ALPHA;
1400     case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_SRC_ALPHA:
1401       return GL_ONE_MINUS_SRC_ALPHA;
1402     case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_DST_ALPHA:
1403       return GL_DST_ALPHA;
1404     case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_DST_ALPHA:
1405       return GL_ONE_MINUS_DST_ALPHA;
1406     case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_CONSTANT_COLOR:
1407       return GL_CONSTANT_COLOR;
1408     case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_CONSTANT_COLOR:
1409       return GL_ONE_MINUS_CONSTANT_COLOR;
1410     case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_CONSTANT_ALPHA:
1411       return GL_CONSTANT_ALPHA;
1412     case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ONE_MINUS_CONSTANT_ALPHA:
1413       return GL_ONE_MINUS_CONSTANT_ALPHA;
1414     case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_SRC_ALPHA_SATURATE:
1415       return GL_SRC_ALPHA_SATURATE;
1416     default:
1417       g_assert_not_reached ();
1418       return 0;
1419   }
1420 }
1421
1422 static gboolean
1423 _set_blend_state (GstGLVideoMixer * video_mixer, GstGLVideoMixerPad * mix_pad)
1424 {
1425   const GstGLFuncs *gl = GST_GL_BASE_MIXER (video_mixer)->context->gl_vtable;
1426   gboolean require_separate = FALSE;
1427   guint gl_func_src_rgb, gl_func_src_alpha, gl_func_dst_rgb, gl_func_dst_alpha;
1428   guint gl_equation_rgb, gl_equation_alpha;
1429
1430   require_separate =
1431       mix_pad->blend_equation_rgb != mix_pad->blend_equation_alpha
1432       || mix_pad->blend_function_src_rgb != mix_pad->blend_function_src_alpha
1433       || mix_pad->blend_function_dst_rgb != mix_pad->blend_function_dst_alpha;
1434
1435   if (require_separate && (!gl->BlendFuncSeparate
1436           || !gl->BlendEquationSeparate)) {
1437     GST_ERROR_OBJECT (mix_pad,
1438         "separated blend equations/functions requested however "
1439         "glBlendFuncSeparate or glBlendEquationSeparate not available");
1440     return FALSE;
1441   }
1442
1443   if (mix_pad->blend_function_dst_rgb ==
1444       GST_GL_VIDEO_MIXER_BLEND_FUNCTION_SRC_ALPHA_SATURATE) {
1445     GST_ERROR_OBJECT (mix_pad,
1446         "Destination RGB blend function cannot be \'SRC_ALPHA_SATURATE\'");
1447     return FALSE;
1448   }
1449
1450   if (mix_pad->blend_function_dst_alpha ==
1451       GST_GL_VIDEO_MIXER_BLEND_FUNCTION_SRC_ALPHA_SATURATE) {
1452     GST_ERROR_OBJECT (mix_pad,
1453         "Destination alpha blend function cannot be \'SRC_ALPHA_SATURATE\'");
1454     return FALSE;
1455   }
1456
1457   gl_equation_rgb = _blend_equation_to_gl (mix_pad->blend_equation_rgb);
1458   gl_equation_alpha = _blend_equation_to_gl (mix_pad->blend_equation_alpha);
1459
1460   gl_func_src_rgb = _blend_function_to_gl (mix_pad->blend_function_src_rgb);
1461   gl_func_src_alpha = _blend_function_to_gl (mix_pad->blend_function_src_alpha);
1462   gl_func_dst_rgb = _blend_function_to_gl (mix_pad->blend_function_dst_rgb);
1463   gl_func_dst_alpha = _blend_function_to_gl (mix_pad->blend_function_dst_alpha);
1464
1465   if (gl->BlendEquationSeparate)
1466     gl->BlendEquationSeparate (gl_equation_rgb, gl_equation_alpha);
1467   else
1468     gl->BlendEquation (gl_equation_rgb);
1469
1470   if (gl->BlendFuncSeparate)
1471     gl->BlendFuncSeparate (gl_func_src_rgb, gl_func_dst_rgb, gl_func_src_alpha,
1472         gl_func_dst_alpha);
1473   else
1474     gl->BlendFunc (gl_func_src_rgb, gl_func_dst_rgb);
1475
1476   gl->BlendColor (mix_pad->blend_constant_color_red,
1477       mix_pad->blend_constant_color_green, mix_pad->blend_constant_color_blue,
1478       mix_pad->blend_constant_color_alpha);
1479
1480   return TRUE;
1481 }
1482
1483 /* opengl scene, params: input texture (not the output mixer->texture) */
1484 static gboolean
1485 gst_gl_video_mixer_callback (gpointer stuff)
1486 {
1487   GstGLVideoMixer *video_mixer = GST_GL_VIDEO_MIXER (stuff);
1488   GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (stuff);
1489   GstGLMixer *mixer = GST_GL_MIXER (video_mixer);
1490   GstGLFuncs *gl = GST_GL_BASE_MIXER (mixer)->context->gl_vtable;
1491   GLint attr_position_loc = 0;
1492   GLint attr_texture_loc = 0;
1493   guint out_width, out_height;
1494   GList *walk;
1495
1496   out_width = GST_VIDEO_INFO_WIDTH (&vagg->info);
1497   out_height = GST_VIDEO_INFO_HEIGHT (&vagg->info);
1498
1499   gst_gl_context_clear_shader (GST_GL_BASE_MIXER (mixer)->context);
1500   gl->BindTexture (GL_TEXTURE_2D, 0);
1501
1502   gl->Disable (GL_DEPTH_TEST);
1503   gl->Disable (GL_CULL_FACE);
1504
1505   if (gl->GenVertexArrays) {
1506     if (!video_mixer->vao)
1507       gl->GenVertexArrays (1, &video_mixer->vao);
1508     gl->BindVertexArray (video_mixer->vao);
1509   }
1510
1511   if (!_draw_background (video_mixer))
1512     return FALSE;
1513
1514   gst_gl_shader_use (video_mixer->shader);
1515
1516   attr_position_loc =
1517       gst_gl_shader_get_attribute_location (video_mixer->shader, "a_position");
1518   attr_texture_loc =
1519       gst_gl_shader_get_attribute_location (video_mixer->shader, "a_texcoord");
1520
1521   gl->Enable (GL_BLEND);
1522
1523   GST_OBJECT_LOCK (video_mixer);
1524   walk = GST_ELEMENT (video_mixer)->sinkpads;
1525   while (walk) {
1526     GstGLMixerPad *mix_pad = walk->data;
1527     GstGLVideoMixerPad *pad = walk->data;
1528     GstVideoAggregatorPad *vagg_pad = walk->data;
1529     GstVideoInfo *v_info;
1530     guint in_tex;
1531     guint in_width, in_height;
1532
1533     /* *INDENT-OFF* */
1534     gfloat v_vertices[] = {
1535       -1.0,-1.0, 0.0f, 0.0f, 0.0f,
1536        1.0,-1.0, 0.0f, 1.0f, 0.0f,
1537        1.0, 1.0, 0.0f, 1.0f, 1.0f,
1538       -1.0, 1.0, 0.0f, 0.0f, 1.0f,
1539     };
1540     /* *INDENT-ON* */
1541
1542     v_info = &GST_VIDEO_AGGREGATOR_PAD (pad)->info;
1543     in_width = GST_VIDEO_INFO_WIDTH (v_info);
1544     in_height = GST_VIDEO_INFO_HEIGHT (v_info);
1545
1546     if (!mix_pad->current_texture || in_width <= 0 || in_height <= 0
1547         || pad->alpha == 0.0f) {
1548       GST_DEBUG ("skipping texture:%u pad:%p width:%u height:%u alpha:%f",
1549           mix_pad->current_texture, pad, in_width, in_height, pad->alpha);
1550       walk = g_list_next (walk);
1551       continue;
1552     }
1553
1554     if (!_set_blend_state (video_mixer, pad)) {
1555       GST_FIXME_OBJECT (pad, "skipping due to incorrect blend parameters");
1556       walk = g_list_next (walk);
1557       continue;
1558     }
1559
1560     in_tex = mix_pad->current_texture;
1561
1562     _init_vbo_indices (video_mixer);
1563
1564     if (video_mixer->output_geo_change
1565         || pad->geometry_change || !pad->vertex_buffer) {
1566       gint pad_width, pad_height;
1567       gfloat w, h;
1568
1569       _mixer_pad_get_output_size (video_mixer, pad,
1570           GST_VIDEO_INFO_PAR_N (&vagg->info),
1571           GST_VIDEO_INFO_PAR_D (&vagg->info), &pad_width, &pad_height);
1572
1573       w = ((gfloat) pad_width / (gfloat) out_width);
1574       h = ((gfloat) pad_height / (gfloat) out_height);
1575
1576       pad->m_matrix[0] = w;
1577       pad->m_matrix[5] = h;
1578       pad->m_matrix[12] =
1579           2. * (gfloat) pad->xpos / (gfloat) out_width - (1. - w);
1580       pad->m_matrix[13] =
1581           2. * (gfloat) pad->ypos / (gfloat) out_height - (1. - h);
1582
1583       GST_TRACE ("processing texture:%u dimensions:%ux%u, at %f,%f %fx%f with "
1584           "alpha:%f", in_tex, in_width, in_height, pad->m_matrix[12],
1585           pad->m_matrix[13], pad->m_matrix[0], pad->m_matrix[5], pad->alpha);
1586
1587       if (!pad->vertex_buffer)
1588         gl->GenBuffers (1, &pad->vertex_buffer);
1589
1590       gl->BindBuffer (GL_ARRAY_BUFFER, pad->vertex_buffer);
1591       gl->BufferData (GL_ARRAY_BUFFER, 4 * 5 * sizeof (GLfloat), v_vertices,
1592           GL_STATIC_DRAW);
1593
1594       pad->geometry_change = FALSE;
1595     } else {
1596       gl->BindBuffer (GL_ARRAY_BUFFER, pad->vertex_buffer);
1597     }
1598     gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, video_mixer->vbo_indices);
1599
1600     gl->ActiveTexture (GL_TEXTURE0);
1601     gl->BindTexture (GL_TEXTURE_2D, in_tex);
1602     gst_gl_shader_set_uniform_1i (video_mixer->shader, "texture", 0);
1603     gst_gl_shader_set_uniform_1f (video_mixer->shader, "alpha", pad->alpha);
1604
1605     {
1606       GstVideoAffineTransformationMeta *af_meta;
1607       gfloat matrix[16];
1608       gfloat af_matrix[16];
1609       GstBuffer *buffer =
1610           gst_video_aggregator_pad_get_current_buffer (vagg_pad);
1611
1612       af_meta = gst_buffer_get_video_affine_transformation_meta (buffer);
1613       gst_gl_get_affine_transformation_meta_as_ndc_ext (af_meta, af_matrix);
1614       gst_gl_multiply_matrix4 (af_matrix, pad->m_matrix, matrix);
1615       gst_gl_shader_set_uniform_matrix_4fv (video_mixer->shader,
1616           "u_transformation", 1, FALSE, matrix);
1617     }
1618
1619     gl->EnableVertexAttribArray (attr_position_loc);
1620     gl->EnableVertexAttribArray (attr_texture_loc);
1621
1622     gl->VertexAttribPointer (attr_position_loc, 3, GL_FLOAT,
1623         GL_FALSE, 5 * sizeof (GLfloat), (void *) 0);
1624
1625     gl->VertexAttribPointer (attr_texture_loc, 2, GL_FLOAT,
1626         GL_FALSE, 5 * sizeof (GLfloat), (void *) (3 * sizeof (GLfloat)));
1627
1628     gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
1629
1630     walk = g_list_next (walk);
1631   }
1632
1633   video_mixer->output_geo_change = FALSE;
1634   GST_OBJECT_UNLOCK (video_mixer);
1635
1636   if (gl->GenVertexArrays) {
1637     gl->BindVertexArray (0);
1638   } else {
1639     gl->DisableVertexAttribArray (attr_position_loc);
1640     gl->DisableVertexAttribArray (attr_texture_loc);
1641
1642     gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);
1643     gl->BindBuffer (GL_ARRAY_BUFFER, 0);
1644     gl->BindTexture (GL_TEXTURE_2D, 0);
1645   }
1646
1647   gl->Disable (GL_BLEND);
1648
1649   gst_gl_context_clear_shader (GST_GL_BASE_MIXER (mixer)->context);
1650
1651   return TRUE;
1652 }
1653
1654 /* GstChildProxy implementation */
1655 static GObject *
1656 gst_gl_video_mixer_child_proxy_get_child_by_index (GstChildProxy * child_proxy,
1657     guint index)
1658 {
1659   GstGLVideoMixer *gl_video_mixer = GST_GL_VIDEO_MIXER (child_proxy);
1660   GObject *obj = NULL;
1661
1662   GST_OBJECT_LOCK (gl_video_mixer);
1663   obj = g_list_nth_data (GST_ELEMENT_CAST (gl_video_mixer)->sinkpads, index);
1664   if (obj)
1665     gst_object_ref (obj);
1666   GST_OBJECT_UNLOCK (gl_video_mixer);
1667
1668   return obj;
1669 }
1670
1671 static guint
1672 gst_gl_video_mixer_child_proxy_get_children_count (GstChildProxy * child_proxy)
1673 {
1674   guint count = 0;
1675   GstGLVideoMixer *gl_video_mixer = GST_GL_VIDEO_MIXER (child_proxy);
1676
1677   GST_OBJECT_LOCK (gl_video_mixer);
1678   count = GST_ELEMENT_CAST (gl_video_mixer)->numsinkpads;
1679   GST_OBJECT_UNLOCK (gl_video_mixer);
1680   GST_INFO_OBJECT (gl_video_mixer, "Children Count: %d", count);
1681
1682   return count;
1683 }
1684
1685 static void
1686 gst_gl_video_mixer_child_proxy_init (gpointer g_iface, gpointer iface_data)
1687 {
1688   GstChildProxyInterface *iface = g_iface;
1689
1690   iface->get_child_by_index = gst_gl_video_mixer_child_proxy_get_child_by_index;
1691   iface->get_children_count = gst_gl_video_mixer_child_proxy_get_children_count;
1692 }