gl*bin: fix transfer semantics for the create-element signal
authorMatthew Waters <matthew@centricular.com>
Fri, 9 Feb 2018 06:15:30 +0000 (17:15 +1100)
committerMatthew Waters <matthew@centricular.com>
Fri, 9 Feb 2018 06:15:30 +0000 (17:15 +1100)
We can either receive an element that is floating or not and need to
accomodate that in the signal return values.  Do so by removing the
floating flag.

https://bugzilla.gnome.org/show_bug.cgi?id=792597

ext/gl/gstglfilterbin.c
ext/gl/gstglmixerbin.c
ext/gl/gstglsinkbin.c
ext/gl/gstglsrcbin.c
tests/check/Makefile.am
tests/check/elements/.gitignore
tests/check/elements/glbin.c [new file with mode: 0644]
tests/check/meson.build

index a3621ec..486b0fe 100644 (file)
@@ -48,6 +48,7 @@ G_DEFINE_TYPE_WITH_CODE (GstGLFilterBin, gst_gl_filter_bin,
     GST_TYPE_BIN, GST_DEBUG_CATEGORY_INIT (gst_gl_filter_bin_debug,
         "glfilterbin", 0, "glfilterbin element"););
 
+static void gst_gl_filter_bin_finalize (GObject * object);
 static void gst_gl_filter_bin_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec);
 static void gst_gl_filter_bin_set_property (GObject * object, guint prop_id,
@@ -72,6 +73,7 @@ gst_gl_filter_bin_class_init (GstGLFilterBinClass * klass)
 
   gobject_class->set_property = gst_gl_filter_bin_set_property;
   gobject_class->get_property = gst_gl_filter_bin_get_property;
+  gobject_class->finalize = gst_gl_filter_bin_finalize;
 
   gst_element_class_add_static_pad_template (element_class, &_src_pad_template);
 
@@ -142,6 +144,17 @@ gst_gl_filter_bin_init (GstGLFilterBin * self)
   }
 }
 
+static void
+gst_gl_filter_bin_finalize (GObject * object)
+{
+  GstGLFilterBin *self = GST_GL_FILTER_BIN (object);
+
+  if (self->filter)
+    gst_object_unref (self->filter);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
 static gboolean
 _connect_filter_element (GstGLFilterBin * self)
 {
@@ -159,18 +172,40 @@ _connect_filter_element (GstGLFilterBin * self)
   return res;
 }
 
-void
-gst_gl_filter_bin_finish_init_with_element (GstGLFilterBin * self,
-    GstElement * element)
+/*
+ * @filter: (transfer full):
+ */
+static gboolean
+gst_gl_filter_bin_set_filter (GstGLFilterBin * self, GstElement * filter)
 {
-  g_return_if_fail (GST_IS_ELEMENT (element));
-
-  self->filter = element;
+  g_return_val_if_fail (GST_IS_ELEMENT (filter), FALSE);
 
-  if (!_connect_filter_element (self)) {
+  if (self->filter) {
+    gst_element_set_locked_state (self->filter, TRUE);
+    gst_bin_remove (GST_BIN (self), self->filter);
+    gst_element_set_state (self->filter, GST_STATE_NULL);
     gst_object_unref (self->filter);
     self->filter = NULL;
   }
+  self->filter = filter;
+
+  if (filter && g_object_is_floating (filter))
+    gst_object_ref_sink (filter);
+
+  if (filter && !_connect_filter_element (self)) {
+    self->filter = NULL;
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+void
+gst_gl_filter_bin_finish_init_with_element (GstGLFilterBin * self,
+    GstElement * element)
+{
+  if (!gst_gl_filter_bin_set_filter (self, element))
+    gst_object_unref (element);
 }
 
 void
@@ -210,17 +245,8 @@ gst_gl_filter_bin_set_property (GObject * object, guint prop_id,
 
   switch (prop_id) {
     case PROP_FILTER:
-    {
-      GstElement *filter = g_value_get_object (value);
-      if (self->filter)
-        gst_bin_remove (GST_BIN (self), self->filter);
-      self->filter = filter;
-      if (filter) {
-        gst_object_ref_sink (filter);
-        _connect_filter_element (self);
-      }
+      gst_gl_filter_bin_set_filter (self, g_value_get_object (value));
       break;
-    }
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -240,10 +266,13 @@ gst_gl_filter_bin_change_state (GstElement * element, GstStateChange transition)
         if (klass->create_element)
           self->filter = klass->create_element ();
 
-        if (!self->filter)
+        if (!self->filter) {
           g_signal_emit (element,
               gst_gl_filter_bin_signals[SIGNAL_CREATE_ELEMENT], 0,
               &self->filter);
+          if (self->filter && g_object_is_floating (self->filter))
+            gst_object_ref_sink (self->filter);
+        }
 
         if (!self->filter) {
           GST_ERROR_OBJECT (element, "Failed to retrieve element");
index 1e6ebeb..25e18ff 100644 (file)
@@ -145,6 +145,7 @@ static void gst_gl_mixer_bin_set_property (GObject * object, guint prop_id,
 static void gst_gl_mixer_bin_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec);
 static void gst_gl_mixer_bin_dispose (GObject * object);
+static void gst_gl_mixer_bin_finalize (GObject * object);
 
 static GstPad *gst_gl_mixer_bin_request_new_pad (GstElement * element,
     GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps);
@@ -171,6 +172,7 @@ gst_gl_mixer_bin_class_init (GstGLMixerBinClass * klass)
   gobject_class->get_property = gst_gl_mixer_bin_get_property;
   gobject_class->set_property = gst_gl_mixer_bin_set_property;
   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_gl_mixer_bin_dispose);
+  gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_gl_mixer_bin_finalize);
 
   g_object_class_install_property (gobject_class, PROP_MIXER,
       g_param_spec_object ("mixer",
@@ -258,6 +260,17 @@ gst_gl_mixer_bin_init (GstGLMixerBin * self)
 }
 
 static void
+gst_gl_mixer_bin_finalize (GObject * object)
+{
+  GstGLMixerBin *self = GST_GL_MIXER_BIN (object);
+
+  if (self->mixer)
+    gst_object_unref (self->mixer);
+
+  G_OBJECT_CLASS (gst_gl_mixer_bin_parent_class)->finalize (object);
+}
+
+static void
 gst_gl_mixer_bin_dispose (GObject * object)
 {
   GstGLMixerBin *self = GST_GL_MIXER_BIN (object);
@@ -385,18 +398,40 @@ _connect_mixer_element (GstGLMixerBin * self)
   return res;
 }
 
-void
-gst_gl_mixer_bin_finish_init_with_element (GstGLMixerBin * self,
-    GstElement * element)
+/*
+ * @mixer: (transfer full):
+ */
+static gboolean
+gst_gl_mixer_bin_set_mixer (GstGLMixerBin * self, GstElement * mixer)
 {
-  g_return_if_fail (GST_IS_ELEMENT (element));
+  g_return_val_if_fail (GST_IS_ELEMENT (mixer), FALSE);
 
-  self->mixer = element;
-
-  if (!_connect_mixer_element (self)) {
+  if (self->mixer) {
+    gst_element_set_locked_state (self->mixer, TRUE);
+    gst_bin_remove (GST_BIN (self), self->mixer);
+    gst_element_set_state (self->mixer, GST_STATE_NULL);
     gst_object_unref (self->mixer);
     self->mixer = NULL;
   }
+  self->mixer = mixer;
+
+  if (mixer && g_object_is_floating (mixer))
+    gst_object_ref_sink (mixer);
+
+  if (mixer && !_connect_mixer_element (self)) {
+    self->mixer = NULL;
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+void
+gst_gl_mixer_bin_finish_init_with_element (GstGLMixerBin * self,
+    GstElement * element)
+{
+  if (!gst_gl_mixer_bin_set_mixer (self, element))
+    gst_object_unref (element);
 }
 
 void
@@ -441,11 +476,7 @@ gst_gl_mixer_bin_set_property (GObject * object,
       GstElement *mixer = g_value_get_object (value);
       /* FIXME: deal with replacing a mixer */
       g_return_if_fail (!self->mixer || (self->mixer == mixer));
-      self->mixer = mixer;
-      if (mixer) {
-        gst_object_ref_sink (mixer);
-        _connect_mixer_element (self);
-      }
+      gst_gl_mixer_bin_set_mixer (self, mixer);
       break;
     }
     default:
@@ -530,9 +561,12 @@ gst_gl_mixer_bin_change_state (GstElement * element, GstStateChange transition)
         if (klass->create_element)
           self->mixer = klass->create_element ();
 
-        if (!self->mixer)
+        if (!self->mixer) {
           g_signal_emit (element,
               gst_gl_mixer_bin_signals[SIGNAL_CREATE_ELEMENT], 0, &self->mixer);
+          if (self->mixer && g_object_is_floating (self->mixer))
+            gst_object_ref_sink (self->mixer);
+        }
 
         if (!self->mixer) {
           GST_ERROR_OBJECT (element, "Failed to retrieve element");
index 310634c..1c0d188 100644 (file)
@@ -31,6 +31,7 @@
 GST_DEBUG_CATEGORY (gst_debug_gl_sink_bin);
 #define GST_CAT_DEFAULT gst_debug_gl_sink_bin
 
+static void gst_gl_sink_bin_finalize (GObject * object);
 static void gst_gl_sink_bin_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * param_spec);
 static void gst_gl_sink_bin_get_property (GObject * object, guint prop_id,
@@ -119,6 +120,7 @@ gst_gl_sink_bin_class_init (GstGLSinkBinClass * klass)
 
   gobject_class->set_property = gst_gl_sink_bin_set_property;
   gobject_class->get_property = gst_gl_sink_bin_get_property;
+  gobject_class->finalize = gst_gl_sink_bin_finalize;
 
   g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
       g_param_spec_boolean ("force-aspect-ratio",
@@ -264,6 +266,17 @@ gst_gl_sink_bin_init (GstGLSinkBin * self)
   }
 }
 
+static void
+gst_gl_sink_bin_finalize (GObject * object)
+{
+  GstGLSinkBin *self = GST_GL_SINK_BIN (object);
+
+  if (self->sink)
+    gst_object_unref (self->sink);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
 static gboolean
 _connect_sink_element (GstGLSinkBin * self)
 {
@@ -277,28 +290,40 @@ _connect_sink_element (GstGLSinkBin * self)
   return FALSE;
 }
 
-static void
+/*
+ * @sink: (transfer full):
+ */
+static gboolean
 gst_gl_sink_bin_set_sink (GstGLSinkBin * self, GstElement * sink)
 {
-  g_return_if_fail (GST_IS_ELEMENT (sink));
+  g_return_val_if_fail (GST_IS_ELEMENT (sink), FALSE);
 
   if (self->sink) {
+    gst_element_set_locked_state (self->sink, TRUE);
     gst_bin_remove (GST_BIN (self), self->sink);
+    gst_element_set_state (self->sink, GST_STATE_NULL);
+    gst_object_unref (self->sink);
     self->sink = NULL;
   }
-
-  /* We keep an indirect reference when the element is added */
   self->sink = sink;
 
-  if (sink && !_connect_sink_element (self))
+  if (sink && g_object_is_floating (sink))
+    gst_object_ref_sink (sink);
+
+  if (sink && !_connect_sink_element (self)) {
     self->sink = NULL;
+    return FALSE;
+  }
+
+  return TRUE;
 }
 
 void
 gst_gl_sink_bin_finish_init_with_element (GstGLSinkBin * self,
     GstElement * element)
 {
-  gst_gl_sink_bin_set_sink (self, element);
+  if (!gst_gl_sink_bin_set_sink (self, element))
+    gst_object_unref (element);
 }
 
 void
@@ -311,7 +336,7 @@ gst_gl_sink_bin_finish_init (GstGLSinkBin * self)
     element = klass->create_element ();
 
   if (element)
-    gst_gl_sink_bin_set_sink (self, element);
+    gst_gl_sink_bin_finish_init_with_element (self, element);
 }
 
 static void
@@ -379,9 +404,12 @@ gst_gl_sink_bin_change_state (GstElement * element, GstStateChange transition)
         if (klass->create_element)
           self->sink = klass->create_element ();
 
-        if (!self->sink)
+        if (!self->sink) {
           g_signal_emit (element,
               gst_gl_sink_bin_signals[SIGNAL_CREATE_ELEMENT], 0, &self->sink);
+          if (self->sink && g_object_is_floating (self->sink))
+            gst_object_ref_sink (self->sink);
+        }
 
         if (!self->sink) {
           GST_ERROR_OBJECT (element, "Failed to retrieve element");
index da74aaa..672e4e0 100644 (file)
@@ -27,6 +27,7 @@
 GST_DEBUG_CATEGORY (gst_debug_gl_src_bin);
 #define GST_CAT_DEFAULT gst_debug_gl_src_bin
 
+static void gst_gl_src_bin_finalize (GObject * object);
 static void gst_gl_src_bin_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * param_spec);
 static void gst_gl_src_bin_get_property (GObject * object, guint prop_id,
@@ -75,6 +76,7 @@ gst_gl_src_bin_class_init (GstGLSrcBinClass * klass)
 
   gobject_class->set_property = gst_gl_src_bin_set_property;
   gobject_class->get_property = gst_gl_src_bin_get_property;
+  gobject_class->finalize = gst_gl_src_bin_finalize;
 
   g_object_class_install_property (gobject_class, PROP_SRC,
       g_param_spec_object ("src",
@@ -135,6 +137,17 @@ gst_gl_src_bin_init (GstGLSrcBin * self)
   }
 }
 
+static void
+gst_gl_src_bin_finalize (GObject * object)
+{
+  GstGLSrcBin *self = GST_GL_SRC_BIN (object);
+
+  if (self->src)
+    gst_object_unref (self->src);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
 static gboolean
 _connect_src_element (GstGLSrcBin * self)
 {
@@ -151,18 +164,40 @@ _connect_src_element (GstGLSrcBin * self)
   return res;
 }
 
-void
-gst_gl_src_bin_finish_init_with_element (GstGLSrcBin * self,
-    GstElement * element)
+/*
+ * @src: (transfer full):
+ */
+static gboolean
+gst_gl_src_bin_set_src (GstGLSrcBin * self, GstElement * src)
 {
-  g_return_if_fail (GST_IS_ELEMENT (element));
+  g_return_val_if_fail (GST_IS_ELEMENT (src), FALSE);
 
-  self->src = element;
-
-  if (!_connect_src_element (self)) {
+  if (self->src) {
+    gst_element_set_locked_state (self->src, TRUE);
+    gst_bin_remove (GST_BIN (self), self->src);
+    gst_element_set_state (self->src, GST_STATE_NULL);
     gst_object_unref (self->src);
     self->src = NULL;
   }
+  self->src = src;
+
+  if (src && g_object_is_floating (src))
+    gst_object_ref_sink (src);
+
+  if (src && !_connect_src_element (self)) {
+    self->src = NULL;
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+void
+gst_gl_src_bin_finish_init_with_element (GstGLSrcBin * self,
+    GstElement * element)
+{
+  if (!gst_gl_src_bin_set_src (self, element))
+    gst_object_unref (self->src);
 }
 
 void
@@ -186,17 +221,8 @@ gst_gl_src_bin_set_property (GObject * object, guint prop_id,
 
   switch (prop_id) {
     case PROP_SRC:
-    {
-      GstElement *src = g_value_get_object (value);
-      if (self->src)
-        gst_bin_remove (GST_BIN (self), self->src);
-      self->src = src;
-      if (src) {
-        gst_object_ref_sink (src);
-        _connect_src_element (self);
-      }
+      gst_gl_src_bin_set_src (self, g_value_get_object (value));
       break;
-    }
     default:
       if (self->src)
         g_object_set_property (G_OBJECT (self->src), pspec->name, value);
@@ -238,9 +264,12 @@ gst_gl_src_bin_change_state (GstElement * element, GstStateChange transition)
         if (klass->create_element)
           self->src = klass->create_element ();
 
-        if (!self->src)
+        if (!self->src) {
           g_signal_emit (element,
               gst_gl_src_bin_signals[SIGNAL_CREATE_ELEMENT], 0, &self->src);
+          if (self->src && g_object_is_floating (self->src))
+            gst_object_ref_sink (self->src);
+        }
 
         if (!self->src) {
           GST_ERROR_OBJECT (element, "Failed to retrieve element");
index e90619d..feaf7c8 100644 (file)
@@ -43,6 +43,7 @@ check_gl=\
     libs/gstglshader \
     libs/gstglheaders \
     elements/glimagesink \
+    elements/glbin \
     pipelines/gl-launch-lines
 else
 check_gl=
@@ -505,6 +506,15 @@ elements_glimagesink_LDADD = \
        $(top_builddir)/gst-libs/gst/video/libgstvideo-@GST_API_VERSION@.la \
        $(GST_BASE_LIBS) $(GST_LIBS) $(LDADD)
 
+elements_glbin_CFLAGS = \
+       $(GST_PLUGINS_BASE_CFLAGS) \
+       $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(GL_CFLAGS) $(AM_CFLAGS)
+
+elements_glbin_LDADD = \
+       $(top_builddir)/gst-libs/gst/gl/libgstgl-@GST_API_VERSION@.la \
+       $(top_builddir)/gst-libs/gst/video/libgstvideo-@GST_API_VERSION@.la \
+       $(GST_BASE_LIBS) $(GST_LIBS) $(LDADD)
+
 libs_navigation_CFLAGS = \
        $(GST_PLUGINS_BASE_CFLAGS) \
         $(GST_BASE_CFLAGS) \
index 28194b0..6678990 100644 (file)
@@ -9,6 +9,7 @@ audioresample
 audiotestsrc
 decodebin
 encodebin
+glbin
 glimagesink
 libvisual
 multifdsink
diff --git a/tests/check/elements/glbin.c b/tests/check/elements/glbin.c
new file mode 100644 (file)
index 0000000..0c3ca7e
--- /dev/null
@@ -0,0 +1,504 @@
+/* GStreamer
+ *
+ * Unit tests for glimagesink
+ *
+ * Copyright (C) 2014 Julien Isorce <j.isorce@samsung.com>
+ * Copyright (C) 2016 Matthew Waters <matthew@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/check/gstcheck.h>
+
+typedef void (*ElementOperation) (GstElement * e, gpointer user_data);
+typedef GstElement *(*CreateElement) (GstElement * src, gpointer unused);
+
+#define CREATE_ELEMENT(e,c,d) \
+    g_signal_connect (e, "create-element", G_CALLBACK (c), d)
+#define SET_ELEMENT(e,p,c,d) \
+    g_object_set (e, p, c (e, d), NULL)
+
+static GstElement *
+_create_element_floating_cb (GstElement * src, const gchar * name)
+{
+  return gst_element_factory_make (name, NULL);
+}
+
+static GstElement *
+_create_element_full_cb (GstElement * src, const gchar * name)
+{
+  return gst_object_ref_sink (gst_element_factory_make (name, NULL));
+}
+
+struct src_data
+{
+  const gchar *prop;
+  const gchar *element_name;
+};
+
+static void
+_set_element_floating (GstElement * e, struct src_data *d /* static */ )
+{
+  SET_ELEMENT (e, d->prop, _create_element_floating_cb,
+      (gchar *) d->element_name);
+}
+
+static void
+_set_element_full (GstElement * e, struct src_data *d /* static */ )
+{
+  SET_ELEMENT (e, d->prop, _create_element_full_cb, (gchar *) d->element_name);
+}
+
+static void
+_set_element_floating_floating (GstElement * e,
+    struct src_data *d /* static */ )
+{
+  _set_element_floating (e, d);
+  _set_element_floating (e, d);
+}
+
+static void
+_set_element_floating_full (GstElement * e, struct src_data *d /* static */ )
+{
+  _set_element_floating (e, d);
+  _set_element_full (e, d);
+}
+
+static void
+_set_element_full_full (GstElement * e, struct src_data *d /* static */ )
+{
+  _set_element_full (e, d);
+  _set_element_full (e, d);
+}
+
+static void
+_set_element_full_floating (GstElement * e, struct src_data *d /* static */ )
+{
+  _set_element_full (e, d);
+  _set_element_floating (e, d);
+}
+
+static void
+_create_element_floating (GstElement * e, const gchar * name /* static */ )
+{
+  CREATE_ELEMENT (e, _create_element_floating_cb, (gchar *) name);
+}
+
+static void
+_create_element_full (GstElement * e, const gchar * name /* static */ )
+{
+  CREATE_ELEMENT (e, _create_element_full_cb, (gchar *) name);
+}
+
+static void
+_test_glsrcbin (ElementOperation op, gpointer user_data)
+{
+  GstElement *pipe = gst_pipeline_new (NULL);
+  GstElement *src = gst_element_factory_make ("glsrcbin", NULL);
+  GstElement *sink = gst_element_factory_make ("glimagesink", NULL);
+
+  gst_bin_add_many (GST_BIN (pipe), src, sink, NULL);
+  gst_element_link (src, sink);
+
+  op (src, user_data);
+
+  gst_element_set_state (pipe, GST_STATE_READY);
+  gst_element_set_state (pipe, GST_STATE_NULL);
+
+  gst_object_unref (pipe);
+}
+
+GST_START_TEST (test_glsrcbin_set_element_floating)
+{
+  struct src_data d = { "src", "gltestsrc" };
+  _test_glsrcbin ((ElementOperation) _set_element_floating, &d);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_glsrcbin_set_element_full)
+{
+  struct src_data d = { "src", "gltestsrc" };
+  _test_glsrcbin ((ElementOperation) _set_element_full, &d);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_glsrcbin_set_element_floating_floating)
+{
+  struct src_data d = { "src", "gltestsrc" };
+  _test_glsrcbin ((ElementOperation) _set_element_floating_floating, &d);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_glsrcbin_set_element_floating_full)
+{
+  struct src_data d = { "src", "gltestsrc" };
+  _test_glsrcbin ((ElementOperation) _set_element_floating_full, &d);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_glsrcbin_set_element_full_floating)
+{
+  struct src_data d = { "src", "gltestsrc" };
+  _test_glsrcbin ((ElementOperation) _set_element_full_floating, &d);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_glsrcbin_set_element_full_full)
+{
+  struct src_data d = { "src", "gltestsrc" };
+  _test_glsrcbin ((ElementOperation) _set_element_full_full, &d);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_glsrcbin_create_element_floating)
+{
+  _test_glsrcbin ((ElementOperation) _create_element_floating,
+      (gchar *) "gltestsrc");
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_glsrcbin_create_element_full)
+{
+  _test_glsrcbin ((ElementOperation) _create_element_full,
+      (gchar *) "gltestsrc");
+}
+
+GST_END_TEST;
+
+static void
+_test_glsinkbin (ElementOperation op, gpointer user_data)
+{
+  GstElement *pipe = gst_pipeline_new (NULL);
+  GstElement *src = gst_element_factory_make ("gltestsrc", NULL);
+  GstElement *sink = gst_element_factory_make ("glsinkbin", NULL);
+
+  gst_bin_add_many (GST_BIN (pipe), src, sink, NULL);
+  gst_element_link (src, sink);
+
+  op (sink, user_data);
+
+  gst_element_set_state (pipe, GST_STATE_READY);
+  gst_element_set_state (pipe, GST_STATE_NULL);
+
+  gst_object_unref (pipe);
+}
+
+GST_START_TEST (test_glsinkbin_set_element_floating)
+{
+  struct src_data d = { "sink", "glimagesinkelement" };
+
+  _test_glsinkbin ((ElementOperation) _set_element_floating, &d);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_glsinkbin_set_element_full)
+{
+  struct src_data d = { "sink", "glimagesinkelement" };
+
+  _test_glsinkbin ((ElementOperation) _set_element_full, &d);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_glsinkbin_create_element_floating)
+{
+  _test_glsinkbin ((ElementOperation) _create_element_floating,
+      (gchar *) "glimagesinkelement");
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_glsinkbin_create_element_full)
+{
+  _test_glsinkbin ((ElementOperation) _create_element_full,
+      (gchar *) "glimagesinkelement");
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_glsinkbin_set_element_floating_floating)
+{
+  struct src_data d = { "sink", "glimagesinkelement" };
+  _test_glsinkbin ((ElementOperation) _set_element_floating_floating, &d);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_glsinkbin_set_element_floating_full)
+{
+  struct src_data d = { "sink", "glimagesinkelement" };
+  _test_glsinkbin ((ElementOperation) _set_element_floating_full, &d);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_glsinkbin_set_element_full_floating)
+{
+  struct src_data d = { "sink", "glimagesinkelement" };
+  _test_glsinkbin ((ElementOperation) _set_element_full_floating, &d);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_glsinkbin_set_element_full_full)
+{
+  struct src_data d = { "sink", "glimagesinkelement" };
+  _test_glsinkbin ((ElementOperation) _set_element_full_full, &d);
+}
+
+GST_END_TEST;
+
+static void
+_test_glfilterbin (ElementOperation op, gpointer user_data)
+{
+  GstElement *pipe = gst_pipeline_new (NULL);
+  GstElement *src = gst_element_factory_make ("gltestsrc", NULL);
+  GstElement *filter = gst_element_factory_make ("glfilterbin", NULL);
+  GstElement *sink = gst_element_factory_make ("glimagesinkelement", NULL);
+
+  gst_bin_add_many (GST_BIN (pipe), src, filter, sink, NULL);
+  gst_element_link_many (src, filter, sink, NULL);
+
+  op (filter, user_data);
+
+  gst_element_set_state (pipe, GST_STATE_READY);
+  gst_element_set_state (pipe, GST_STATE_NULL);
+
+  gst_object_unref (pipe);
+}
+
+GST_START_TEST (test_glfilterbin_set_element_floating)
+{
+  struct src_data d = { "filter", "gleffects_identity" };
+
+  _test_glfilterbin ((ElementOperation) _set_element_floating, &d);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_glfilterbin_set_element_full)
+{
+  struct src_data d = { "filter", "gleffects_identity" };
+
+  _test_glfilterbin ((ElementOperation) _set_element_full, &d);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_glfilterbin_create_element_floating)
+{
+  _test_glfilterbin ((ElementOperation) _create_element_floating,
+      (gchar *) "gleffects_identity");
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_glfilterbin_create_element_full)
+{
+  _test_glfilterbin ((ElementOperation) _create_element_full,
+      (gchar *) "gleffects_identity");
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_glfilterbin_set_element_floating_floating)
+{
+  struct src_data d = { "filter", "gleffects_identity" };
+  _test_glfilterbin ((ElementOperation) _set_element_floating_floating, &d);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_glfilterbin_set_element_floating_full)
+{
+  struct src_data d = { "filter", "gleffects_identity" };
+  _test_glfilterbin ((ElementOperation) _set_element_floating_full, &d);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_glfilterbin_set_element_full_floating)
+{
+  struct src_data d = { "filter", "gleffects_identity" };
+  _test_glfilterbin ((ElementOperation) _set_element_full_floating, &d);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_glfilterbin_set_element_full_full)
+{
+  struct src_data d = { "filter", "gleffects_identity" };
+  _test_glfilterbin ((ElementOperation) _set_element_full_full, &d);
+}
+
+GST_END_TEST;
+
+#if 0
+/* FIXME: add when gl mixers are added to base */
+static void
+_test_glmixerbin (ElementOperation op, gpointer user_data)
+{
+  GstElement *pipe = gst_pipeline_new (NULL);
+  GstElement *src = gst_element_factory_make ("gltestsrc", NULL);
+  GstElement *mixer = gst_element_factory_make ("glmixerbin", NULL);
+  GstElement *sink = gst_element_factory_make ("glimagesinkelement", NULL);
+
+  gst_bin_add_many (GST_BIN (pipe), src, mixer, sink, NULL);
+  gst_element_link_many (src, mixer, sink, NULL);
+
+  op (mixer, user_data);
+
+  gst_element_set_state (pipe, GST_STATE_READY);
+  gst_element_set_state (pipe, GST_STATE_NULL);
+
+  gst_object_unref (pipe);
+}
+
+GST_START_TEST (test_glmixerbin_set_element_floating)
+{
+  struct src_data d = { "mixer", "glvideomixerelement" };
+
+  _test_glmixerbin ((ElementOperation) _set_element_floating, &d);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_glmixerbin_set_element_full)
+{
+  struct src_data d = { "mixer", "glvideomixerelement" };
+
+  _test_glmixerbin ((ElementOperation) _set_element_full, &d);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_glmixerbin_create_element_floating)
+{
+  _test_glmixerbin ((ElementOperation) _create_element_floating,
+      (gchar *) "glvideomixerelement");
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_glmixerbin_create_element_full)
+{
+  _test_glmixerbin ((ElementOperation) _create_element_full,
+      (gchar *) "glvideomixerelement");
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_glmixerbin_set_element_floating_floating)
+{
+  struct src_data d = { "mixer", "glvideomixerelement" };
+  _test_glmixerbin ((ElementOperation) _set_element_floating_floating, &d);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_glmixerbin_set_element_floating_full)
+{
+  struct src_data d = { "mixer", "glvideomixerelement" };
+  _test_glmixerbin ((ElementOperation) _set_element_floating_full, &d);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_glmixerbin_set_element_full_floating)
+{
+  struct src_data d = { "mixer", "glvideomixerelement" };
+  _test_glmixerbin ((ElementOperation) _set_element_full_floating, &d);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_glmixerbin_set_element_full_full)
+{
+  struct src_data d = { "mixer", "glvideomixerelement" };
+  _test_glmixerbin ((ElementOperation) _set_element_full_full, &d);
+}
+
+GST_END_TEST;
+#endif
+static Suite *
+glbin_suite (void)
+{
+  Suite *s = suite_create ("glbin");
+  TCase *tc;
+
+  tc = tcase_create ("glsrcbin");
+  tcase_add_test (tc, test_glsrcbin_create_element_floating);
+  tcase_add_test (tc, test_glsrcbin_create_element_full);
+  tcase_add_test (tc, test_glsrcbin_set_element_floating);
+  tcase_add_test (tc, test_glsrcbin_set_element_full);
+  tcase_add_test (tc, test_glsrcbin_set_element_floating_floating);
+  tcase_add_test (tc, test_glsrcbin_set_element_full_floating);
+  tcase_add_test (tc, test_glsrcbin_set_element_floating_full);
+  tcase_add_test (tc, test_glsrcbin_set_element_full_full);
+  suite_add_tcase (s, tc);
+
+  tc = tcase_create ("glsinkbin");
+  tcase_add_test (tc, test_glsinkbin_create_element_floating);
+  tcase_add_test (tc, test_glsinkbin_create_element_full);
+  tcase_add_test (tc, test_glsinkbin_set_element_floating);
+  tcase_add_test (tc, test_glsinkbin_set_element_full);
+  tcase_add_test (tc, test_glsinkbin_set_element_floating_floating);
+  tcase_add_test (tc, test_glsinkbin_set_element_full_floating);
+  tcase_add_test (tc, test_glsinkbin_set_element_floating_full);
+  tcase_add_test (tc, test_glsinkbin_set_element_full_full);
+  suite_add_tcase (s, tc);
+
+  tc = tcase_create ("glfilterbin");
+  tcase_add_test (tc, test_glfilterbin_create_element_floating);
+  tcase_add_test (tc, test_glfilterbin_create_element_full);
+  tcase_add_test (tc, test_glfilterbin_set_element_floating);
+  tcase_add_test (tc, test_glfilterbin_set_element_full);
+  tcase_add_test (tc, test_glfilterbin_set_element_floating_floating);
+  tcase_add_test (tc, test_glfilterbin_set_element_full_floating);
+  tcase_add_test (tc, test_glfilterbin_set_element_floating_full);
+  tcase_add_test (tc, test_glfilterbin_set_element_full_full);
+  suite_add_tcase (s, tc);
+
+#if 0
+  tc = tcase_create ("glmixerbin");
+  tcase_add_test (tc, test_glmixerbin_create_element_floating);
+  tcase_add_test (tc, test_glmixerbin_create_element_full);
+  tcase_add_test (tc, test_glmixerbin_set_element_floating);
+  tcase_add_test (tc, test_glmixerbin_set_element_full);
+  tcase_add_test (tc, test_glmixerbin_set_element_floating_floating);
+  tcase_add_test (tc, test_glmixerbin_set_element_full_floating);
+  tcase_add_test (tc, test_glmixerbin_set_element_floating_full);
+  tcase_add_test (tc, test_glmixerbin_set_element_full_full);
+  suite_add_tcase (s, tc);
+#endif
+  return s;
+}
+
+GST_CHECK_MAIN (glbin)
index 2652d25..113c4f6 100644 (file)
@@ -81,6 +81,7 @@ if build_gstgl
     [ 'libs/gstglslstage.c', not build_gstgl, [gstgl_dep]],
     [ 'libs/gstglupload.c', not build_gstgl, [gstgl_dep]],
     [ 'elements/glimagesink.c', not build_gstgl, [gstgl_dep]],
+    [ 'elements/glbin.c', not build_gstgl ],
     [ 'pipelines/gl-launch-lines.c', not build_gstgl ],
   ]
 endif