3 * Copyright (C) 2009 Julien Isorce <julien.isorce@gmail.com>
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.
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.
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.
22 * SECTION:element-glvideomixer
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.
29 * <title>Examples</title>
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.
46 #include <gst/video/gstvideoaffinetransformationmeta.h>
48 #include "gstglvideomixer.h"
49 #include "gstglmixerbin.h"
51 #define GST_CAT_DEFAULT gst_gl_video_mixer_debug
52 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
54 #define GST_GL_TYPE_VIDEO_MIXER_BACKGROUND (gst_gl_video_mixer_background_get_type())
56 gst_gl_video_mixer_background_get_type (void)
58 static GType mixer_background_type = 0;
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"},
69 if (!mixer_background_type) {
70 mixer_background_type =
71 g_enum_register_static ("GstGLVideoMixerBackground", mixer_background);
73 return mixer_background_type;
76 #define GST_TYPE_GL_VIDEO_MIXER_BLEND_EQUATION (gst_gl_video_mixer_blend_equation_get_type())
78 gst_gl_video_mixer_blend_equation_get_type (void)
80 static GType mixer_blend_equation_type = 0;
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",
90 if (!mixer_blend_equation_type) {
91 mixer_blend_equation_type =
92 g_enum_register_static ("GstGLVideoMixerBlendEquation",
93 mixer_blend_equations);
95 return mixer_blend_equation_type;
98 #define GST_TYPE_GL_VIDEO_MIXER_BLEND_FUNCTION (gst_gl_video_mixer_blend_function_get_type())
100 gst_gl_video_mixer_blend_function_get_type (void)
102 static GType mixer_blend_function_type = 0;
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",
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",
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",
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",
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"},
134 if (!mixer_blend_function_type) {
135 mixer_blend_function_type =
136 g_enum_register_static ("GstGLVideoMixerBlendFunction",
139 return mixer_blend_function_type;
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
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,
175 PROP_INPUT_IGNORE_EOS,
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);
183 typedef struct _GstGLVideoMixerInput GstGLVideoMixerInput;
184 typedef GstGhostPadClass GstGLVideoMixerInputClass;
186 struct _GstGLVideoMixerInput
195 GType gst_gl_video_mixer_input_get_type (void);
196 G_DEFINE_TYPE (GstGLVideoMixerInput, gst_gl_video_mixer_input,
200 gst_gl_video_mixer_input_init (GstGLVideoMixerInput * self)
205 gst_gl_video_mixer_input_class_init (GstGLVideoMixerInputClass * klass)
207 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
209 gobject_class->set_property = gst_gl_video_mixer_input_set_property;
210 gobject_class->get_property = gst_gl_video_mixer_input_get_property;
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,
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,
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,
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,
305 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
309 gst_gl_video_mixer_input_get_property (GObject * object, guint prop_id,
310 GValue * value, GParamSpec * pspec)
312 GstGLVideoMixerInput *self = (GstGLVideoMixerInput *) object;
315 g_object_get_property (G_OBJECT (self->mixer_pad), pspec->name, value);
319 gst_gl_video_mixer_input_set_property (GObject * object, guint prop_id,
320 const GValue * value, GParamSpec * pspec)
322 GstGLVideoMixerInput *self = (GstGLVideoMixerInput *) object;
325 g_object_set_property (G_OBJECT (self->mixer_pad), pspec->name, value);
329 _create_video_mixer_input (GstGLMixerBin * self, GstPad * mixer_pad)
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),
336 if (!gst_ghost_pad_construct (GST_GHOST_PAD (input))) {
337 gst_object_unref (input);
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");
374 input->mixer_pad = mixer_pad;
376 return GST_GHOST_PAD (input);
384 #define DEFAULT_BACKGROUND GST_GL_VIDEO_MIXER_BACKGROUND_CHECKER
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);
391 typedef GstGLMixerBin GstGLVideoMixerBin;
392 typedef GstGLMixerBinClass GstGLVideoMixerBinClass;
394 G_DEFINE_TYPE (GstGLVideoMixerBin, gst_gl_video_mixer_bin,
395 GST_TYPE_GL_MIXER_BIN);
398 gst_gl_video_mixer_bin_init (GstGLVideoMixerBin * self)
400 GstGLMixerBin *mix_bin = GST_GL_MIXER_BIN (self);
402 gst_gl_mixer_bin_finish_init_with_element (mix_bin,
403 g_object_new (GST_TYPE_GL_VIDEO_MIXER, NULL));
407 gst_gl_video_mixer_bin_class_init (GstGLVideoMixerBinClass * klass)
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);
413 mixer_class->create_input_pad = _create_video_mixer_input;
415 gobject_class->set_property = gst_gl_video_mixer_bin_set_property;
416 gobject_class->get_property = gst_gl_video_mixer_bin_get_property;
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));
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>");
429 gst_gl_video_mixer_bin_get_property (GObject * object, guint prop_id,
430 GValue * value, GParamSpec * pspec)
432 GstGLMixerBin *self = GST_GL_MIXER_BIN (object);
435 g_object_get_property (G_OBJECT (self->mixer), pspec->name, value);
439 gst_gl_video_mixer_bin_set_property (GObject * object, guint prop_id,
440 const GValue * value, GParamSpec * pspec)
442 GstGLMixerBin *self = GST_GL_MIXER_BIN (object);
445 g_object_set_property (G_OBJECT (self->mixer), pspec->name, value);
455 GST_DEBUG_CATEGORY_INIT (gst_gl_video_mixer_debug, "glvideomixer", 0, "glvideomixer element");
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,
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);
466 static GstCaps *_update_caps (GstVideoAggregator * vagg, GstCaps * caps,
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,
472 static void gst_gl_video_mixer_reset (GstGLMixer * mixer);
473 static gboolean gst_gl_video_mixer_init_shader (GstGLMixer * mixer,
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);
482 /* fragment source */
483 static const gchar *video_mixer_f_src =
485 "precision mediump float;\n"
487 "uniform sampler2D texture; \n"
488 "uniform float alpha;\n"
489 "varying vec2 v_texcoord; \n"
492 " vec4 rgba = texture2D(texture, v_texcoord);\n"
493 " gl_FragColor = vec4(rgba.rgb, rgba.a * alpha);\n"
496 /* checker vertex source */
497 static const gchar *checker_v_src =
498 "attribute vec4 a_position;\n"
501 " gl_Position = a_position;\n"
504 /* checker fragment source */
505 static const gchar *checker_f_src =
507 "precision mediump float;\n"
509 "const float blocksize = 8.0;\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"
518 " gl_FragColor = high;\n"
520 " if (mod(gl_FragCoord.y, blocksize * 2.0) < blocksize)\n"
521 " gl_FragColor = low;\n"
523 " gl_FragColor = high;\n"
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))
538 typedef struct _GstGLVideoMixerPad GstGLVideoMixerPad;
539 typedef struct _GstGLVideoMixerPadClass GstGLVideoMixerPadClass;
540 typedef struct _GstGLVideoMixerCollect GstGLVideoMixerCollect;
543 * GstGLVideoMixerPad:
545 * The opaque #GstGLVideoMixerPad structure.
547 struct _GstGLVideoMixerPad
549 GstGLMixerPad parent;
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;
568 gboolean geometry_change;
569 GLuint vertex_buffer;
572 struct _GstGLVideoMixerPadClass
574 GstGLMixerPadClass parent_class;
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);
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);
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,
607 gst_gl_video_mixer_pad_init (GstGLVideoMixerPad * pad)
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;
619 gst_gl_video_mixer_pad_class_init (GstGLVideoMixerPadClass * klass)
621 GObjectClass *gobject_class = (GObjectClass *) klass;
623 gobject_class->set_property = gst_gl_video_mixer_pad_set_property;
624 gobject_class->get_property = gst_gl_video_mixer_pad_get_property;
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,
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,
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,
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,
710 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
714 gst_gl_video_mixer_pad_get_property (GObject * object, guint prop_id,
715 GValue * value, GParamSpec * pspec)
717 GstGLVideoMixerPad *pad = GST_GL_VIDEO_MIXER_PAD (object);
721 g_value_set_int (value, pad->xpos);
724 g_value_set_int (value, pad->ypos);
727 g_value_set_int (value, pad->width);
729 case PROP_PAD_HEIGHT:
730 g_value_set_int (value, pad->height);
733 g_value_set_double (value, pad->alpha);
735 case PROP_PAD_BLEND_EQUATION_RGB:
736 g_value_set_enum (value, pad->blend_equation_rgb);
738 case PROP_PAD_BLEND_EQUATION_ALPHA:
739 g_value_set_enum (value, pad->blend_equation_alpha);
741 case PROP_PAD_BLEND_FUNCTION_SRC_RGB:
742 g_value_set_enum (value, pad->blend_function_src_rgb);
744 case PROP_PAD_BLEND_FUNCTION_SRC_ALPHA:
745 g_value_set_enum (value, pad->blend_function_src_alpha);
747 case PROP_PAD_BLEND_FUNCTION_DST_RGB:
748 g_value_set_enum (value, pad->blend_function_dst_rgb);
750 case PROP_PAD_BLEND_FUNCTION_DST_ALPHA:
751 g_value_set_enum (value, pad->blend_function_dst_alpha);
753 case PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_RED:
754 g_value_set_double (value, pad->blend_constant_color_red);
756 case PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_GREEN:
757 g_value_set_double (value, pad->blend_constant_color_green);
759 case PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_BLUE:
760 g_value_set_double (value, pad->blend_constant_color_blue);
762 case PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_ALPHA:
763 g_value_set_double (value, pad->blend_constant_color_alpha);
766 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
772 gst_gl_video_mixer_pad_set_property (GObject * object, guint prop_id,
773 const GValue * value, GParamSpec * pspec)
775 GstGLVideoMixerPad *pad = GST_GL_VIDEO_MIXER_PAD (object);
776 GstGLMixer *mix = GST_GL_MIXER (gst_pad_get_parent (GST_PAD (pad)));
780 pad->xpos = g_value_get_int (value);
781 pad->geometry_change = TRUE;
784 pad->ypos = g_value_get_int (value);
785 pad->geometry_change = TRUE;
788 pad->width = g_value_get_int (value);
789 pad->geometry_change = TRUE;
791 case PROP_PAD_HEIGHT:
792 pad->height = g_value_get_int (value);
793 pad->geometry_change = TRUE;
796 pad->alpha = g_value_get_double (value);
798 case PROP_PAD_BLEND_EQUATION_RGB:
799 pad->blend_equation_rgb = g_value_get_enum (value);
801 case PROP_PAD_BLEND_EQUATION_ALPHA:
802 pad->blend_equation_alpha = g_value_get_enum (value);
804 case PROP_PAD_BLEND_FUNCTION_SRC_RGB:
805 pad->blend_function_src_rgb = g_value_get_enum (value);
807 case PROP_PAD_BLEND_FUNCTION_SRC_ALPHA:
808 pad->blend_function_src_alpha = g_value_get_enum (value);
810 case PROP_PAD_BLEND_FUNCTION_DST_RGB:
811 pad->blend_function_dst_rgb = g_value_get_enum (value);
813 case PROP_PAD_BLEND_FUNCTION_DST_ALPHA:
814 pad->blend_function_dst_alpha = g_value_get_enum (value);
816 case PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_RED:
817 pad->blend_constant_color_red = g_value_get_double (value);
819 case PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_GREEN:
820 pad->blend_constant_color_green = g_value_get_double (value);
822 case PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_BLUE:
823 pad->blend_constant_color_blue = g_value_get_double (value);
825 case PROP_PAD_BLEND_FUNCTION_CONSTANT_COLOR_ALPHA:
826 pad->blend_constant_color_alpha = g_value_get_double (value);
829 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
833 gst_object_unref (mix);
837 _del_buffer (GstGLContext * context, GLuint * pBuffer)
839 context->gl_vtable->DeleteBuffers (1, pBuffer);
843 gst_gl_video_mixer_release_pad (GstElement * element, GstPad * p)
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;
852 GST_ELEMENT_CLASS (g_type_class_peek_parent (G_OBJECT_GET_CLASS (element)))
853 ->release_pad (element, p);
857 gst_gl_video_mixer_class_init (GstGLVideoMixerClass * klass)
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);
865 gobject_class = (GObjectClass *) klass;
866 element_class = GST_ELEMENT_CLASS (klass);
867 element_class->release_pad = gst_gl_video_mixer_release_pad;
869 gobject_class->set_property = gst_gl_video_mixer_set_property;
870 gobject_class->get_property = gst_gl_video_mixer_get_property;
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>");
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));
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;
886 vagg_class->update_caps = _update_caps;
887 vagg_class->fixate_caps = _fixate_caps;
889 agg_class->sinkpads_type = GST_TYPE_GL_VIDEO_MIXER_PAD;
891 mix_class->propose_allocation = gst_gl_video_mixer_propose_allocation;
893 GST_GL_BASE_MIXER_CLASS (klass)->supported_gl_api =
894 GST_GL_API_OPENGL | GST_GL_API_OPENGL3 | GST_GL_API_GLES2;
898 gst_gl_video_mixer_init (GstGLVideoMixer * video_mixer)
900 video_mixer->background = DEFAULT_BACKGROUND;
901 video_mixer->shader = NULL;
905 gst_gl_video_mixer_set_property (GObject * object, guint prop_id,
906 const GValue * value, GParamSpec * pspec)
908 GstGLVideoMixer *mixer = GST_GL_VIDEO_MIXER (object);
911 case PROP_BACKGROUND:
912 mixer->background = g_value_get_enum (value);
915 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
921 gst_gl_video_mixer_get_property (GObject * object, guint prop_id,
922 GValue * value, GParamSpec * pspec)
924 GstGLVideoMixer *mixer = GST_GL_VIDEO_MIXER (object);
927 case PROP_BACKGROUND:
928 g_value_set_enum (value, mixer->background);
931 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
937 gst_gl_video_mixer_propose_allocation (GstGLBaseMixer * base_mix,
938 GstGLBaseMixerPad * base_pad, GstQuery * decide_query, GstQuery * query)
940 if (!GST_GL_BASE_MIXER_CLASS (parent_class)->propose_allocation (base_mix,
941 base_pad, decide_query, query))
944 gst_query_add_allocation_meta (query,
945 GST_VIDEO_AFFINE_TRANSFORMATION_META_API_TYPE, 0);
951 _mixer_pad_get_output_size (GstGLVideoMixer * mix,
952 GstGLVideoMixerPad * mix_pad, gint out_par_n, gint out_par_d, gint * width,
955 GstVideoAggregatorPad *vagg_pad = GST_VIDEO_AGGREGATOR_PAD (mix_pad);
956 gint pad_width, pad_height;
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");
970 0 ? GST_VIDEO_INFO_WIDTH (&vagg_pad->info) : mix_pad->width;
973 0 ? GST_VIDEO_INFO_HEIGHT (&vagg_pad->info) : mix_pad->height;
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);
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);
987 pad_width = gst_util_uint64_scale_int (pad_height, dar_n, dar_d);
993 *height = pad_height;
997 _update_caps (GstVideoAggregator * vagg, GstCaps * caps, GstCaps * filter)
1002 ret = gst_caps_intersect (caps, filter);
1004 ret = gst_caps_ref (caps);
1011 _fixate_caps (GstVideoAggregator * vagg, GstCaps * caps)
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;
1017 gdouble best_fps = 0.;
1018 GstCaps *ret = NULL;
1022 ret = gst_caps_make_writable (caps);
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);
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);
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;
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);
1045 if (width == 0 || height == 0)
1048 this_width = width + MAX (mixer_pad->xpos, 0);
1049 this_height = height + MAX (mixer_pad->ypos, 0);
1051 if (best_width < this_width)
1052 best_width = this_width;
1053 if (best_height < this_height)
1054 best_height = this_height;
1059 gst_util_fraction_to_double (fps_n, fps_d, &cur_fps);
1061 if (best_fps < cur_fps) {
1067 GST_OBJECT_UNLOCK (vagg);
1069 if (best_fps_n <= 0 || best_fps_d <= 0 || best_fps == 0.0) {
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,
1080 ret = gst_caps_fixate (ret);
1086 _reset_pad_gl (GstAggregator * agg, GstAggregatorPad * aggpad, gpointer udata)
1088 const GstGLFuncs *gl = GST_GL_BASE_MIXER (agg)->context->gl_vtable;
1089 GstGLVideoMixerPad *pad = GST_GL_VIDEO_MIXER_PAD (aggpad);
1091 if (pad->vertex_buffer) {
1092 gl->DeleteBuffers (1, &pad->vertex_buffer);
1093 pad->vertex_buffer = 0;
1100 _reset_gl (GstGLContext * context, GstGLVideoMixer * video_mixer)
1102 const GstGLFuncs *gl = GST_GL_BASE_MIXER (video_mixer)->context->gl_vtable;
1104 if (video_mixer->vao) {
1105 gl->DeleteVertexArrays (1, &video_mixer->vao);
1106 video_mixer->vao = 0;
1109 if (video_mixer->vbo_indices) {
1110 gl->DeleteBuffers (1, &video_mixer->vbo_indices);
1111 video_mixer->vbo_indices = 0;
1114 if (video_mixer->checker_vbo) {
1115 gl->DeleteBuffers (1, &video_mixer->checker_vbo);
1116 video_mixer->checker_vbo = 0;
1119 gst_aggregator_iterate_sinkpads (GST_AGGREGATOR (video_mixer), _reset_pad_gl,
1124 gst_gl_video_mixer_reset (GstGLMixer * mixer)
1126 GstGLVideoMixer *video_mixer = GST_GL_VIDEO_MIXER (mixer);
1127 GstGLContext *context = GST_GL_BASE_MIXER (mixer)->context;
1129 GST_DEBUG_OBJECT (mixer, "context:%p", context);
1131 if (video_mixer->shader)
1132 gst_gl_context_del_shader (context, video_mixer->shader);
1133 video_mixer->shader = NULL;
1135 if (video_mixer->checker)
1136 gst_gl_context_del_shader (context, video_mixer->checker);
1137 video_mixer->checker = NULL;
1139 if (GST_GL_BASE_MIXER (mixer)->context)
1140 gst_gl_context_thread_add (context, (GstGLContextThreadFunc) _reset_gl,
1145 gst_gl_video_mixer_init_shader (GstGLMixer * mixer, GstCaps * outcaps)
1147 GstGLVideoMixer *video_mixer = GST_GL_VIDEO_MIXER (mixer);
1149 if (video_mixer->shader)
1150 gst_gl_context_del_shader (GST_GL_BASE_MIXER (mixer)->context,
1151 video_mixer->shader);
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);
1159 gst_gl_video_mixer_process_textures (GstGLMixer * mix, GstGLMemory * out_tex)
1161 GstGLVideoMixer *video_mixer = GST_GL_VIDEO_MIXER (mix);
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);
1172 static const GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
1175 _init_vbo_indices (GstGLVideoMixer * mixer)
1177 const GstGLFuncs *gl = GST_GL_BASE_MIXER (mixer)->context->gl_vtable;
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,
1188 _draw_checker_background (GstGLVideoMixer * video_mixer)
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;
1195 gfloat v_vertices[] = {
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))
1209 gst_gl_shader_use (video_mixer->checker);
1211 gst_gl_shader_get_attribute_location (video_mixer->checker, "a_position");
1213 _init_vbo_indices (video_mixer);
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,
1221 gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, video_mixer->vbo_indices);
1222 gl->BindBuffer (GL_ARRAY_BUFFER, video_mixer->checker_vbo);
1225 gl->VertexAttribPointer (attr_position_loc, 3, GL_FLOAT,
1226 GL_FALSE, 3 * sizeof (GLfloat), (void *) 0);
1228 gl->EnableVertexAttribArray (attr_position_loc);
1230 gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
1232 gl->DisableVertexAttribArray (attr_position_loc);
1233 gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);
1234 gl->BindBuffer (GL_ARRAY_BUFFER, 0);
1240 _draw_background (GstGLVideoMixer * video_mixer)
1242 GstGLMixer *mixer = GST_GL_MIXER (video_mixer);
1243 const GstGLFuncs *gl = GST_GL_BASE_MIXER (mixer)->context->gl_vtable;
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);
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);
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);
1258 case GST_GL_VIDEO_MIXER_BACKGROUND_CHECKER:
1259 return _draw_checker_background (video_mixer);
1269 _blend_equation_to_gl (GstGLVideoMixerBlendEquation equation)
1272 case GST_GL_VIDEO_MIXER_BLEND_EQUATION_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;
1279 g_assert_not_reached ();
1285 _blend_function_to_gl (GstGLVideoMixerBlendFunction equation)
1288 case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_ZERO:
1290 case GST_GL_VIDEO_MIXER_BLEND_FUNCTION_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;
1319 g_assert_not_reached ();
1325 _set_blend_state (GstGLVideoMixer * video_mixer, GstGLVideoMixerPad * mix_pad)
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;
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;
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");
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\'");
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\'");
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);
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);
1367 if (gl->BlendEquationSeparate)
1368 gl->BlendEquationSeparate (gl_equation_rgb, gl_equation_alpha);
1370 gl->BlendEquation (gl_equation_rgb);
1372 if (gl->BlendFuncSeparate)
1373 gl->BlendFuncSeparate (gl_func_src_rgb, gl_func_dst_rgb, gl_func_src_alpha,
1376 gl->BlendFunc (gl_func_src_rgb, gl_func_dst_rgb);
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);
1385 /* opengl scene, params: input texture (not the output mixer->texture) */
1387 gst_gl_video_mixer_callback (gpointer stuff)
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;
1398 out_width = GST_VIDEO_INFO_WIDTH (&vagg->info);
1399 out_height = GST_VIDEO_INFO_HEIGHT (&vagg->info);
1401 gst_gl_context_clear_shader (GST_GL_BASE_MIXER (mixer)->context);
1402 gl->BindTexture (GL_TEXTURE_2D, 0);
1404 gl->Disable (GL_DEPTH_TEST);
1405 gl->Disable (GL_CULL_FACE);
1407 if (gl->GenVertexArrays) {
1408 if (!video_mixer->vao)
1409 gl->GenVertexArrays (1, &video_mixer->vao);
1410 gl->BindVertexArray (video_mixer->vao);
1413 if (!_draw_background (video_mixer))
1416 gst_gl_shader_use (video_mixer->shader);
1419 gst_gl_shader_get_attribute_location (video_mixer->shader, "a_position");
1421 gst_gl_shader_get_attribute_location (video_mixer->shader, "a_texcoord");
1423 gl->Enable (GL_BLEND);
1425 GST_OBJECT_LOCK (video_mixer);
1426 walk = GST_ELEMENT (video_mixer)->sinkpads;
1428 GstGLMixerPad *mix_pad = walk->data;
1429 GstGLVideoMixerPad *pad = walk->data;
1430 GstVideoAggregatorPad *vagg_pad = walk->data;
1431 GstVideoInfo *v_info;
1433 guint in_width, in_height;
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,
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);
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);
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);
1462 in_tex = mix_pad->current_texture;
1464 _init_vbo_indices (video_mixer);
1466 if (pad->geometry_change || !pad->vertex_buffer) {
1467 gint pad_width, pad_height;
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);
1474 w = ((gfloat) pad_width / (gfloat) out_width);
1475 h = ((gfloat) pad_height / (gfloat) out_height);
1478 v_vertices[0] = v_vertices[15] =
1479 2.0f * (gfloat) pad->xpos / (gfloat) out_width - 1.0f;
1481 v_vertices[1] = v_vertices[6] =
1482 2.0f * (gfloat) pad->ypos / (gfloat) out_height - 1.0f;
1484 v_vertices[5] = v_vertices[10] = v_vertices[0] + 2.0f * w;
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);
1491 if (!pad->vertex_buffer)
1492 gl->GenBuffers (1, &pad->vertex_buffer);
1494 gl->BindBuffer (GL_ARRAY_BUFFER, pad->vertex_buffer);
1496 gl->BufferData (GL_ARRAY_BUFFER, 4 * 5 * sizeof (GLfloat), v_vertices,
1499 pad->geometry_change = FALSE;
1501 gl->BindBuffer (GL_ARRAY_BUFFER, pad->vertex_buffer);
1503 gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, video_mixer->vbo_indices);
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);
1511 GstVideoAffineTransformationMeta *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);
1521 gl->EnableVertexAttribArray (attr_position_loc);
1522 gl->EnableVertexAttribArray (attr_texture_loc);
1524 gl->VertexAttribPointer (attr_position_loc, 3, GL_FLOAT,
1525 GL_FALSE, 5 * sizeof (GLfloat), (void *) 0);
1527 gl->VertexAttribPointer (attr_texture_loc, 2, GL_FLOAT,
1528 GL_FALSE, 5 * sizeof (GLfloat), (void *) (3 * sizeof (GLfloat)));
1530 gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
1532 walk = g_list_next (walk);
1534 GST_OBJECT_UNLOCK (video_mixer);
1536 gl->DisableVertexAttribArray (attr_position_loc);
1537 gl->DisableVertexAttribArray (attr_texture_loc);
1539 if (gl->GenVertexArrays)
1540 gl->BindVertexArray (0);
1542 gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);
1543 gl->BindBuffer (GL_ARRAY_BUFFER, 0);
1544 gl->BindTexture (GL_TEXTURE_2D, 0);
1546 gl->Disable (GL_BLEND);
1548 gst_gl_context_clear_shader (GST_GL_BASE_MIXER (mixer)->context);