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