move gl elements to ext subdirectory
authorMatthew Waters <ystreet00@gmail.com>
Sun, 16 Mar 2014 10:23:16 +0000 (11:23 +0100)
committerTim-Philipp Müller <tim@centricular.com>
Sat, 9 Dec 2017 19:31:34 +0000 (19:31 +0000)
59 files changed:
ext/gl/BUGS [new file with mode: 0644]
ext/gl/Makefile.am [new file with mode: 0644]
ext/gl/effects/gstgleffectbulge.c [new file with mode: 0644]
ext/gl/effects/gstgleffectfisheye.c [new file with mode: 0644]
ext/gl/effects/gstgleffectglow.c [new file with mode: 0644]
ext/gl/effects/gstgleffectidentity.c [new file with mode: 0644]
ext/gl/effects/gstgleffectlumatocurve.c [new file with mode: 0644]
ext/gl/effects/gstgleffectlumatocurve.h [new file with mode: 0644]
ext/gl/effects/gstgleffectmirror.c [new file with mode: 0644]
ext/gl/effects/gstgleffectrgbtocurve.c [new file with mode: 0644]
ext/gl/effects/gstgleffectscurves.h [new file with mode: 0644]
ext/gl/effects/gstgleffectsin.c [new file with mode: 0644]
ext/gl/effects/gstgleffectsquare.c [new file with mode: 0644]
ext/gl/effects/gstgleffectsqueeze.c [new file with mode: 0644]
ext/gl/effects/gstgleffectssources.c [new file with mode: 0644]
ext/gl/effects/gstgleffectssources.h [new file with mode: 0644]
ext/gl/effects/gstgleffectstretch.c [new file with mode: 0644]
ext/gl/effects/gstgleffecttunnel.c [new file with mode: 0644]
ext/gl/effects/gstgleffecttwirl.c [new file with mode: 0644]
ext/gl/effects/gstgleffectxray.c [new file with mode: 0644]
ext/gl/gltestsrc.c [new file with mode: 0644]
ext/gl/gltestsrc.h [new file with mode: 0644]
ext/gl/gstglbumper.c [new file with mode: 0644]
ext/gl/gstglbumper.h [new file with mode: 0644]
ext/gl/gstglcolorscale.c [new file with mode: 0644]
ext/gl/gstglcolorscale.h [new file with mode: 0644]
ext/gl/gstgldeinterlace.c [new file with mode: 0644]
ext/gl/gstgldeinterlace.h [new file with mode: 0644]
ext/gl/gstgldifferencematte.c [new file with mode: 0644]
ext/gl/gstgldifferencematte.h [new file with mode: 0644]
ext/gl/gstgleffects.c [new file with mode: 0644]
ext/gl/gstgleffects.h [new file with mode: 0644]
ext/gl/gstglfilterapp.c [new file with mode: 0644]
ext/gl/gstglfilterapp.h [new file with mode: 0644]
ext/gl/gstglfilterblur.c [new file with mode: 0644]
ext/gl/gstglfilterblur.h [new file with mode: 0644]
ext/gl/gstglfiltercube.c [new file with mode: 0644]
ext/gl/gstglfiltercube.h [new file with mode: 0644]
ext/gl/gstglfilterglass.c [new file with mode: 0644]
ext/gl/gstglfilterglass.h [new file with mode: 0644]
ext/gl/gstglfilterlaplacian.c [new file with mode: 0644]
ext/gl/gstglfilterlaplacian.h [new file with mode: 0644]
ext/gl/gstglfilterreflectedscreen.c [new file with mode: 0644]
ext/gl/gstglfilterreflectedscreen.h [new file with mode: 0644]
ext/gl/gstglfiltershader.c [new file with mode: 0644]
ext/gl/gstglfiltershader.h [new file with mode: 0644]
ext/gl/gstglfiltersobel.c [new file with mode: 0644]
ext/gl/gstglfiltersobel.h [new file with mode: 0644]
ext/gl/gstglimagesink.c [new file with mode: 0644]
ext/gl/gstglimagesink.h [new file with mode: 0644]
ext/gl/gstglmosaic.c [new file with mode: 0644]
ext/gl/gstglmosaic.h [new file with mode: 0644]
ext/gl/gstgloverlay.c [new file with mode: 0644]
ext/gl/gstgloverlay.h [new file with mode: 0644]
ext/gl/gstgltestsrc.c [new file with mode: 0644]
ext/gl/gstgltestsrc.h [new file with mode: 0644]
ext/gl/gstglvideomixer.c [new file with mode: 0644]
ext/gl/gstglvideomixer.h [new file with mode: 0644]
ext/gl/gstopengl.c [new file with mode: 0644]

diff --git a/ext/gl/BUGS b/ext/gl/BUGS
new file mode 100644 (file)
index 0000000..7110c92
--- /dev/null
@@ -0,0 +1,3 @@
+
+known issues:
+
diff --git a/ext/gl/Makefile.am b/ext/gl/Makefile.am
new file mode 100644 (file)
index 0000000..d87f881
--- /dev/null
@@ -0,0 +1,96 @@
+
+plugin_LTLIBRARIES = libgstopengl.la
+
+AM_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+AM_LIBS = $(GST_BASE_LIBS) $(GST_PLUGINS_BASE_LIBS)
+
+# full opengl required
+if USE_OPENGL
+OPENGL_SOURCES =  \
+       gstglfiltershader.c \
+       gstglfiltershader.h \
+       gstglfilterblur.c \
+       gstglfilterblur.h \
+       gstglfiltersobel.c \
+       gstglfiltersobel.h \
+       gstglfilterlaplacian.c \
+       gstglfilterlaplacian.h \
+       gstglfilterglass.c \
+       gstglfilterglass.h \
+       gstglfilterapp.c \
+       gstglfilterapp.h \
+       gstglfilterreflectedscreen.c \
+       gstglfilterreflectedscreen.h \
+       gstgldeinterlace.c \
+       gstgldeinterlace.h \
+       gltestsrc.c \
+       gltestsrc.h \
+       gstgltestsrc.c \
+       gstgltestsrc.h \
+       gstglmosaic.c \
+       gstglmosaic.h \
+       gstglvideomixer.c \
+       gstglvideomixer.h \
+       effects/gstgleffectscurves.h \
+       effects/gstgleffectstretch.c \
+       effects/gstgleffecttunnel.c \
+       effects/gstgleffectfisheye.c \
+       effects/gstgleffecttwirl.c \
+       effects/gstgleffectbulge.c \
+       effects/gstgleffectsquare.c \
+       effects/gstgleffectlumatocurve.c \
+       effects/gstgleffectlumatocurve.h \
+       effects/gstgleffectrgbtocurve.c \
+       effects/gstgleffectsin.c \
+       effects/gstgleffectglow.c \
+       effects/gstgleffectxray.c
+
+if HAVE_PNG
+OPENGL_SOURCES += \
+       gstglbumper.c \
+       gstglbumper.h \
+       gstgldifferencematte.c \
+       gstgldifferencematte.h
+if HAVE_JPEG
+OPENGL_SOURCES += \
+       gstgloverlay.c \
+       gstgloverlay.h
+endif
+endif
+endif
+
+libgstopengl_la_SOURCES = \
+       gstopengl.c \
+       gstglimagesink.c \
+       gstglimagesink.h \
+       gstglfiltercube.c \
+       gstglfiltercube.h \
+       gstgleffects.c \
+       gstgleffects.h \
+       effects/gstgleffectssources.c \
+       effects/gstgleffectssources.h \
+       effects/gstgleffectidentity.c \
+       effects/gstgleffectmirror.c \
+       effects/gstgleffectsqueeze.c \
+       gstglcolorscale.c \
+       gstglcolorscale.h \
+       $(OPENGL_SOURCES)
+
+# check order of CFLAGS and LIBS, shouldn't the order be the other way around
+# (like in AM_CFLAGS)?
+libgstopengl_la_CFLAGS = -I$(top_srcdir)/gst-libs $(GST_CFLAGS) $(GST_BASE_CFLAGS) \
+       $(GST_PLUGINS_BASE_CFLAGS) $(GL_CFLAGS) $(LIBPNG_CFLAGS)
+
+libgstopengl_la_LIBADD = \
+       $(top_builddir)/gst-libs/gst/gl/libgstgl-$(GST_API_VERSION).la \
+       $(GST_BASE_LIBS) \
+       $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_API_VERSION) \
+       -lgstpbutils-$(GST_API_VERSION) \
+       $(GL_LIBS) \
+       $(LIBPNG_LIBS) \
+        $(JPEG_LIBS) \
+       $(LIBM)
+
+libgstopengl_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstopengl_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
+
diff --git a/ext/gl/effects/gstgleffectbulge.c b/ext/gl/effects/gstgleffectbulge.c
new file mode 100644 (file)
index 0000000..b0c1b41
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 "../gstgleffects.h"
+
+static void
+gst_gl_effects_bulge_callback (gint width, gint height, guint texture,
+    gpointer data)
+{
+  GstGLShader *shader;
+  GstGLEffects *effects = GST_GL_EFFECTS (data);
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+  GstGLContext *context = filter->context;
+  GstGLFuncs *gl = context->gl_vtable;
+
+  shader = g_hash_table_lookup (effects->shaderstable, "bulge0");
+
+  if (!shader) {
+    shader = gst_gl_shader_new (context);
+    g_hash_table_insert (effects->shaderstable, "bulge0", shader);
+  }
+
+  if (!gst_gl_shader_compile_and_check (shader,
+          bulge_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
+    gst_gl_context_set_error (context, "Failed to initialize bulge shader");
+    GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
+        ("%s", gst_gl_context_get_error ()), (NULL));
+    return;
+  }
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+
+  gst_gl_shader_use (shader);
+
+  gl->ActiveTexture (GL_TEXTURE0);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+
+  gst_gl_shader_set_uniform_1i (shader, "tex", 0);
+
+  gst_gl_shader_set_uniform_1f (shader, "width", (gfloat) width / 2.0f);
+  gst_gl_shader_set_uniform_1f (shader, "height", (gfloat) height / 2.0f);
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
+
+void
+gst_gl_effects_bulge (GstGLEffects * effects)
+{
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+
+  gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
+      effects->outtexture, gst_gl_effects_bulge_callback, effects);
+}
diff --git a/ext/gl/effects/gstgleffectfisheye.c b/ext/gl/effects/gstgleffectfisheye.c
new file mode 100644 (file)
index 0000000..4ee6416
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 "../gstgleffects.h"
+
+static void
+gst_gl_effects_fisheye_callback (gint width, gint height, guint texture,
+    gpointer data)
+{
+  GstGLShader *shader;
+  GstGLEffects *effects = GST_GL_EFFECTS (data);
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+  GstGLContext *context = filter->context;
+  GstGLFuncs *gl = context->gl_vtable;
+
+  shader = g_hash_table_lookup (effects->shaderstable, "fisheye0");
+
+  if (!shader) {
+    shader = gst_gl_shader_new (context);
+    g_hash_table_insert (effects->shaderstable, "fisheye0", shader);
+  }
+
+  if (!gst_gl_shader_compile_and_check (shader,
+          fisheye_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
+    gst_gl_context_set_error (context, "Failed to initialize fisheye shader");
+    GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
+        ("%s", gst_gl_context_get_error ()), (NULL));
+    return;
+  }
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+
+  gst_gl_shader_use (shader);
+
+  gl->ActiveTexture (GL_TEXTURE0);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+
+  gst_gl_shader_set_uniform_1i (shader, "tex", 0);
+
+  gst_gl_shader_set_uniform_1f (shader, "width", (gfloat) width / 2.0f);
+  gst_gl_shader_set_uniform_1f (shader, "height", (gfloat) height / 2.0f);
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
+
+void
+gst_gl_effects_fisheye (GstGLEffects * effects)
+{
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+
+  gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
+      effects->outtexture, gst_gl_effects_fisheye_callback, effects);
+}
diff --git a/ext/gl/effects/gstgleffectglow.c b/ext/gl/effects/gstgleffectglow.c
new file mode 100644 (file)
index 0000000..b79f54f
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 "../gstgleffects.h"
+
+static gboolean kernel_ready = FALSE;
+static float gauss_kernel[7];
+
+static void
+gst_gl_effects_glow_step_one (gint width, gint height, guint texture,
+    gpointer data)
+{
+  GstGLShader *shader;
+  GstGLEffects *effects = GST_GL_EFFECTS (data);
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+  GstGLContext *context = filter->context;
+  GstGLFuncs *gl = context->gl_vtable;
+
+  shader = g_hash_table_lookup (effects->shaderstable, "glow0");
+
+  if (!shader) {
+    shader = gst_gl_shader_new (context);
+    g_hash_table_insert (effects->shaderstable, "glow0", shader);
+  }
+
+  if (!gst_gl_shader_compile_and_check (shader,
+          luma_threshold_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
+    gst_gl_context_set_error (context,
+        "Failed to initialize luma threshold shader");
+    GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
+        ("%s", gst_gl_context_get_error ()), (NULL));
+    return;
+  }
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+
+  gst_gl_shader_use (shader);
+
+  gl->ActiveTexture (GL_TEXTURE0);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+
+  gst_gl_shader_set_uniform_1i (shader, "tex", 0);
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
+
+static void
+gst_gl_effects_glow_step_two (gint width, gint height, guint texture,
+    gpointer data)
+{
+  GstGLShader *shader;
+  GstGLEffects *effects = GST_GL_EFFECTS (data);
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+  GstGLContext *context = filter->context;
+  GstGLFuncs *gl = context->gl_vtable;
+
+  shader = g_hash_table_lookup (effects->shaderstable, "glow1");
+
+  if (!shader) {
+    shader = gst_gl_shader_new (context);
+    g_hash_table_insert (effects->shaderstable, "glow1", shader);
+  }
+
+  if (!kernel_ready) {
+    fill_gaussian_kernel (gauss_kernel, 7, 10.0);
+    kernel_ready = TRUE;
+  }
+
+  if (!gst_gl_shader_compile_and_check (shader,
+          hconv7_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
+    gst_gl_context_set_error (context, "Failed to initialize hconv7 shader");
+    GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
+        ("%s", gst_gl_context_get_error ()), (NULL));
+    return;
+  }
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+
+  gst_gl_shader_use (shader);
+
+  gl->ActiveTexture (GL_TEXTURE1);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+  gl->Disable (GL_TEXTURE_2D);
+
+  gst_gl_shader_set_uniform_1i (shader, "tex", 1);
+  gst_gl_shader_set_uniform_1fv (shader, "kernel", 7, gauss_kernel);
+  gst_gl_shader_set_uniform_1f (shader, "height", height);
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
+
+void
+gst_gl_effects_glow_step_three (gint width, gint height, guint texture,
+    gpointer data)
+{
+  GstGLShader *shader;
+  GstGLEffects *effects = GST_GL_EFFECTS (data);
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+  GstGLContext *context = filter->context;
+  GstGLFuncs *gl = context->gl_vtable;
+
+  shader = g_hash_table_lookup (effects->shaderstable, "glow2");
+
+  if (!shader) {
+    shader = gst_gl_shader_new (context);
+    g_hash_table_insert (effects->shaderstable, "glow2", shader);
+  }
+
+  if (!gst_gl_shader_compile_and_check (shader,
+          vconv7_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
+    gst_gl_context_set_error (context, "Failed to initialize vcon7 shader");
+    GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
+        ("%s", gst_gl_context_get_error ()), (NULL));
+    return;
+  }
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+
+  gst_gl_shader_use (shader);
+
+  gl->ActiveTexture (GL_TEXTURE1);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+  gl->Disable (GL_TEXTURE_2D);
+
+  gst_gl_shader_set_uniform_1i (shader, "tex", 1);
+  gst_gl_shader_set_uniform_1fv (shader, "kernel", 7, gauss_kernel);
+  gst_gl_shader_set_uniform_1f (shader, "width", width);
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
+
+void
+gst_gl_effects_glow_step_four (gint width, gint height, guint texture,
+    gpointer data)
+{
+  GstGLShader *shader;
+  GstGLEffects *effects = GST_GL_EFFECTS (data);
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+  GstGLContext *context = filter->context;
+  GstGLFuncs *gl = context->gl_vtable;
+
+  shader = g_hash_table_lookup (effects->shaderstable, "glow3");
+
+  if (!shader) {
+    shader = gst_gl_shader_new (context);
+    g_hash_table_insert (effects->shaderstable, "glow3", shader);
+  }
+
+  if (!gst_gl_shader_compile_and_check (shader,
+          sum_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
+    gst_gl_context_set_error (context, "Failed to initialize sum shader");
+    GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
+        ("%s", gst_gl_context_get_error ()), (NULL));
+    return;
+  }
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+
+  gst_gl_shader_use (shader);
+
+  gl->ActiveTexture (GL_TEXTURE2);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, effects->intexture);
+  gl->Disable (GL_TEXTURE_2D);
+
+  gst_gl_shader_set_uniform_1f (shader, "alpha", 1.0);
+  gst_gl_shader_set_uniform_1i (shader, "base", 2);
+
+  gl->ActiveTexture (GL_TEXTURE1);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+  gl->Disable (GL_TEXTURE_2D);
+
+  gst_gl_shader_set_uniform_1f (shader, "beta", (gfloat) 1 / 3.5f);
+  gst_gl_shader_set_uniform_1i (shader, "blend", 1);
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
+
+void
+gst_gl_effects_glow (GstGLEffects * effects)
+{
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+
+  /* threshold */
+  gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
+      effects->midtexture[0], gst_gl_effects_glow_step_one, effects);
+  /* blur */
+  gst_gl_filter_render_to_target (filter, FALSE, effects->midtexture[0],
+      effects->midtexture[1], gst_gl_effects_glow_step_two, effects);
+  gst_gl_filter_render_to_target (filter, FALSE, effects->midtexture[1],
+      effects->midtexture[2], gst_gl_effects_glow_step_three, effects);
+  /* add blurred luma to intexture */
+  gst_gl_filter_render_to_target (filter, FALSE, effects->midtexture[2],
+      effects->outtexture, gst_gl_effects_glow_step_four, effects);
+}
diff --git a/ext/gl/effects/gstgleffectidentity.c b/ext/gl/effects/gstgleffectidentity.c
new file mode 100644 (file)
index 0000000..9814fec
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 "../gstgleffects.h"
+
+#define USING_OPENGL(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_OPENGL)
+#define USING_OPENGL3(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_OPENGL3)
+#define USING_GLES(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES)
+#define USING_GLES2(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES2)
+#define USING_GLES3(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES3)
+
+static void
+gst_gl_effects_identity_callback (gint width, gint height, guint texture,
+    gpointer data)
+{
+  GstGLEffects *effects = GST_GL_EFFECTS (data);
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+  GstGLContext *context = filter->context;
+  GstGLFuncs *gl = context->gl_vtable;
+
+#if GST_GL_HAVE_OPENGL
+  if (USING_OPENGL (context)) {
+    gl->MatrixMode (GL_PROJECTION);
+    gl->LoadIdentity ();
+  }
+#endif
+#if GST_GL_HAVE_GLES2
+  if (USING_GLES2 (context)) {
+    GstGLShader *shader =
+        g_hash_table_lookup (effects->shaderstable, "identity0");
+
+    if (!shader) {
+      shader = gst_gl_shader_new (context);
+      g_hash_table_insert (effects->shaderstable, "identity0", shader);
+
+      if (shader) {
+        GError *error = NULL;
+        gst_gl_shader_set_vertex_source (shader, vertex_shader_source);
+        gst_gl_shader_set_fragment_source (shader, identity_fragment_source);
+
+        gst_gl_shader_compile (shader, &error);
+        if (error) {
+          GST_ERROR ("%s", error->message);
+          g_error_free (error);
+          error = NULL;
+          gst_gl_shader_use (NULL);
+        } else {
+          filter->draw_attr_position_loc =
+              gst_gl_shader_get_attribute_location (shader, "a_position");
+          filter->draw_attr_texture_loc =
+              gst_gl_shader_get_attribute_location (shader, "a_texCoord");
+        }
+      }
+    }
+    gst_gl_shader_use (shader);
+
+    gl->ActiveTexture (GL_TEXTURE0);
+    gl->Enable (GL_TEXTURE_2D);
+    gl->BindTexture (GL_TEXTURE_2D, texture);
+
+    gst_gl_shader_set_uniform_1i (shader, "tex", 0);
+  }
+#endif
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
+
+void
+gst_gl_effects_identity (GstGLEffects * effects)
+{
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+
+  gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
+      effects->outtexture, gst_gl_effects_identity_callback, effects);
+}
diff --git a/ext/gl/effects/gstgleffectlumatocurve.c b/ext/gl/effects/gstgleffectlumatocurve.c
new file mode 100644 (file)
index 0000000..e45a81b
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 "../gstgleffects.h"
+#include "gstgleffectlumatocurve.h"
+
+void
+gst_gl_effects_luma_to_curve (GstGLEffects * effects,
+    GstGLEffectsCurve curve,
+    gint curve_index, gint width, gint height, GLuint texture)
+{
+  GstGLShader *shader;
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+  GstGLContext *context = filter->context;
+  GstGLFuncs *gl = context->gl_vtable;
+
+  shader = g_hash_table_lookup (effects->shaderstable, "lumamap0");
+
+  if (!shader) {
+    shader = gst_gl_shader_new (context);
+    g_hash_table_insert (effects->shaderstable, "lumamap0", shader);
+  }
+
+  if (!gst_gl_shader_compile_and_check (shader,
+          luma_to_curve_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
+    gst_gl_context_set_error (context,
+        "Failed to initialize luma to curve shader");
+    GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
+        ("%s", gst_gl_context_get_error ()), (NULL));
+    return;
+  }
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+
+  gst_gl_shader_use (shader);
+
+  if (effects->curve[curve_index] == 0) {
+    /* this parameters are needed to have a right, predictable, mapping */
+    gl->GenTextures (1, &effects->curve[curve_index]);
+    gl->Enable (GL_TEXTURE_1D);
+    gl->BindTexture (GL_TEXTURE_1D, effects->curve[curve_index]);
+    gl->TexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    gl->TexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    gl->TexParameteri (GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+    gl->TexParameteri (GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+
+    gl->TexImage1D (GL_TEXTURE_1D, 0, curve.bytes_per_pixel,
+        curve.width, 0, GL_RGB, GL_UNSIGNED_BYTE, curve.pixel_data);
+
+    gl->Disable (GL_TEXTURE_1D);
+  }
+
+  gl->ActiveTexture (GL_TEXTURE2);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+
+  gst_gl_shader_set_uniform_1i (shader, "tex", 2);
+
+  gl->Disable (GL_TEXTURE_2D);
+
+  gl->ActiveTexture (GL_TEXTURE1);
+  gl->Enable (GL_TEXTURE_1D);
+  gl->BindTexture (GL_TEXTURE_1D, effects->curve[curve_index]);
+
+  gst_gl_shader_set_uniform_1i (shader, "curve", 1);
+
+  gl->Disable (GL_TEXTURE_1D);
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
+
+static void
+gst_gl_effects_heat_callback (gint width, gint height, guint texture,
+    gpointer data)
+{
+  GstGLEffects *effects = GST_GL_EFFECTS (data);
+
+  gst_gl_effects_luma_to_curve (effects, heat_curve, GST_GL_EFFECTS_CURVE_HEAT,
+      width, height, texture);
+}
+
+void
+gst_gl_effects_heat (GstGLEffects * effects)
+{
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+
+  gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
+      effects->outtexture, gst_gl_effects_heat_callback, effects);
+}
+
+static void
+gst_gl_effects_sepia_callback (gint width, gint height, guint texture,
+    gpointer data)
+{
+  GstGLEffects *effects = GST_GL_EFFECTS (data);
+
+  gst_gl_effects_luma_to_curve (effects, sepia_curve,
+      GST_GL_EFFECTS_CURVE_SEPIA, width, height, texture);
+}
+
+void
+gst_gl_effects_sepia (GstGLEffects * effects)
+{
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+
+  gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
+      effects->outtexture, gst_gl_effects_sepia_callback, effects);
+}
+
+static void
+gst_gl_effects_luma_xpro_callback (gint width, gint height, guint texture,
+    gpointer data)
+{
+  GstGLEffects *effects = GST_GL_EFFECTS (data);
+
+  gst_gl_effects_luma_to_curve (effects, luma_xpro_curve,
+      GST_GL_EFFECTS_CURVE_LUMA_XPRO, width, height, texture);
+}
+
+void
+gst_gl_effects_luma_xpro (GstGLEffects * effects)
+{
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+
+  gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
+      effects->outtexture, gst_gl_effects_luma_xpro_callback, effects);
+}
diff --git a/ext/gl/effects/gstgleffectlumatocurve.h b/ext/gl/effects/gstgleffectlumatocurve.h
new file mode 100644 (file)
index 0000000..1260416
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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.
+ */
+
+#ifndef __GST_GL_LUMA_TO_CURVE_H__
+#define __GST_GL_LUMA_TO_CURVE_H__
+
+#include "gstgleffectscurves.h"
+
+G_BEGIN_DECLS
+
+void gst_gl_effects_luma_to_curve (GstGLEffects *effects,
+                                   GstGLEffectsCurve curve,
+                                   gint curve_index,
+                                   gint width, gint height,
+                                   GLuint texture);
+G_END_DECLS
+
+#endif /* __GST_GL_LUMA_TO_CURVE_H__ */
diff --git a/ext/gl/effects/gstgleffectmirror.c b/ext/gl/effects/gstgleffectmirror.c
new file mode 100644 (file)
index 0000000..5d77fa9
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 "../gstgleffects.h"
+
+#define USING_OPENGL(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_OPENGL)
+#define USING_OPENGL3(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_OPENGL3)
+#define USING_GLES(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES)
+#define USING_GLES2(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES2)
+#define USING_GLES3(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES3)
+
+static void
+gst_gl_effects_mirror_callback (gint width, gint height, guint texture,
+    gpointer data)
+{
+  GstGLShader *shader;
+  GstGLFilter *filter = GST_GL_FILTER (data);
+  GstGLEffects *effects = GST_GL_EFFECTS (filter);
+  GstGLContext *context = filter->context;
+  GstGLFuncs *gl = context->gl_vtable;
+
+  shader = g_hash_table_lookup (effects->shaderstable, "mirror0");
+
+  if (!shader) {
+    shader = gst_gl_shader_new (context);
+    g_hash_table_insert (effects->shaderstable, "mirror0", shader);
+
+#if GST_GL_HAVE_GLES2
+    if (USING_GLES2 (context)) {
+      if (shader) {
+        GError *error = NULL;
+        gst_gl_shader_set_vertex_source (shader, vertex_shader_source);
+        gst_gl_shader_set_fragment_source (shader,
+            mirror_fragment_source_gles2);
+
+        gst_gl_shader_compile (shader, &error);
+        if (error) {
+          gst_gl_context_set_error (context,
+              "Failed to initialize mirror shader, %s", error->message);
+          g_error_free (error);
+          error = NULL;
+          gst_gl_shader_use (NULL);
+          GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
+              ("%s", gst_gl_context_get_error ()), (NULL));
+        } else {
+          filter->draw_attr_position_loc =
+              gst_gl_shader_get_attribute_location (shader, "a_position");
+          filter->draw_attr_texture_loc =
+              gst_gl_shader_get_attribute_location (shader, "a_texCoord");
+        }
+      }
+    }
+#endif
+#if GST_GL_HAVE_OPENGL
+    if (USING_OPENGL (context)) {
+      if (!gst_gl_shader_compile_and_check (shader,
+              mirror_fragment_source_opengl, GST_GL_SHADER_FRAGMENT_SOURCE)) {
+        gst_gl_context_set_error (context,
+            "Failed to initialize mirror shader");
+        GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
+            ("%s", gst_gl_context_get_error ()), (NULL));
+        return;
+      }
+
+    }
+#endif
+  }
+#if GST_GL_HAVE_OPENGL
+  if (USING_OPENGL (context)) {
+    gl->MatrixMode (GL_PROJECTION);
+    gl->LoadIdentity ();
+  }
+#endif
+
+  gst_gl_shader_use (shader);
+
+  gl->ActiveTexture (GL_TEXTURE0);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+
+  gst_gl_shader_set_uniform_1i (shader, "tex", 0);
+
+#if GST_GL_HAVE_OPENGL
+  if (USING_OPENGL (filter->context)) {
+    gst_gl_shader_set_uniform_1f (shader, "width", (gfloat) width / 2.0f);
+    gst_gl_shader_set_uniform_1f (shader, "height", (gfloat) height / 2.0f);
+  }
+#endif
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
+
+void
+gst_gl_effects_mirror (GstGLEffects * effects)
+{
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+
+  gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
+      effects->outtexture, gst_gl_effects_mirror_callback, effects);
+}
diff --git a/ext/gl/effects/gstgleffectrgbtocurve.c b/ext/gl/effects/gstgleffectrgbtocurve.c
new file mode 100644 (file)
index 0000000..293875f
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 "../gstgleffects.h"
+#include "gstgleffectscurves.h"
+
+static void
+gst_gl_effects_rgb_to_curve (GstGLEffects * effects,
+    GstGLEffectsCurve curve,
+    gint curve_index, gint width, gint height, GLuint texture)
+{
+  GstGLShader *shader;
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+  GstGLContext *context = filter->context;
+  GstGLFuncs *gl = context->gl_vtable;
+
+  shader = g_hash_table_lookup (effects->shaderstable, "rgbmap0");
+
+  if (!shader) {
+    shader = gst_gl_shader_new (context);
+    g_hash_table_insert (effects->shaderstable, "rgbmap0", shader);
+  }
+
+  if (!gst_gl_shader_compile_and_check (shader,
+          rgb_to_curve_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
+    gst_gl_context_set_error (context,
+        "Failed to initialize rgb to curve shader");
+    GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
+        ("%s", gst_gl_context_get_error ()), (NULL));
+    return;
+  }
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+
+  gst_gl_shader_use (shader);
+
+  if (effects->curve[curve_index] == 0) {
+    /* this parameters are needed to have a right, predictable, mapping */
+    gl->GenTextures (1, &effects->curve[curve_index]);
+    gl->Enable (GL_TEXTURE_1D);
+    gl->BindTexture (GL_TEXTURE_1D, effects->curve[curve_index]);
+    gl->TexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    gl->TexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    gl->TexParameteri (GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+    gl->TexParameteri (GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+
+    gl->TexImage1D (GL_TEXTURE_1D, 0, curve.bytes_per_pixel,
+        curve.width, 0, GL_RGB, GL_UNSIGNED_BYTE, curve.pixel_data);
+
+    gl->Disable (GL_TEXTURE_1D);
+  }
+
+  gl->ActiveTexture (GL_TEXTURE0);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+
+  gst_gl_shader_set_uniform_1i (shader, "tex", 0);
+
+  gl->Disable (GL_TEXTURE_2D);
+
+  gl->ActiveTexture (GL_TEXTURE1);
+  gl->Enable (GL_TEXTURE_1D);
+  gl->BindTexture (GL_TEXTURE_1D, effects->curve[curve_index]);
+
+  gst_gl_shader_set_uniform_1i (shader, "curve", 1);
+
+  gl->Disable (GL_TEXTURE_1D);
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
+
+static void
+gst_gl_effects_xpro_callback (gint width, gint height, guint texture,
+    gpointer data)
+{
+  GstGLEffects *effects = GST_GL_EFFECTS (data);
+
+  gst_gl_effects_rgb_to_curve (effects, xpro_curve, GST_GL_EFFECTS_CURVE_XPRO,
+      width, height, texture);
+}
+
+void
+gst_gl_effects_xpro (GstGLEffects * effects)
+{
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+
+  gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
+      effects->outtexture, gst_gl_effects_xpro_callback, effects);
+}
diff --git a/ext/gl/effects/gstgleffectscurves.h b/ext/gl/effects/gstgleffectscurves.h
new file mode 100644 (file)
index 0000000..e0e98a5
--- /dev/null
@@ -0,0 +1,212 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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.
+ */
+
+#ifndef __GST_GL_EFFECTS_TEXTURES_H__
+#define __GST_GL_EFFECTS_TEXTURES_H__
+
+
+struct _GstGLEffectsCurve {
+  guint         width;
+  guint         height;
+  guint         bytes_per_pixel; /* 3:RGB */ 
+  guint8        pixel_data[256 * 1 * 3 + 1];
+};
+
+typedef struct _GstGLEffectsCurve GstGLEffectsCurve;
+
+/* CURVE for the heat signature effect */
+static const GstGLEffectsCurve xpro_curve = {
+  256, 1, 3,
+  "\0\0\37\0\0\37\0\1\40\0\2!\0\2\"\0\3\"\1\4%\1\4%\1\5%\1\5'\1\7'\1\7(\1\7"
+  "(\1\10*\1\11+\1\11,\1\12,\1\13/\1\14/\1\14""1\2\15""1\2\15""1\2\16""4\2\17"
+  """4\3\17""5\3\22""7\3\22""7\3\23""8\3\24""9\3\25;\3\26;\3\27<\3\27=\4\31"
+  "=\4\33?\4\34@\5\34B\5\35C\5\36D\5\40D\5\40G\5!G\6\"H\6$H\7&J\7&K\7*M\7*M"
+  "\10+N\10-P\11-P\11/R\11""3R\11""3T\12""4U\12""5U\13""7W\14""8Y\14""9Y\14"
+  "<Y\16=[\16@^\16@^\17C^\17D`\20F`\20Jb\22Jb\22Kc\23Me\24Nf\25Qg\26Rg\27Ti"
+  "\27Wj\30Xl\31Yl\33\\m\34^p\35`p\40bp\40fq!fr$gt$lt%lu'mv(px*qy-ty/uz/x|0"
+  "y}3|}4}~5\177\2018\203\2019\203\201;\204\202=\207\203?\210\204@\214\204C"
+  "\214\206D\216\207G\217\210H\223\211K\223\211M\225\212P\226\214Q\231\215T"
+  "\232\215U\234\216X\235\217Y\240\220\\\241\220^\243\221`\244\223b\246\224"
+  "e\250\224f\252\225i\253\226l\255\227m\256\231p\261\231q\262\232t\264\233"
+  "v\265\234x\267\234z\270\235|\271\236~\274\240\201\275\240\202\277\241\204"
+  "\300\242\207\302\243\210\303\243\212\305\244\214\306\245\216\307\246\220"
+  "\311\250\221\313\250\224\315\251\226\316\252\227\317\253\232\321\253\234"
+  "\322\254\235\323\255\240\325\256\242\326\256\242\330\256\245\331\261\250"
+  "\331\262\251\332\262\253\334\263\255\335\264\256\336\265\261\340\266\263"
+  "\341\266\264\342\267\266\343\270\270\344\271\271\344\271\271\346\273\276"
+  "\347\274\277\350\275\277\351\275\302\352\276\304\353\277\306\353\300\307"
+  "\355\300\311\356\301\314\356\302\315\357\303\317\360\304\320\360\304\322"
+  "\361\305\323\362\306\325\362\307\327\363\307\330\363\310\330\364\311\333"
+  "\364\313\334\365\313\336\365\314\340\365\314\342\366\316\342\366\316\346"
+  "\367\317\347\367\320\351\367\320\353\370\322\354\370\322\356\370\323\356"
+  "\370\324\360\371\325\360\371\325\363\371\326\363\371\327\363\372\330\365"
+  "\372\330\366\372\331\366\372\331\370\372\332\371\373\332\371\373\333\372"
+  "\373\334\373\373\335\373\373\336\374\373\336\374\374\337\374\374\340\375"
+  "\374\341\375\374\341\376\374\342\376\374\343\376\374\344\376\374\344\377"
+  "\374\345\377\374\346\377\375\346\377\375\346\377\375\347\377\375\350\377"
+  "\375\351\377\375\352\377\375\352\377\375\352\377\375\353\377\375\353\377"
+  "\376\354\377\376\354\377\376\356\377\376\356\377\376\356\377\376\357\377"
+  "\376\360\377\376\360\377\376\360\377\376\360\377\376\362\377\376\362\377"
+  "\376\363\377\376\363\377\376\363\377\376\363\377\376\364\377\376\364\377"
+  "\376\365\377\377\365\377\377\366\377\377\366\377\377\366\377\377\367\377"
+  "\377\367\377\377\367\377\377\370",
+};
+
+static const GstGLEffectsCurve luma_xpro_curve = {
+  256, 1, 3,
+  "\0\0\1\0\1\1\0\1\2\0\1\2\0\1\2\0\1\2\0\1\3\0\2\3\0\2\4\0\2\4\0\2\5\0\2\6"
+  "\0\3\6\0\3\6\0\3\7\0\3\10\0\4\10\0\4\11\0\4\12\0\4\12\1\4\13\1\5\14\1\5\15"
+  "\1\5\15\1\5\16\1\5\17\1\6\17\1\6\20\1\7\21\1\7\23\2\10\23\2\10\24\2\10\24"
+  "\2\11\26\2\11\27\2\11\30\3\11\31\3\12\31\3\13\32\3\13\33\4\13\34\4\14\35"
+  "\4\14\36\4\15\37\5\15\40\5\15\"\6\16#\6\17#\6\20$\7\20%\7\20%\10\21&\10\22"
+  "'\10\22)\11\24*\11\24*\12\24+\12\26.\13\26.\14\27.\14\30/\15\31""1\15\31"
+  """2\16\32""3\16\33""3\20\33""5\20\35""6\20\36""7\22\37""7\23\"9\23#9\24$"
+  ":\25$<\27&<\27'=\31'?\31)?\32*@\35+B\35-C\36.C\37""1E\"2F#3H$5H&6I'7I)7K"
+  "+:M-<N-<N1@N1BQ2BQ6CQ6EU7HU<IU=IV@NX@NXBQZCS[FU[HU]IV_MZ_N[_Q]`S_bU`dXbe"
+  "Zbe]gg]ig`ji`jjdljenlgpljqnpwppwpqxqszqw|sx}u|\201u}\203w\177\204x\177\206"
+  "x\204\210x\204\212z\212\213|\212\217}\217\221}\221\222}\222\224\177\226\224"
+  "\201\226\226\203\230\233\203\235\235\204\236\235\204\236\236\210\244\242"
+  "\210\244\242\210\245\244\212\251\245\213\252\251\213\254\252\215\257\254"
+  "\215\261\256\217\261\257\221\266\261\221\267\261\222\273\264\224\273\267"
+  "\224\274\267\224\276\273\230\301\273\230\302\274\231\304\276\231\307\302"
+  "\233\312\302\235\312\304\235\314\306\236\316\307\240\320\311\240\321\314"
+  "\242\324\315\242\325\316\244\327\320\245\332\321\245\333\321\245\334\323"
+  "\251\335\325\251\335\330\252\341\332\254\341\332\256\344\334\256\346\334"
+  "\256\347\337\257\347\340\261\350\340\263\351\342\263\352\344\264\354\345"
+  "\266\355\346\266\356\347\267\357\350\271\360\351\273\361\352\273\362\352"
+  "\274\362\355\276\364\356\277\364\357\277\365\360\277\365\360\302\366\361"
+  "\302\367\361\304\370\363\304\370\363\307\370\364\307\371\364\311\371\366"
+  "\312\372\367\312\372\367\314\372\367\316\373\370\316\373\370\320\373\371"
+  "\320\374\371\321\374\372\323\374\372\324\375\372\325\375\372\325\375\373"
+  "\327\375\373\330\375\374\332\375\374\333\375\375\334\376\375\334\376\375"
+  "\335\376\375\337\376\375\337\376\375\340\376\376\342\376\376\344\376\376"
+  "\344\376\376\345\376\376\346\376\376\347\376\376\350\377\376\351\377\377"
+  "\353\377\377\354\377\377\356\377\377\357\377\377\361\377\377\361\377\377"
+  "\361\377\377\364\377\377\365\377\377\366\377\377\367\377\377\367\377\377"
+  "\371\377\377\371\377\377\372\377\377\373\377\377\373\377\377\374\377\377"
+  "\375\377\377\375\377\377\375\377\377\376",
+};
+
+/* CURVE for the heat signature effect */
+static const GstGLEffectsCurve heat_curve = {
+  256, 1, 3,
+  "\0\0\0\0\0\0\0\1\0\0\1\0\0\1\1\0\2\1\0\2\1\1\2\1\1\2\2\1\2\2\1\3\2\1\3\3"
+  "\1\3\3\1\4\3\1\4\4\1\5\4\1\5\5\2\5\6\2\6\6\2\6\7\2\6\7\2\7\7\2\7\11\2\10"
+  "\11\2\10\12\3\11\13\3\11\13\3\11\14\3\12\15\3\12\17\3\13\17\3\14\20\3\14"
+  "\22\4\15\23\4\16\24\4\16\26\4\16\27\4\17\31\4\20\34\4\21\34\5\21\40\5\22"
+  "\40\5\22$\5\23$\5\25&\6\25(\6\26-\6\26-\6\27""0\6\31""2\7\31""5\7\32;\7\34"
+  ";\7\34?\10\35C\10\36G\10\37L\10\40V\11!V\11\"[\11$a\11&l\12&l\12'r\12(~\13"
+  "*~\13,\204\14,\213\14.\221\14/\227\14""1\236\15""2\244\15""4\252\15""5\260"
+  "\16""7\267\16""8\275\17:\302\17;\310\17=\323\20?\323\21@\330\21D\335\21D"
+  "\342\22E\346\22I\353\23I\356\23K\362\24M\365\24N\370\25P\372\26R\374\26T"
+  "\376\26V\377\27X\377\27Z\377\30\\\376\31`\376\31`\375\32b\373\32d\371\33"
+  "f\366\34j\363\34j\360\35l\354\36n\350\36r\344\37r\337\40t\333\40w\326!y\321"
+  "\"|\314#~\307$\201\301$\204\267%\207\267&\212\261'\214\254(\217\247(\222"
+  "\241)\226\234*\231\227+\234\222,\237\216-\242\211.\245\205/\251\2010\254"
+  "}1\257z2\262w3\266t4\271p5\274m6\277j7\302f8\305c9\310`:\314\\;\317Y<\321"
+  "V>\324S?\327P@\332LA\335IB\337FC\342CE\344@F\347=G\351;I\3538I\3558M\357"
+  "3P\3610S\363.V\365+Y\366)\\\370'`\371%d\372#g\373\"l\374\40p\374\37t\374"
+  "\35t\375\34}\376\33\202\376\32\202\375\31\213\375\30\220\375\27\225\375\27"
+  "\232\373\26\237\372\25\244\371\24\251\370\23\256\367\23\262\367\22\267\364"
+  "\21\274\362\20\300\361\20\305\357\17\311\355\16\311\353\16\322\351\15\326"
+  "\346\15\332\346\14\336\344\14\341\337\13\341\335\13\350\332\12\353\330\11"
+  "\356\330\11\360\322\10\362\320\10\364\320\10\364\312\7\366\307\7\366\304"
+  "\7\367\302\6\367\277\6\370\274\5\367\271\5\367\271\5\367\263\4\365\260\4"
+  "\364\255\4\363\253\3\362\250\3\361\245\3\360\242\3\357\240\3\357\235\2\355"
+  "\232\2\355\227\2\354\225\2\353\221\1\353\216\1\353\216\1\353\213\1\353\204"
+  "\1\353\201\1\354}\1\354y\0\354v\0\355r\0\355n\0\355j\0\356f\0\356b\0\357"
+  "_\0\357[\0\357W\0\357S\0\360O\0\360O\0\361K\0\361C\0\362@\0\363<\0\3638\0"
+  "\3648\0\3641\0\365.\0\366+\0\366'\0\367'\0\370!\0\370\36\0\370\33\0\371\30"
+  "\0\371\26\0\373\26\0\373\23\0\374\15\0\374\13\0\375\10\0\375\5\0\376\3\0",
+};
+
+static const GstGLEffectsCurve sepia_curve = {
+  256, 1, 3,
+  "\0\0\0\0\0\0\0\0\0\0\1\0\1\1\0\1\1\0\1\1\1\2\1\1\2\2\1\3\2\1\3\2\1\3\2\1"
+  "\4\3\2\4\3\2\4\3\2\6\4\2\6\4\2\6\4\2\7\5\2\7\5\3\11\6\3\11\6\3\12\7\3\13"
+  "\10\3\15\10\4\16\11\4\17\11\4\21\12\4\22\13\4\22\13\5\23\14\5\24\15\5\26"
+  "\16\6\31\20\6\31\21\6\32\22\7\34\22\7\35\23\7\40\24\10\40\26\10!\26\11#\30"
+  "\11&\31\12&\32\12'\34\13)\34\13*\37\13,\37\13-\40\14.\"\15""0\"\15""2#\17"
+  """3&\17""4&\17""5'\20""8(\21""9)\21:*\23<,\23=-\23A.\24A0\25B0\25C2\26D3"
+  "\30H4\30H7\31K7\32K8\32L9\33M:\34P<\34Q=\35S>\37T?\37UA\40VB!XC!ZD#\\F#^"
+  "G#^J$`J&bK'bM'eM(fO)gP)iQ*kS,mT-mU-nV.oX/rY0sZ2u]2v]3w^3x`4za5{c7|c8~e8\177"
+  "f9\200i:\203i<\204j<\206k=\207m>\210n?\211o?\213qA\214rC\215sC\217uD\220"
+  "vD\221wF\223xG\224zH\225{J\227|K\230~K\231\177L\232\200M\234\202O\235\203"
+  "P\236\204Q\240\206Q\241\207S\242\210T\243\211U\245\213V\246\214X\247\215"
+  "Y\250\217Y\252\220Z\253\221\\\254\223]\254\224^\255\225`\257\227a\260\230"
+  "b\261\231c\262\232e\264\234e\265\235f\266\236g\267\240i\267\241i\272\242"
+  "k\273\243m\274\245n\274\246o\276\247q\277\250r\300\252s\301\253u\302\254"
+  "v\304\255w\305\257x\306\257z\306\261{\307\262|\310\264~\310\265\177\313\266"
+  "\200\314\267\202\315\267\203\316\272\204\317\273\206\317\274\207\320\276"
+  "\210\322\277\211\323\277\213\324\301\214\325\302\215\326\304\217\326\305"
+  "\220\327\306\221\327\307\223\331\310\224\333\311\225\334\311\227\334\313"
+  "\227\335\315\231\335\316\231\337\317\234\340\320\235\341\320\235\341\323"
+  "\240\342\324\241\343\324\242\343\326\243\345\327\245\345\330\245\346\331"
+  "\250\346\333\252\347\334\253\351\335\254\351\335\255\351\337\257\352\340"
+  "\260\353\341\260\354\342\262\355\343\264\355\344\265\355\345\266\356\346"
+  "\266\356\347\272\357\350\273\360\351\274\360\351\276\361\352\277\361\353"
+  "\300\362\353\301\362\354\302\362\355\304\362\356\305\364\357\305\364\357"
+  "\310\364\360\311\365\361\313\365\361\314\366\362\315\366\362\316\366\363"
+  "\316\367\364\320\367\364\320\367\365\324\367\365\324\370\366\326\370\366"
+  "\327\371\366\330\371\367\331\371\367\333\371\370\333\372\370\336\372\370"
+  "\336\372\371\340\373\371\341\373\372\342\373\372\343\374\372\344\374\373"
+  "\344\374\373\347\374\374\350\375\374\351\375\374\351\375\374\352\375\375"
+  "\352\376\375\353\376\376\355\376\376\356\376\376\357\377\377\357",
+};
+
+static const GstGLEffectsCurve xray_curve = {
+  256, 1, 3,
+  "\377\377\377\377\377\377\376\376\376\375\375\376\374\375\375\373\374\375"
+  "\372\374\374\371\374\374\370\373\373\366\373\372\366\372\372\365\372\371"
+  "\363\371\371\363\371\370\362\370\370\360\370\367\360\367\366\357\367\365"
+  "\356\366\365\355\366\364\353\365\363\353\365\363\352\364\362\351\363\362"
+  "\347\363\361\346\362\361\345\362\361\344\362\360\343\361\357\343\361\356"
+  "\342\360\356\341\360\356\340\357\355\336\356\354\336\356\354\335\355\353"
+  "\334\355\353\333\355\352\331\354\351\331\353\351\330\353\350\327\353\350"
+  "\325\352\347\325\351\347\324\350\346\323\350\345\322\347\344\321\347\344"
+  "\320\347\344\317\346\343\316\346\342\315\345\341\314\344\341\313\344\340"
+  "\312\344\340\311\343\337\310\342\337\307\342\335\306\341\335\305\341\335"
+  "\303\340\334\303\337\333\302\337\333\301\337\332\300\336\331\276\335\331"
+  "\276\334\330\274\334\330\274\334\327\273\333\327\272\333\326\271\332\325"
+  "\270\332\325\267\331\324\266\330\323\265\330\323\264\327\322\263\327\321"
+  "\262\326\320\261\325\320\257\325\317\257\324\317\256\324\316\254\323\315"
+  "\254\322\315\253\322\314\252\321\313\251\321\313\250\320\312\246\317\311"
+  "\245\317\311\245\316\310\244\316\307\243\315\307\242\314\306\241\314\305"
+  "\240\312\305\237\312\304\236\312\303\235\311\303\234\311\302\233\307\301"
+  "\232\307\300\231\307\300\230\306\277\227\305\276\226\305\276\225\304\275"
+  "\224\303\274\223\303\273\222\302\273\221\301\272\220\301\271\217\300\270"
+  "\216\277\270\215\277\267\214\276\266\213\275\265\212\275\265\211\274\264"
+  "\210\273\263\207\273\262\206\272\262\205\271\261\204\270\260\203\270\257"
+  "\202\267\257\201\266\256\200\266\255\177\265\254~\264\253}\263\253|\263\252"
+  "{\262\251z\261\250y\260\247x\260\247w\257\246v\256\245u\255\244t\255\243"
+  "s\254\243r\253\242q\252\241p\252\240o\251\237n\250\236m\247\235l\246\235"
+  "l\246\235j\245\233i\244\232h\243\231g\242\230f\242\227e\241\226d\240\226"
+  "c\237\225b\236\224a\235\223`\234\222_\234\221_\233\220]\232\217\\\231\216"
+  "\\\230\215Z\227\214Y\226\214X\226\213W\225\212V\224\211U\223\210T\222\207"
+  "S\221\206R\221\205Q\217\204P\216\203O\215\202N\215\201M\214\200M\213\177"
+  "K\212~J\211}I\211|H\210|G\206zG\205zE\204xD\203vC\203vB\201tA\200s@\200q"
+  "@~p>}o>|o<{l<yk;xi9wh8wg8te6sd5qd4pa3n_2m]1k\\0j\\0hY.fW-dU,cT+aR*_P)_O("
+  "]M'YK'XI%VI$TF$RD\"OB!M@\40K?\37I=\37G=\35E9\34C9\34A5\33>5\31<2\31<0\27"
+  ":.\27""5,\26""3*\24""1*\23.&\22.&\22*\"\21'\40\17%\36\16\"\34\15\"\32\14"
+  "\36\32\13\33\26\13\31\24\11\26\22\11\24\20\7\24\16\6\21\16\5\14\14\4\12\10"
+  "\3\7\6\3\5\4\1\2\2",
+};
+
+#endif
diff --git a/ext/gl/effects/gstgleffectsin.c b/ext/gl/effects/gstgleffectsin.c
new file mode 100644 (file)
index 0000000..1b229d2
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 "../gstgleffects.h"
+
+static void
+gst_gl_effects_sin_callback (gint width, gint height, guint texture,
+    gpointer data)
+{
+  GstGLShader *shader;
+  GstGLEffects *effects = GST_GL_EFFECTS (data);
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+  GstGLContext *context = filter->context;
+  GstGLFuncs *gl = context->gl_vtable;
+
+  shader = g_hash_table_lookup (effects->shaderstable, "sin0");
+
+  if (!shader) {
+    shader = gst_gl_shader_new (context);
+    g_hash_table_insert (effects->shaderstable, "sin0", shader);
+  }
+
+  if (!gst_gl_shader_compile_and_check (shader,
+          sin_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
+    gst_gl_context_set_error (context, "Failed to initialize sin shader");
+    GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
+        ("%s", gst_gl_context_get_error ()), (NULL));
+    return;
+  }
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+
+  gst_gl_shader_use (shader);
+
+  gl->ActiveTexture (GL_TEXTURE0);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+
+  gst_gl_shader_set_uniform_1i (shader, "tex", 0);
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
+
+void
+gst_gl_effects_sin (GstGLEffects * effects)
+{
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+
+  gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
+      effects->outtexture, gst_gl_effects_sin_callback, effects);
+}
diff --git a/ext/gl/effects/gstgleffectsquare.c b/ext/gl/effects/gstgleffectsquare.c
new file mode 100644 (file)
index 0000000..127e39f
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 "../gstgleffects.h"
+
+static void
+gst_gl_effects_square_callback (gint width, gint height, guint texture,
+    gpointer data)
+{
+  GstGLShader *shader;
+  GstGLEffects *effects = GST_GL_EFFECTS (data);
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+  GstGLContext *context = filter->context;
+  GstGLFuncs *gl = context->gl_vtable;
+
+  shader = g_hash_table_lookup (effects->shaderstable, "square0");
+
+  if (!shader) {
+    shader = gst_gl_shader_new (context);
+    g_hash_table_insert (effects->shaderstable, "square0", shader);
+  }
+
+  if (!gst_gl_shader_compile_and_check (shader,
+          square_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
+    gst_gl_context_set_error (context, "Failed to initialize square shader");
+    GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
+        ("%s", gst_gl_context_get_error ()), (NULL));
+    return;
+  }
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+
+  gst_gl_shader_use (shader);
+
+  gl->ActiveTexture (GL_TEXTURE0);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+
+  gst_gl_shader_set_uniform_1i (shader, "tex", 0);
+
+  gst_gl_shader_set_uniform_1f (shader, "width", (gfloat) width / 2.0f);
+  gst_gl_shader_set_uniform_1f (shader, "height", (gfloat) height / 2.0f);
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
+
+void
+gst_gl_effects_square (GstGLEffects * effects)
+{
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+
+  gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
+      effects->outtexture, gst_gl_effects_square_callback, effects);
+}
diff --git a/ext/gl/effects/gstgleffectsqueeze.c b/ext/gl/effects/gstgleffectsqueeze.c
new file mode 100644 (file)
index 0000000..14a9bcb
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 "../gstgleffects.h"
+
+#define USING_OPENGL(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_OPENGL)
+#define USING_OPENGL3(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_OPENGL3)
+#define USING_GLES(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES)
+#define USING_GLES2(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES2)
+#define USING_GLES3(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES3)
+
+static void
+gst_gl_effects_squeeze_callback (gint width, gint height, guint texture,
+    gpointer data)
+{
+  GstGLShader *shader;
+  GstGLFilter *filter = GST_GL_FILTER (data);
+  GstGLEffects *effects = GST_GL_EFFECTS (data);
+  GstGLContext *context = filter->context;
+  GstGLFuncs *gl = context->gl_vtable;
+
+  shader = g_hash_table_lookup (effects->shaderstable, "squeeze0");
+
+  if (!shader) {
+    shader = gst_gl_shader_new (context);
+    g_hash_table_insert (effects->shaderstable, "squeeze0", shader);
+
+#if GST_GL_HAVE_GLES2
+    if (USING_GLES2 (context)) {
+      if (shader) {
+        GError *error = NULL;
+        gst_gl_shader_set_vertex_source (shader, vertex_shader_source);
+        gst_gl_shader_set_fragment_source (shader,
+            squeeze_fragment_source_gles2);
+
+        gst_gl_shader_compile (shader, &error);
+        if (error) {
+          gst_gl_context_set_error (context,
+              "Failed to initialize squeeze shader, %s", error->message);
+          g_error_free (error);
+          error = NULL;
+          gst_gl_shader_use (NULL);
+          GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
+              ("%s", gst_gl_context_get_error ()), (NULL));
+        } else {
+          filter->draw_attr_position_loc =
+              gst_gl_shader_get_attribute_location (shader, "a_position");
+          filter->draw_attr_texture_loc =
+              gst_gl_shader_get_attribute_location (shader, "a_texCoord");
+        }
+      }
+    }
+#endif
+#if GST_GL_HAVE_OPENGL
+    if (USING_OPENGL (context)) {
+      if (!gst_gl_shader_compile_and_check (shader,
+              squeeze_fragment_source_opengl, GST_GL_SHADER_FRAGMENT_SOURCE)) {
+        gst_gl_context_set_error (context,
+            "Failed to initialize squeeze shader");
+        GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
+            ("%s", gst_gl_context_get_error ()), (NULL));
+        return;
+      }
+    }
+#endif
+  }
+#if GST_GL_HAVE_OPENGL
+  if (USING_OPENGL (context)) {
+    gl->MatrixMode (GL_PROJECTION);
+    gl->LoadIdentity ();
+  }
+#endif
+
+  gst_gl_shader_use (shader);
+
+  gl->ActiveTexture (GL_TEXTURE0);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+
+  gst_gl_shader_set_uniform_1i (shader, "tex", 0);
+
+#if GST_GL_HAVE_OPENGL
+  if (USING_OPENGL (filter->context)) {
+    gst_gl_shader_set_uniform_1f (shader, "width", (gfloat) width / 2.0f);
+    gst_gl_shader_set_uniform_1f (shader, "height", (gfloat) height / 2.0f);
+  }
+#endif
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
+
+void
+gst_gl_effects_squeeze (GstGLEffects * effects)
+{
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+
+  gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
+      effects->outtexture, gst_gl_effects_squeeze_callback, effects);
+}
diff --git a/ext/gl/effects/gstgleffectssources.c b/ext/gl/effects/gstgleffectssources.c
new file mode 100644 (file)
index 0000000..eadcccd
--- /dev/null
@@ -0,0 +1,481 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gl/gstglconfig.h>
+
+#include "../gstgleffects.h"
+#include "gstgleffectssources.h"
+#include <math.h>
+
+/* A common file for sources is needed since shader sources can be
+ * generic and reused by several effects */
+
+/* FIXME */
+/* Move sooner or later into single .frag .vert files and either bake
+ * them into a c file at compile time or load them at run time */
+
+
+/* fill a normalized and zero centered gaussian vector for separable
+ * gaussian convolution */
+
+void
+fill_gaussian_kernel (float *kernel, int size, float sigma)
+{
+  int i;
+  float sum;
+  int l;
+
+  /* need an odd sized vector to center it at zero */
+  g_return_if_fail ((size % 2) != 0);
+
+  sum = 0.0;
+  l = (size - 1) / 2;
+
+  for (i = 0; i < size; i++) {
+    kernel[i] = expf (-0.5 * pow ((i - l) / sigma, 2.0));
+    sum += kernel[i];
+  }
+
+  for (i = 0; i < size; i++) {
+    kernel[i] /= sum;
+  }
+}
+
+/* *INDENT-OFF* */
+
+/* Vertex shader */
+const gchar *vertex_shader_source =
+  "attribute vec4 a_position;"
+  "attribute vec2 a_texCoord;"
+  "varying vec2 v_texCoord;"
+  "void main()"
+  "{"
+  "   gl_Position = a_position;"
+  "   v_texCoord = a_texCoord;"
+  "}";
+
+/* Identity effect */
+const gchar *identity_fragment_source =
+  "precision mediump float;"
+  "varying vec2 v_texCoord;"
+  "uniform sampler2D tex;"
+  "void main()"
+  "{"
+  "  gl_FragColor = texture2D(tex, v_texCoord);"
+  "}";
+
+/* Mirror effect */
+#if GST_GL_HAVE_OPENGL
+const gchar *mirror_fragment_source_opengl =
+  "uniform sampler2D tex;"
+  "void main () {"
+  "  vec2 texturecoord = gl_TexCoord[0].xy;"
+  "  vec2 normcoord;"
+  "  normcoord = texturecoord - 0.5;"
+  "  normcoord.x *= sign (normcoord.x);"
+  "  texturecoord = normcoord + 0.5;"
+  "  vec4 color = texture2D (tex, texturecoord);"
+  "  gl_FragColor = color * gl_Color;"
+  "}";
+#endif
+#if GST_GL_HAVE_GLES2
+const gchar *mirror_fragment_source_gles2 =
+  "precision mediump float;"
+  "varying vec2 v_texCoord;"
+  "uniform sampler2D tex;"
+  "void main () {"
+  "  vec2 texturecoord = v_texCoord.xy;"
+  "  float normcoord = texturecoord.x - 0.5;"
+  "  normcoord *= sign (normcoord);"
+  "  texturecoord.x = normcoord + 0.5;"
+  "  gl_FragColor = texture2D (tex, texturecoord);"
+  "}";
+#endif
+
+/* Squeeze effect */
+#if GST_GL_HAVE_OPENGL
+const gchar *squeeze_fragment_source_opengl =
+  "uniform sampler2D tex;"
+  "void main () {"
+  "  vec2 texturecoord = gl_TexCoord[0].xy;"
+  "  vec2 normcoord = texturecoord - 0.5;"
+  "  float r = length (normcoord);"
+  "  r = pow(r, 0.40)*1.3;"
+  "  normcoord = normcoord / r;"
+  "  texturecoord = (normcoord + 0.5);"
+  "  gl_FragColor = texture2D (tex, texturecoord);"
+  "}";
+#endif
+#if GST_GL_HAVE_GLES2
+const gchar *squeeze_fragment_source_gles2 =
+  "precision mediump float;"
+  "varying vec2 v_texCoord;"
+  "uniform sampler2D tex;"
+  "void main () {"
+  "  vec2 texturecoord = v_texCoord.xy;"
+  "  vec2 normcoord = texturecoord - 0.5;"
+  "  float r = length (normcoord);"
+  "  r = pow(r, 0.40)*1.3;"
+  "  normcoord = normcoord / r;"
+  "  texturecoord = (normcoord + 0.5);"
+  "  gl_FragColor = texture2D (tex, texturecoord);"
+  "}";
+#endif
+
+/* Stretch Effect */
+const gchar *stretch_fragment_source =
+  "uniform sampler2D tex;"
+  "void main () {"
+  "  vec2 texturecoord = gl_TexCoord[0].xy;"
+  "  vec2 normcoord;"
+  "  normcoord = texturecoord - 0.5;"
+  "  float r = length (normcoord);"
+  "  normcoord *= 2.0 - smoothstep(0.0, 0.35, r);"
+  "  texturecoord = normcoord + 0.5;"
+  "  vec4 color = texture2D (tex, texturecoord);"
+  "  gl_FragColor = color * gl_Color;"
+  "}";
+
+/* Light Tunnel effect */
+const gchar *tunnel_fragment_source =
+  "uniform sampler2D tex;"
+  "void main () {"
+  "  vec2 texturecoord = gl_TexCoord[0].xy;"
+  "  vec2 normcoord;"
+  /* little trick with normalized coords to obtain a circle with
+   * rect textures */
+  "  normcoord = (texturecoord - 0.5);"
+  "  float r = length(normcoord);"
+  "  normcoord *= clamp (r, 0.0, 0.275) / r;"
+  "  texturecoord = normcoord + 0.5;"
+  "  vec4 color = texture2D (tex, texturecoord); "
+  "  gl_FragColor = color;"
+  "}";
+
+/* FishEye effect */
+const gchar *fisheye_fragment_source =
+  "uniform sampler2D tex;"
+  "void main () {"
+  "  vec2 texturecoord = gl_TexCoord[0].xy;"
+  "  vec2 normcoord;"
+  "  normcoord = texturecoord - 0.5;"
+  "  float r = length (normcoord);"
+  "  normcoord *= r * sqrt(2);"
+  "  texturecoord = normcoord + 0.5;"
+  "  vec4 color = texture2D (tex, texturecoord);"
+  "  gl_FragColor = color;"
+  "}";
+
+
+/* Twirl effect */
+const gchar *twirl_fragment_source =
+  "uniform sampler2D tex;"
+  "void main () {"
+  "  vec2 texturecoord = gl_TexCoord[0].xy;"
+  "  vec2 normcoord;"
+  "  normcoord = texturecoord - 0.5;"
+  "  float r = length (normcoord);"
+  /* calculate rotation angle: maximum (about pi/2) at the origin and
+   * gradually decrease it up to 0.6 of each quadrant */
+  "  float phi = (1.0 - smoothstep (0.0, 0.3, r)) * 1.6;"
+  /* precalculate sin phi and cos phi, save some alu */
+  "  float s = sin(phi);"
+  "  float c = cos(phi);"
+  /* rotate */
+  "  normcoord *= mat2(c, s, -s, c);"
+  "  texturecoord = normcoord + 0.5;"
+  "  vec4 color = texture2D (tex, texturecoord); "
+  "  gl_FragColor = color;"
+  "}";
+
+
+/* Bulge effect */
+const gchar *bulge_fragment_source =
+  "uniform sampler2D tex;"
+  "void main () {"
+  "  vec2 texturecoord = gl_TexCoord[0].xy;"
+  "  vec2 normcoord;"
+  "  normcoord = texturecoord - 0.5;"
+  "  float r =  length (normcoord);"
+  "  normcoord *= smoothstep (-0.05, 0.25, r);"
+  "  texturecoord = normcoord + 0.5;"
+  "  vec4 color = texture2D (tex, texturecoord);"
+  "  gl_FragColor = color;"
+  "}";
+
+
+/* Square Effect */
+const gchar *square_fragment_source =
+  "uniform sampler2D tex;"
+  "void main () {"
+  "  vec2 texturecoord = gl_TexCoord[0].xy;"
+  "  vec2 normcoord;"
+  "  normcoord = texturecoord - 0.5;"
+  "  float r = length (normcoord);"
+  "  normcoord *= 1.0 + smoothstep(0.125, 0.25, abs(normcoord));"
+  "  normcoord /= 2.0; /* zoom amount */"
+  "  texturecoord = normcoord + 0.5;"
+  "  vec4 color = texture2D (tex, texturecoord);"
+  "  gl_FragColor = color * gl_Color;"
+  "}";
+
+
+const gchar *luma_threshold_fragment_source =
+  "uniform sampler2D tex;"
+  "void main () {"
+  "  vec2 texturecoord = gl_TexCoord[0].st;"
+  "  vec4 color = texture2D(tex, texturecoord);"
+  "  float luma = dot(color.rgb, vec3(0.2125, 0.7154, 0.0721));"    /* BT.709 (from orange book) */
+  "  gl_FragColor = vec4 (vec3 (smoothstep (0.30, 0.50, luma)), color.a);"
+  "}";
+
+const gchar *sep_sobel_length_fragment_source =
+  "uniform sampler2D tex;"
+  "uniform bool invert;"
+  "void main () {"
+  "  vec4 g = texture2D (tex, gl_TexCoord[0].st);"
+  /* restore black background with grey edges */
+  "  g -= vec4(0.5, 0.5, 0.0, 0.0);"
+  "  float len = length (g);"
+  /* little trick to avoid IF operator */
+  /* TODO: test if a standalone inverting pass is worth */
+  "  gl_FragColor = abs(vec4(vec3(float(invert) - len), 1.0));"
+  "}";
+
+const gchar *desaturate_fragment_source =
+  "uniform sampler2D tex;"
+  "void main () {"
+  "  vec4 color = texture2D (tex, gl_TexCoord[0].st);"
+  "  float luma = dot(color.rgb, vec3(0.2125, 0.7154, 0.0721));"
+  "  gl_FragColor = vec4(vec3(luma), color.a);"
+  "}";
+
+const gchar *sep_sobel_hconv3_fragment_source =
+  "uniform sampler2D tex;"
+  "uniform float width;"
+  "void main () {"
+  "  float w = 1.0 / width;"
+  "  vec2 texturecoord[3];"
+  "  texturecoord[1] = gl_TexCoord[0].st;"
+  "  texturecoord[0] = texturecoord[1] - vec2(w, 0.0);"
+  "  texturecoord[2] = texturecoord[1] + vec2(w, 0.0);"
+  "  float grad_kern[3];"
+  "  grad_kern[0] = 1.0;"
+  "  grad_kern[1] = 0.0;"
+  "  grad_kern[2] = -1.0;"
+  "  float blur_kern[3];"
+  "  blur_kern[0] = 0.25;"
+  "  blur_kern[1] = 0.5;"
+  "  blur_kern[2] = 0.25;"
+  "  int i;"
+  "  vec4 sum = vec4 (0.0);"
+  "  for (i = 0; i < 3; i++) { "
+  "    vec4 neighbor = texture2D(tex, texturecoord[i]); "
+  "    sum.r = neighbor.r * blur_kern[i] + sum.r;"
+  "    sum.g = neighbor.g * grad_kern[i] + sum.g;"
+  "  }"
+  "  gl_FragColor = sum + vec4(0.0, 0.5, 0.0, 0.0);"
+  "}";
+
+const gchar *sep_sobel_vconv3_fragment_source =
+  "uniform sampler2D tex;"
+  "uniform float height;"
+  "void main () {"
+  "  float h = 1.0 / height;"
+  "  vec2 texturecoord[3];"
+  "  texturecoord[1] = gl_TexCoord[0].st;"
+  "  texturecoord[0] = texturecoord[1] - vec2(0.0, h);"
+  "  texturecoord[2] = texturecoord[1] + vec2(0.0, h);"
+  "  float grad_kern[3];"
+  "  grad_kern[0] = 1.0;"
+  "  grad_kern[1] = 0.0;"
+  "  grad_kern[2] = -1.0;"
+  "  float blur_kern[3];"
+  "  blur_kern[0] = 0.25;"
+  "  blur_kern[1] = 0.5;"
+  "  blur_kern[2] = 0.25;"
+  "  int i;"
+  "  vec4 sum = vec4 (0.0);"
+  "  for (i = 0; i < 3; i++) { "
+  "    vec4 neighbor = texture2D(tex, texturecoord[i]); "
+  "    sum.r = neighbor.r * grad_kern[i] + sum.r;"
+  "    sum.g = neighbor.g * blur_kern[i] + sum.g;"
+  "  }"
+  "  gl_FragColor = sum + vec4(0.5, 0.0, 0.0, 0.0);"
+  "}";
+
+/* horizontal convolution 7x7 */
+const gchar *hconv7_fragment_source =
+  "uniform sampler2D tex;"
+  "uniform float kernel[7];"
+  "uniform float width;"
+  "void main () {"
+  "  float w = 1.0 / width;"
+  "  vec2 texturecoord[7];"
+  "  texturecoord[3] = gl_TexCoord[0].st;"
+  "  texturecoord[2] = texturecoord[3] - vec2(w, 0.0);"
+  "  texturecoord[1] = texturecoord[2] - vec2(w, 0.0);"
+  "  texturecoord[0] = texturecoord[1] - vec2(w, 0.0);"
+  "  texturecoord[4] = texturecoord[3] + vec2(w, 0.0);"
+  "  texturecoord[5] = texturecoord[4] + vec2(w, 0.0);"
+  "  texturecoord[6] = texturecoord[5] + vec2(w, 0.0);"
+  "  int i;"
+  "  vec4 sum = vec4 (0.0);"
+  "  for (i = 0; i < 7; i++) { "
+  "    vec4 neighbor = texture2D(tex, texturecoord[i]); "
+  "    sum += neighbor * kernel[i];"
+  "  }"
+  "  gl_FragColor = sum;"
+  "}";
+
+/* vertical convolution 7x7 */
+const gchar *vconv7_fragment_source =
+  "uniform sampler2D tex;"
+  "uniform float kernel[7];"
+  "uniform float height;"
+  "void main () {"
+  "  float h = 1.0 / height;"
+  "  vec2 texturecoord[7];"
+  "  texturecoord[3] = gl_TexCoord[0].st;"
+  "  texturecoord[2] = texturecoord[3] - vec2(0.0, h);"
+  "  texturecoord[1] = texturecoord[2] - vec2(0.0, h);"
+  "  texturecoord[0] = texturecoord[1] - vec2(0.0, h);"
+  "  texturecoord[4] = texturecoord[3] + vec2(0.0, h);"
+  "  texturecoord[5] = texturecoord[4] + vec2(0.0, h);"
+  "  texturecoord[6] = texturecoord[5] + vec2(0.0, h);"
+  "  int i;"
+  "  vec4 sum = vec4 (0.0);"
+  "  for (i = 0; i < 7; i++) { "
+  "    vec4 neighbor = texture2D(tex, texturecoord[i]);"
+  "    sum += neighbor * kernel[i];"
+  "  }"
+  "  gl_FragColor = sum;"
+  "}";
+
+
+/* TODO: support several blend modes */
+const gchar *sum_fragment_source =
+  "uniform sampler2D base;"
+  "uniform sampler2D blend;"
+  "uniform float alpha;"
+  "uniform float beta;"
+  "void main () {"
+  "  vec4 basecolor = texture2D (base, gl_TexCoord[0].st);"
+  "  vec4 blendcolor = texture2D (blend, gl_TexCoord[0].st);"
+  "  gl_FragColor = alpha * basecolor + beta * blendcolor;"
+  "}";
+
+const gchar *multiply_fragment_source =
+  "uniform sampler2D base;"
+  "uniform sampler2D blend;"
+  "uniform float alpha;"
+  "void main () {"
+  "  vec4 basecolor = texture2D (base, gl_TexCoord[0].st);"
+  "  vec4 blendcolor = texture2D (blend, gl_TexCoord[0].st);"
+  "  gl_FragColor = (1.0 - alpha) * basecolor + alpha * basecolor * blendcolor;"
+  "}";
+
+/* lut operations, map luma to tex1d, see orange book (chapter 19) */
+const gchar *luma_to_curve_fragment_source =
+  "uniform sampler2D tex;"
+  "uniform sampler1D curve;"
+  "void main () {"
+  "  vec2 texturecoord = gl_TexCoord[0].st;"
+  "  vec4 color = texture2D (tex, texturecoord);"
+  "  float luma = dot(color.rgb, vec3(0.2125, 0.7154, 0.0721));"
+  "  color = texture1D(curve, luma);"
+  "  gl_FragColor = color;"
+  "}";
+
+
+/* lut operations, map rgb to tex1d, see orange book (chapter 19) */
+const gchar *rgb_to_curve_fragment_source =
+  "uniform sampler2D tex;"
+  "uniform sampler1D curve;"
+  "void main () {"
+  "  vec4 color = texture2D (tex, gl_TexCoord[0].st);"
+  "  vec4 outcolor;"
+  "  outcolor.r = texture1D(curve, color.r).r;"
+  "  outcolor.g = texture1D(curve, color.g).g;"
+  "  outcolor.b = texture1D(curve, color.b).b;"
+  "  outcolor.a = color.a;"
+  "  gl_FragColor = outcolor;"
+  "}";
+
+const gchar *sin_fragment_source =
+  "uniform sampler2D tex;"
+  "void main () {"
+  "  vec4 color = texture2D (tex, vec2(gl_TexCoord[0].st));"
+  "  float luma = dot(color.rgb, vec3(0.2125, 0.7154, 0.0721));"
+/* calculate hue with the Preucil formula */
+  "  float cosh = color.r - 0.5*(color.g + color.b);"
+/* sqrt(3)/2 = 0.866 */
+  "  float sinh = 0.866*(color.g - color.b);"
+/* hue = atan2 h */
+  "  float sch = (1.0-sinh)*cosh;"
+/* ok this is a little trick I came up because I didn't find any
+ * detailed proof of the Preucil formula. The issue is that tan(h) is
+ * pi-periodic so the smoothstep thing gives both reds (h = 0) and
+ * cyans (h = 180). I don't want to use atan since it requires
+ * branching and doesn't work on i915. So take only the right half of
+ * the circle where cosine is positive */
+/* take a slightly purple color trying to get rid of human skin reds */
+/* tanh = +-1.0 for h = +-45, where yellow=60, magenta=-60 */
+  "  float a = smoothstep (0.3, 1.0, sch);"
+  "  float b = smoothstep (-0.4, -0.1, sinh);"
+  "  float mix = a * b;"
+  "  gl_FragColor = color * mix + luma * (1.0 - mix);"
+  "}";
+
+const gchar *interpolate_fragment_source =
+  "uniform sampler2D base;"
+  "uniform sampler2D blend;"
+  "void main () {"
+  "vec4 basecolor = texture2D (base, gl_TexCoord[0].st);"
+  "vec4 blendcolor = texture2D (blend, gl_TexCoord[0].st);"
+  "vec4 white = vec4(1.0);"
+  "gl_FragColor = blendcolor + (1.0 - blendcolor.a) * basecolor;"
+  "}";
+
+const gchar *texture_interp_fragment_source =
+  "uniform sampler2D base;"
+  "uniform sampler2D blend;"
+  "uniform sampler2D alpha;"
+  "void main () {"
+  "  vec4 basecolor = texture2D (base, gl_TexCoord[0].st);"
+  "  vec4 blendcolor = texture2D (blend, gl_TexCoord[0].st);"
+  "  vec4 alphacolor = texture2D (alpha, gl_TexCoord[0].st);"
+  "  gl_FragColor = (alphacolor * blendcolor) + (1.0 - alphacolor) * basecolor;"
+  "}";
+
+const gchar *difference_fragment_source =
+  "uniform sampler2D saved;"
+  "uniform sampler2D current;"
+  "void main () {"
+  "vec4 savedcolor = texture2D (saved, gl_TexCoord[0].st);"
+  "vec4 currentcolor = texture2D (current, gl_TexCoord[0].st);"
+  "gl_FragColor = vec4 (step (0.12, length (savedcolor - currentcolor)));"
+  "}";
+
+/* *INDENT-ON* */
diff --git a/ext/gl/effects/gstgleffectssources.h b/ext/gl/effects/gstgleffectssources.h
new file mode 100644 (file)
index 0000000..ba05de1
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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.
+ */
+
+#ifndef __GST_GL_EFFECTS_SOURCES_H__
+#define __GST_GL_EFFECTS_SOURCES_H__
+
+extern const gchar *vertex_shader_source;
+extern const gchar *identity_fragment_source;
+#if GST_GL_HAVE_OPENGL
+extern const gchar *mirror_fragment_source_opengl;
+extern const gchar *squeeze_fragment_source_opengl;
+#endif
+#if GST_GL_HAVE_GLES2
+extern const gchar *mirror_fragment_source_gles2;
+extern const gchar *squeeze_fragment_source_gles2;
+#endif
+extern const gchar *stretch_fragment_source;
+extern const gchar *tunnel_fragment_source;
+extern const gchar *fisheye_fragment_source;
+extern const gchar *twirl_fragment_source;
+extern const gchar *bulge_fragment_source;
+extern const gchar *square_fragment_source;
+extern const gchar *luma_threshold_fragment_source;
+extern const gchar *sep_sobel_length_fragment_source;
+extern const gchar *desaturate_fragment_source;
+extern const gchar *sep_sobel_hconv3_fragment_source;
+extern const gchar *sep_sobel_vconv3_fragment_source;
+extern const gchar *hconv7_fragment_source;
+extern const gchar *vconv7_fragment_source;
+extern const gchar *sum_fragment_source;
+extern const gchar *luma_to_curve_fragment_source;
+extern const gchar *rgb_to_curve_fragment_source;
+extern const gchar *sin_fragment_source;
+extern const gchar *interpolate_fragment_source;
+extern const gchar *texture_interp_fragment_source;
+extern const gchar *difference_fragment_source;
+extern const gchar *multiply_fragment_source;
+
+void fill_gaussian_kernel (float *kernel, int size, float sigma);
+
+#endif /* __GST_GL_EFFECTS_SOURCES_H__ */
diff --git a/ext/gl/effects/gstgleffectstretch.c b/ext/gl/effects/gstgleffectstretch.c
new file mode 100644 (file)
index 0000000..0b8b9d1
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 "../gstgleffects.h"
+
+static void
+gst_gl_effects_stretch_callback (gint width, gint height, guint texture,
+    gpointer data)
+{
+  GstGLShader *shader;
+  GstGLEffects *effects = GST_GL_EFFECTS (data);
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+  GstGLContext *context = filter->context;
+  GstGLFuncs *gl = context->gl_vtable;
+
+  shader = g_hash_table_lookup (effects->shaderstable, "stretch0");
+
+  if (!shader) {
+    shader = gst_gl_shader_new (context);
+    g_hash_table_insert (effects->shaderstable, "stretch0", shader);
+  }
+
+  if (!gst_gl_shader_compile_and_check (shader,
+          stretch_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
+    gst_gl_context_set_error (context, "Failed to initialize stretch shader");
+    GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
+        ("%s", gst_gl_context_get_error ()), (NULL));
+    return;
+  }
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+
+  gst_gl_shader_use (shader);
+
+  gl->ActiveTexture (GL_TEXTURE0);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+
+  gst_gl_shader_set_uniform_1i (shader, "tex", 0);
+
+  gst_gl_shader_set_uniform_1f (shader, "width", (gfloat) width / 2.0f);
+  gst_gl_shader_set_uniform_1f (shader, "height", (gfloat) height / 2.0f);
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
+
+void
+gst_gl_effects_stretch (GstGLEffects * effects)
+{
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+
+  gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
+      effects->outtexture, gst_gl_effects_stretch_callback, effects);
+}
diff --git a/ext/gl/effects/gstgleffecttunnel.c b/ext/gl/effects/gstgleffecttunnel.c
new file mode 100644 (file)
index 0000000..2188633
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 "../gstgleffects.h"
+
+static void
+gst_gl_effects_tunnel_callback (gint width, gint height, guint texture,
+    gpointer data)
+{
+  GstGLShader *shader;
+  GstGLEffects *effects = GST_GL_EFFECTS (data);
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+  GstGLContext *context = filter->context;
+  GstGLFuncs *gl = context->gl_vtable;
+
+  shader = g_hash_table_lookup (effects->shaderstable, "tunnel0");
+
+  if (!shader) {
+    shader = gst_gl_shader_new (context);
+    g_hash_table_insert (effects->shaderstable, "tunnel0", shader);
+  }
+
+  if (!gst_gl_shader_compile_and_check (shader,
+          tunnel_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
+    gst_gl_context_set_error (context, "Failed to initialize tunnel shader");
+    GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
+        ("%s", gst_gl_context_get_error ()), (NULL));
+    return;
+  }
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+
+  gst_gl_shader_use (shader);
+
+  gl->ActiveTexture (GL_TEXTURE0);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+
+  gst_gl_shader_set_uniform_1i (shader, "tex", 0);
+
+  gst_gl_shader_set_uniform_1f (shader, "width", (gfloat) width / 2.0f);
+  gst_gl_shader_set_uniform_1f (shader, "height", (gfloat) height / 2.0f);
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
+
+void
+gst_gl_effects_tunnel (GstGLEffects * effects)
+{
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+
+  gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
+      effects->outtexture, gst_gl_effects_tunnel_callback, effects);
+}
diff --git a/ext/gl/effects/gstgleffecttwirl.c b/ext/gl/effects/gstgleffecttwirl.c
new file mode 100644 (file)
index 0000000..22ce874
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 "../gstgleffects.h"
+
+static void
+gst_gl_effects_twirl_callback (gint width, gint height, guint texture,
+    gpointer data)
+{
+  GstGLShader *shader;
+  GstGLEffects *effects = GST_GL_EFFECTS (data);
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+  GstGLContext *context = filter->context;
+  GstGLFuncs *gl = context->gl_vtable;
+
+  shader = g_hash_table_lookup (effects->shaderstable, "twirl0");
+
+  if (!shader) {
+    shader = gst_gl_shader_new (GST_GL_FILTER (effects)->context);
+    g_hash_table_insert (effects->shaderstable, "twirl0", shader);
+  }
+
+  if (!gst_gl_shader_compile_and_check (shader,
+          twirl_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
+    gst_gl_context_set_error (context, "Failed to initialize twirl shader");
+    GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
+        ("%s", gst_gl_context_get_error ()), (NULL));
+    return;
+  }
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+
+  gst_gl_shader_use (shader);
+
+  gl->ActiveTexture (GL_TEXTURE0);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+
+  gst_gl_shader_set_uniform_1i (shader, "tex", 0);
+
+  gst_gl_shader_set_uniform_1f (shader, "width", (gfloat) width / 2.0f);
+  gst_gl_shader_set_uniform_1f (shader, "height", (gfloat) height / 2.0f);
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
+
+void
+gst_gl_effects_twirl (GstGLEffects * effects)
+{
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+
+  gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
+      effects->outtexture, gst_gl_effects_twirl_callback, effects);
+}
diff --git a/ext/gl/effects/gstgleffectxray.c b/ext/gl/effects/gstgleffectxray.c
new file mode 100644 (file)
index 0000000..bd70abf
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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 "../gstgleffects.h"
+#include "gstgleffectscurves.h"
+#include "gstgleffectlumatocurve.h"
+
+static gboolean kernel_ready = FALSE;
+static float gauss_kernel[7];
+
+static void
+gst_gl_effects_xray_step_one (gint width, gint height, guint texture,
+    gpointer data)
+{
+  GstGLEffects *effects = GST_GL_EFFECTS (data);
+
+  gst_gl_effects_luma_to_curve (effects, xray_curve, GST_GL_EFFECTS_CURVE_XRAY,
+      width, height, texture);
+}
+
+static void
+gst_gl_effects_xray_step_two (gint width, gint height, guint texture,
+    gpointer data)
+{
+  GstGLShader *shader;
+  GstGLEffects *effects = GST_GL_EFFECTS (data);
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+  GstGLContext *context = filter->context;
+  GstGLFuncs *gl = context->gl_vtable;
+
+  shader = g_hash_table_lookup (effects->shaderstable, "xray1");
+
+  if (!shader) {
+    shader = gst_gl_shader_new (context);
+    g_hash_table_insert (effects->shaderstable, "xray1", shader);
+  }
+
+  if (!kernel_ready) {
+    fill_gaussian_kernel (gauss_kernel, 7, 1.5);
+    kernel_ready = TRUE;
+  }
+
+  if (!gst_gl_shader_compile_and_check (shader,
+          hconv7_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
+    gst_gl_context_set_error (context, "Failed to initialize hconv7 shader");
+    GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
+        ("%s", gst_gl_context_get_error ()), (NULL));
+    return;
+  }
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+
+  gst_gl_shader_use (shader);
+
+  gl->ActiveTexture (GL_TEXTURE1);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+  gl->Disable (GL_TEXTURE_2D);
+
+  gst_gl_shader_set_uniform_1i (shader, "tex", 1);
+  gst_gl_shader_set_uniform_1fv (shader, "kernel", 9, gauss_kernel);
+  gst_gl_shader_set_uniform_1f (shader, "width", width);
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
+
+static void
+gst_gl_effects_xray_step_three (gint width, gint height, guint texture,
+    gpointer data)
+{
+  GstGLShader *shader;
+  GstGLEffects *effects = GST_GL_EFFECTS (data);
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+  GstGLContext *context = filter->context;
+  GstGLFuncs *gl = context->gl_vtable;
+
+  shader = g_hash_table_lookup (effects->shaderstable, "xray2");
+
+  if (!shader) {
+    shader = gst_gl_shader_new (context);
+    g_hash_table_insert (effects->shaderstable, "xray2", shader);
+  }
+
+  if (!gst_gl_shader_compile_and_check (shader,
+          vconv7_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
+    gst_gl_context_set_error (context, "Failed to initialize vconv7 shader");
+    GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
+        ("%s", gst_gl_context_get_error ()), (NULL));
+    return;
+  }
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+
+  gst_gl_shader_use (shader);
+
+  gl->ActiveTexture (GL_TEXTURE1);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+  gl->Disable (GL_TEXTURE_2D);
+
+  gst_gl_shader_set_uniform_1i (shader, "tex", 1);
+  gst_gl_shader_set_uniform_1fv (shader, "kernel", 9, gauss_kernel);
+  gst_gl_shader_set_uniform_1f (shader, "height", height);
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
+
+/* multipass separable sobel */
+static void
+gst_gl_effects_xray_desaturate (gint width, gint height, guint texture,
+    gpointer data)
+{
+  GstGLShader *shader;
+  GstGLEffects *effects = GST_GL_EFFECTS (data);
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+  GstGLContext *context = filter->context;
+  GstGLFuncs *gl = context->gl_vtable;
+
+  shader = g_hash_table_lookup (effects->shaderstable, "xray_desat");
+
+  if (!shader) {
+    shader = gst_gl_shader_new (context);
+    g_hash_table_insert (effects->shaderstable, "xray_desat", shader);
+  }
+
+  if (!gst_gl_shader_compile_and_check (shader,
+          desaturate_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
+    gst_gl_context_set_error (context,
+        "Failed to initialize desaturate shader");
+    GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
+        ("%s", gst_gl_context_get_error ()), (NULL));
+    return;
+  }
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+
+  gst_gl_shader_use (shader);
+
+  gl->ActiveTexture (GL_TEXTURE1);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+  gl->Disable (GL_TEXTURE_2D);
+
+  gst_gl_shader_set_uniform_1i (shader, "tex", 1);
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
+
+static void
+gst_gl_effects_xray_sobel_hconv (gint width, gint height, guint texture,
+    gpointer data)
+{
+  GstGLShader *shader;
+  GstGLEffects *effects = GST_GL_EFFECTS (data);
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+  GstGLContext *context = filter->context;
+  GstGLFuncs *gl = context->gl_vtable;
+
+  shader = g_hash_table_lookup (effects->shaderstable, "xray_sob_hconv");
+
+  if (!shader) {
+    shader = gst_gl_shader_new (context);
+    g_hash_table_insert (effects->shaderstable, "xray_sob_hconv", shader);
+  }
+
+  if (!gst_gl_shader_compile_and_check (shader,
+          sep_sobel_hconv3_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
+    gst_gl_context_set_error (context,
+        "Failed to initialize sobel hvonc3 shader");
+    GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
+        ("%s", gst_gl_context_get_error ()), (NULL));
+    return;
+  }
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+
+  gst_gl_shader_use (shader);
+
+  gl->ActiveTexture (GL_TEXTURE1);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+  gl->Disable (GL_TEXTURE_2D);
+
+  gst_gl_shader_set_uniform_1i (shader, "tex", 1);
+  gst_gl_shader_set_uniform_1f (shader, "width", width);
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
+
+static void
+gst_gl_effects_xray_sobel_vconv (gint width, gint height, guint texture,
+    gpointer data)
+{
+  GstGLShader *shader;
+  GstGLEffects *effects = GST_GL_EFFECTS (data);
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+  GstGLContext *context = filter->context;
+  GstGLFuncs *gl = context->gl_vtable;
+
+  shader = g_hash_table_lookup (effects->shaderstable, "xray_sob_vconv");
+
+  if (!shader) {
+    shader = gst_gl_shader_new (context);
+    g_hash_table_insert (effects->shaderstable, "xray_sob_vconv", shader);
+  }
+
+  if (!gst_gl_shader_compile_and_check (shader,
+          sep_sobel_vconv3_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
+    gst_gl_context_set_error (context,
+        "Failed to initialize sobel vconv3 shader");
+    GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
+        ("%s", gst_gl_context_get_error ()), (NULL));
+    return;
+  }
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+
+  gst_gl_shader_use (shader);
+
+  gl->ActiveTexture (GL_TEXTURE1);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+  gl->Disable (GL_TEXTURE_2D);
+
+  gst_gl_shader_set_uniform_1i (shader, "tex", 1);
+  gst_gl_shader_set_uniform_1f (shader, "height", height);
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
+
+static void
+gst_gl_effects_xray_sobel_length (gint width, gint height, guint texture,
+    gpointer data)
+{
+  GstGLShader *shader;
+  GstGLEffects *effects = GST_GL_EFFECTS (data);
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+  GstGLContext *context = filter->context;
+  GstGLFuncs *gl = context->gl_vtable;
+
+  shader = g_hash_table_lookup (effects->shaderstable, "xray_sob_len");
+
+  if (!shader) {
+    shader = gst_gl_shader_new (context);
+    g_hash_table_insert (effects->shaderstable, "xray_sob_len", shader);
+  }
+
+  if (!gst_gl_shader_compile_and_check (shader,
+          sep_sobel_length_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
+    gst_gl_context_set_error (context,
+        "Failed to initialize seobel length shader");
+    GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
+        ("%s", gst_gl_context_get_error ()), (NULL));
+    return;
+  }
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+
+  gst_gl_shader_use (shader);
+
+  gl->ActiveTexture (GL_TEXTURE1);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+  gl->Disable (GL_TEXTURE_2D);
+
+  gst_gl_shader_set_uniform_1i (shader, "tex", 1);
+  gst_gl_shader_set_uniform_1i (shader, "invert", TRUE);
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
+
+/* end of sobel passes */
+
+void
+gst_gl_effects_xray_step_five (gint width, gint height, guint texture,
+    gpointer data)
+{
+  GstGLShader *shader;
+  GstGLEffects *effects = GST_GL_EFFECTS (data);
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+  GstGLContext *context = filter->context;
+  GstGLFuncs *gl = context->gl_vtable;
+
+  shader = g_hash_table_lookup (effects->shaderstable, "xray4");
+
+  if (!shader) {
+    shader = gst_gl_shader_new (context);
+    g_hash_table_insert (effects->shaderstable, "xray4", shader);
+  }
+
+  if (!gst_gl_shader_compile_and_check (shader,
+          multiply_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
+    gst_gl_context_set_error (context, "Failed to initialize multiply shader");
+    GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
+        ("%s", gst_gl_context_get_error ()), (NULL));
+    return;
+  }
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+
+  gst_gl_shader_use (shader);
+
+  gl->ActiveTexture (GL_TEXTURE2);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, effects->midtexture[2]);
+  gl->Disable (GL_TEXTURE_2D);
+
+  gst_gl_shader_set_uniform_1i (shader, "base", 2);
+
+  gl->ActiveTexture (GL_TEXTURE1);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+  gl->Disable (GL_TEXTURE_2D);
+
+  gst_gl_shader_set_uniform_1f (shader, "alpha", (gfloat) 0.5f);
+  gst_gl_shader_set_uniform_1i (shader, "blend", 1);
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
+
+void
+gst_gl_effects_xray (GstGLEffects * effects)
+{
+  GstGLFilter *filter = GST_GL_FILTER (effects);
+
+  /* map luma to xray curve */
+  gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
+      effects->midtexture[0], gst_gl_effects_xray_step_one, effects);
+  /* horizontal blur */
+  gst_gl_filter_render_to_target (filter, FALSE, effects->midtexture[0],
+      effects->midtexture[1], gst_gl_effects_xray_step_two, effects);
+  /* vertical blur */
+  gst_gl_filter_render_to_target (filter, FALSE, effects->midtexture[1],
+      effects->midtexture[2], gst_gl_effects_xray_step_three, effects);
+  /* detect edges with Sobel */
+  /* the old version used edges from the blurred texture, this uses
+   * the ones from original texture, still not sure what I like
+   * more. This one gives better edges obviously but behaves badly
+   * with noise */
+  /* desaturate */
+  gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
+      effects->midtexture[3], gst_gl_effects_xray_desaturate, effects);
+  /* horizonal convolution */
+  gst_gl_filter_render_to_target (filter, FALSE, effects->midtexture[3],
+      effects->midtexture[4], gst_gl_effects_xray_sobel_hconv, effects);
+  /* vertical convolution */
+  gst_gl_filter_render_to_target (filter, FALSE, effects->midtexture[4],
+      effects->midtexture[3], gst_gl_effects_xray_sobel_vconv, effects);
+  /* gradient length */
+  gst_gl_filter_render_to_target (filter, FALSE, effects->midtexture[3],
+      effects->midtexture[4], gst_gl_effects_xray_sobel_length, effects);
+  /* multiply edges with the blurred image */
+  gst_gl_filter_render_to_target (filter, FALSE, effects->midtexture[4],
+      effects->outtexture, gst_gl_effects_xray_step_five, effects);
+}
diff --git a/ext/gl/gltestsrc.c b/ext/gl/gltestsrc.c
new file mode 100644 (file)
index 0000000..db28017
--- /dev/null
@@ -0,0 +1,507 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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
+
+/* non-GST-specific stuff */
+
+#include "gltestsrc.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#ifndef M_PI
+#define M_PI  3.14159265358979323846
+#endif
+
+enum
+{
+  COLOR_WHITE = 0,
+  COLOR_YELLOW,
+  COLOR_CYAN,
+  COLOR_GREEN,
+  COLOR_MAGENTA,
+  COLOR_RED,
+  COLOR_BLUE,
+  COLOR_BLACK,
+  COLOR_NEG_I,
+  COLOR_POS_Q,
+  COLOR_SUPER_BLACK,
+  COLOR_DARK_GREY
+};
+
+static const struct vts_color_struct vts_colors[] = {
+  /* 100% white */
+  {255, 128, 128, 255, 255, 255, 255},
+  /* yellow */
+  {226, 0, 155, 255, 255, 0, 255},
+  /* cyan */
+  {179, 170, 0, 0, 255, 255, 255},
+  /* green */
+  {150, 46, 21, 0, 255, 0, 255},
+  /* magenta */
+  {105, 212, 235, 255, 0, 255, 255},
+  /* red */
+  {76, 85, 255, 255, 0, 0, 255},
+  /* blue */
+  {29, 255, 107, 0, 0, 255, 255},
+  /* black */
+  {16, 128, 128, 0, 0, 0, 255},
+  /* -I */
+  {16, 198, 21, 0, 0, 128, 255},
+  /* +Q */
+  {16, 235, 198, 0, 128, 255, 255},
+  /* superblack */
+  {0, 128, 128, 0, 0, 0, 255},
+  /* 5% grey */
+  {32, 128, 128, 32, 32, 32, 255},
+};
+
+static void
+gst_gl_test_src_unicolor (GstGLTestSrc * v, GstBuffer * buffer, int w,
+    int h, const struct vts_color_struct *color);
+
+void
+gst_gl_test_src_smpte (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
+{
+#if GST_GL_HAVE_OPENGL
+  int i;
+
+  if (gst_gl_context_get_gl_api (v->context) & GST_GL_API_OPENGL) {
+
+    glClearColor (0.0, 0.0, 0.0, 1.0);
+    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    glDisable (GL_CULL_FACE);
+    glDisable (GL_TEXTURE_2D);
+
+    glMatrixMode (GL_PROJECTION);
+    glLoadIdentity ();
+
+    for (i = 0; i < 7; i++) {
+      glColor4f (vts_colors[i].R * (1 / 255.0f), vts_colors[i].G * (1 / 255.0f),
+          vts_colors[i].B * (1 / 255.0f), 1.0f);
+      glBegin (GL_QUADS);
+      glVertex3f (-1.0f + i * (2.0f / 7.0f), -1.0f + 2.0 * (2.0f / 3.0f), 0);
+      glVertex3f (-1.0f + (i + 1.0f) * (2.0f / 7.0f),
+          -1.0f + 2.0f * (2.0f / 3.0f), 0);
+      glVertex3f (-1.0f + (i + 1.0f) * (2.0f / 7.0f), -1.0f, 0);
+      glVertex3f (-1.0f + i * (2.0f / 7.0f), -1.0f, 0);
+      glEnd ();
+    }
+
+    for (i = 0; i < 7; i++) {
+      int k;
+
+      if (i & 1) {
+        k = 7;
+      } else {
+        k = 6 - i;
+      }
+
+      glColor4f (vts_colors[k].R * (1 / 255.0f), vts_colors[k].G * (1 / 255.0f),
+          vts_colors[k].B * (1 / 255.0f), 1.0f);
+      glBegin (GL_QUADS);
+      glVertex3f (-1.0f + i * (2.0f / 7.0f), -1.0f + 2.0f * (3.0f / 4.0f), 0);
+      glVertex3f (-1.0f + (i + 1) * (2.0f / 7.0f), -1.0f + 2.0f * (3.0f / 4.0f),
+          0);
+      glVertex3f (-1.0f + (i + 1) * (2.0f / 7.0f), -1.0f + 2.0f * (2.0f / 3.0f),
+          0);
+      glVertex3f (-1.0f + i * (2.0f / 7.0f), -1.0f + 2.0f * (2.0f / 3.0f), 0);
+      glEnd ();
+    }
+
+    for (i = 0; i < 3; i++) {
+      int k;
+
+      if (i == 0) {
+        k = 8;
+      } else if (i == 1) {
+        k = 0;
+      } else {
+        k = 9;
+      }
+
+      glColor4f (vts_colors[k].R * (1 / 255.0f), vts_colors[k].G * (1 / 255.0f),
+          vts_colors[k].B * (1 / 255.0f), 1.0f);
+      glBegin (GL_QUADS);
+      glVertex3f (-1.0f + i * (2.0f / 6.0f), -1.0f + 2.0f * 1, 0);
+      glVertex3f (-1.0f + (i + 1) * (2.0f / 6.0f), -1.0f + 2.0f * 1, 0);
+      glVertex3f (-1.0f + (i + 1) * (2.0f / 6.0f), -1.0f + 2.0f * (3.0f / 4.0f),
+          0);
+      glVertex3f (-1.0f + i * (2.0f / 6.0f), -1.0f + 2.0f * (3.0f / 4.0f), 0);
+      glEnd ();
+    }
+
+    for (i = 0; i < 3; i++) {
+      int k;
+
+      if (i == 0) {
+        k = COLOR_SUPER_BLACK;
+      } else if (i == 1) {
+        k = COLOR_BLACK;
+      } else {
+        k = COLOR_DARK_GREY;
+      }
+
+      glColor4f (vts_colors[k].R * (1 / 255.0f), vts_colors[k].G * (1 / 255.0f),
+          vts_colors[k].B * (1 / 255.0f), 1.0f);
+      glBegin (GL_QUADS);
+      glVertex3f (-1.0f + 2.0f * (0.5f + i * (1.0f / 12.0f)), -1.0 + 2.0f * 1,
+          0);
+      glVertex3f (-1.0f + 2.0f * (0.5f + (i + 1) * (1.0f / 12.0f)),
+          -1.0f + 2.0f * 1, 0);
+      glVertex3f (-1.0f + 2.0f * (0.5f + (i + 1) * (1.0f / 12.0f)),
+          -1.0f + 2.0f * (3.0f / 4.0f), 0);
+      glVertex3f (-1.0f + 2.0f * (0.5f + i * (1.0f / 12.0f)),
+          -1.0f + 2.0f * (3.0f / 4.0f), 0);
+      glEnd ();
+    }
+
+    glColor4f (1.0, 1.0, 1.0, 1.0);
+    glBegin (GL_QUADS);
+    glVertex3f (-1.0 + 2.0 * (0.75), -1.0 + 2.0 * 1, 0);
+    glVertex3f (-1.0 + 2.0 * (1.0), -1.0 + 2.0 * 1, 0);
+    glVertex3f (-1.0 + 2.0 * (1.0), -1.0 + 2.0 * (3.0 / 4.0), 0);
+    glVertex3f (-1.0 + 2.0 * (0.75), -1.0 + 2.0 * (3.0 / 4.0), 0);
+    glEnd ();
+  }
+#endif
+}
+
+void
+gst_gl_test_src_snow (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
+{
+#if GST_GL_HAVE_OPENGL
+  if (gst_gl_context_get_gl_api (v->context) & GST_GL_API_OPENGL) {
+    glClearColor (0.0, 0.0, 0.0, 1.0);
+    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    glMatrixMode (GL_PROJECTION);
+    glLoadIdentity ();
+
+    glMatrixMode (GL_MODELVIEW);
+    glLoadIdentity ();
+
+    /* FIXME snow requires a fragment shader.  Please write. */
+    glColor4f (0.5, 0.5, 0.5, 1.0);
+    glBegin (GL_QUADS);
+    glVertex3f (-1.0 + 2.0 * (0.0), -1.0 + 2.0 * 1, 0);
+    glVertex3f (-1.0 + 2.0 * (1.0), -1.0 + 2.0 * 1, 0);
+    glVertex3f (-1.0 + 2.0 * (1.0), -1.0 + 2.0 * (0.0), 0);
+    glVertex3f (-1.0 + 2.0 * (0.0), -1.0 + 2.0 * (0.0), 0);
+    glEnd ();
+  }
+#endif
+}
+
+static void
+gst_gl_test_src_unicolor (GstGLTestSrc * v, GstBuffer * buffer, int w,
+    int h, const struct vts_color_struct *color)
+{
+#if GST_GL_HAVE_OPENGL
+  if (gst_gl_context_get_gl_api (v->context) & GST_GL_API_OPENGL) {
+    glClearColor (color->R * (1 / 255.0f), color->G * (1 / 255.0f),
+        color->B * (1 / 255.0f), 1.0f);
+    glClear (GL_COLOR_BUFFER_BIT);
+  }
+#endif
+}
+
+void
+gst_gl_test_src_black (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
+{
+  gst_gl_test_src_unicolor (v, buffer, w, h, vts_colors + COLOR_BLACK);
+}
+
+void
+gst_gl_test_src_white (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
+{
+  gst_gl_test_src_unicolor (v, buffer, w, h, vts_colors + COLOR_WHITE);
+}
+
+void
+gst_gl_test_src_red (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
+{
+  gst_gl_test_src_unicolor (v, buffer, w, h, vts_colors + COLOR_RED);
+}
+
+void
+gst_gl_test_src_green (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
+{
+  gst_gl_test_src_unicolor (v, buffer, w, h, vts_colors + COLOR_GREEN);
+}
+
+void
+gst_gl_test_src_blue (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
+{
+  gst_gl_test_src_unicolor (v, buffer, w, h, vts_colors + COLOR_BLUE);
+}
+
+void
+gst_gl_test_src_checkers1 (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
+{
+#if 0
+  int x, y;
+  paintinfo pi = { NULL, };
+  paintinfo *p = &pi;
+  struct fourcc_list_struct *fourcc;
+
+  p->width = w;
+  p->height = h;
+  fourcc = v->fourcc;
+  if (fourcc == NULL)
+    return;
+
+  fourcc->paint_setup (p, dest);
+  p->paint_hline = fourcc->paint_hline;
+
+  for (y = 0; y < h; y++) {
+    p->color = vts_colors + COLOR_GREEN;
+    p->paint_hline (p, 0, y, w);
+    for (x = (y % 2); x < w; x += 2) {
+      p->color = vts_colors + COLOR_RED;
+      p->paint_hline (p, x, y, 1);
+    }
+  }
+#endif
+}
+
+void
+gst_gl_test_src_checkers2 (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
+{
+#if 0
+  int x, y;
+  paintinfo pi = { NULL, };
+  paintinfo *p = &pi;
+  struct fourcc_list_struct *fourcc;
+
+  p->width = w;
+  p->height = h;
+  fourcc = v->fourcc;
+  if (fourcc == NULL)
+    return;
+
+  fourcc->paint_setup (p, dest);
+  p->paint_hline = fourcc->paint_hline;
+
+  p->color = vts_colors + COLOR_GREEN;
+  for (y = 0; y < h; y++) {
+    p->paint_hline (p, 0, y, w);
+  }
+
+  for (y = 0; y < h; y += 2) {
+    for (x = ((y % 4) == 0) ? 0 : 2; x < w; x += 4) {
+      guint len = (x < (w - 1)) ? 2 : (w - x);
+
+      p->color = vts_colors + COLOR_RED;
+      p->paint_hline (p, x, y + 0, len);
+      if (G_LIKELY ((y + 1) < h)) {
+        p->paint_hline (p, x, y + 1, len);
+      }
+    }
+  }
+#endif
+}
+
+void
+gst_gl_test_src_checkers4 (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
+{
+#if 0
+  int x, y;
+  paintinfo pi = { NULL, };
+  paintinfo *p = &pi;
+  struct fourcc_list_struct *fourcc;
+
+  p->width = w;
+  p->height = h;
+  fourcc = v->fourcc;
+  if (fourcc == NULL)
+    return;
+
+  fourcc->paint_setup (p, dest);
+  p->paint_hline = fourcc->paint_hline;
+
+  p->color = vts_colors + COLOR_GREEN;
+  for (y = 0; y < h; y++) {
+    p->paint_hline (p, 0, y, w);
+  }
+
+  for (y = 0; y < h; y += 4) {
+    for (x = ((y % 8) == 0) ? 0 : 4; x < w; x += 8) {
+      guint len = (x < (w - 3)) ? 4 : (w - x);
+
+      p->color = vts_colors + COLOR_RED;
+      p->paint_hline (p, x, y + 0, len);
+      if (G_LIKELY ((y + 1) < h)) {
+        p->paint_hline (p, x, y + 1, len);
+        if (G_LIKELY ((y + 2) < h)) {
+          p->paint_hline (p, x, y + 2, len);
+          if (G_LIKELY ((y + 3) < h)) {
+            p->paint_hline (p, x, y + 3, len);
+          }
+        }
+      }
+    }
+  }
+#endif
+}
+
+void
+gst_gl_test_src_checkers8 (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
+{
+#if 0
+  int x, y;
+  paintinfo pi = { NULL, };
+  paintinfo *p = &pi;
+  struct fourcc_list_struct *fourcc;
+
+  p->width = w;
+  p->height = h;
+  fourcc = v->fourcc;
+  if (fourcc == NULL)
+    return;
+
+  fourcc->paint_setup (p, dest);
+  p->paint_hline = fourcc->paint_hline;
+
+  p->color = vts_colors + COLOR_GREEN;
+  for (y = 0; y < h; y++) {
+    p->paint_hline (p, 0, y, w);
+  }
+
+  for (y = 0; y < h; y += 8) {
+    for (x = ((GST_ROUND_UP_8 (y) % 16) == 0) ? 0 : 8; x < w; x += 16) {
+      guint len = (x < (w - 7)) ? 8 : (w - x);
+
+      p->color = vts_colors + COLOR_RED;
+      p->paint_hline (p, x, y + 0, len);
+      if (G_LIKELY ((y + 1) < h)) {
+        p->paint_hline (p, x, y + 1, len);
+        if (G_LIKELY ((y + 2) < h)) {
+          p->paint_hline (p, x, y + 2, len);
+          if (G_LIKELY ((y + 3) < h)) {
+            p->paint_hline (p, x, y + 3, len);
+            if (G_LIKELY ((y + 4) < h)) {
+              p->paint_hline (p, x, y + 4, len);
+              if (G_LIKELY ((y + 5) < h)) {
+                p->paint_hline (p, x, y + 5, len);
+                if (G_LIKELY ((y + 6) < h)) {
+                  p->paint_hline (p, x, y + 6, len);
+                  if (G_LIKELY ((y + 7) < h)) {
+                    p->paint_hline (p, x, y + 7, len);
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+#endif
+}
+
+void
+gst_gl_test_src_circular (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
+{
+#if 0
+  int i;
+  int j;
+  paintinfo pi = { NULL, };
+  paintinfo *p = &pi;
+  struct fourcc_list_struct *fourcc;
+  struct vts_color_struct color;
+  static uint8_t sine_array[256];
+  static int sine_array_inited = FALSE;
+  double freq[8];
+
+#ifdef SCALE_AMPLITUDE
+  double ampl[8];
+#endif
+  int d;
+
+  if (!sine_array_inited) {
+    for (i = 0; i < 256; i++) {
+      sine_array[i] =
+          floor (255 * (0.5 + 0.5 * sin (i * 2 * M_PI / 256)) + 0.5);
+    }
+    sine_array_inited = TRUE;
+  }
+
+  p->width = w;
+  p->height = h;
+  fourcc = v->fourcc;
+  if (fourcc == NULL)
+    return;
+
+  fourcc->paint_setup (p, dest);
+  p->paint_hline = fourcc->paint_hline;
+
+  color = vts_colors[COLOR_BLACK];
+  p->color = &color;
+
+  for (i = 1; i < 8; i++) {
+    freq[i] = 200 * pow (2.0, -(i - 1) / 4.0);
+#ifdef SCALE_AMPLITUDE
+    {
+      double x;
+
+      x = 2 * M_PI * freq[i] / w;
+      ampl[i] = sin (x) / x;
+    }
+#endif
+  }
+
+  for (i = 0; i < w; i++) {
+    for (j = 0; j < h; j++) {
+      double dist;
+      int seg;
+
+      dist =
+          sqrt ((2 * i - w) * (2 * i - w) + (2 * j - h) * (2 * j -
+              h)) / (2 * w);
+      seg = floor (dist * 16);
+      if (seg == 0 || seg >= 8) {
+        color.Y = 255;
+      } else {
+#ifdef SCALE_AMPLITUDE
+        double a;
+#endif
+        d = floor (256 * dist * freq[seg] + 0.5);
+#ifdef SCALE_AMPLITUDE
+        a = ampl[seg];
+        if (a < 0)
+          a = 0;
+        color.Y = 128 + a * (sine_array[d & 0xff] - 128);
+#else
+        color.Y = sine_array[d & 0xff];
+#endif
+      }
+      color.R = color.Y;
+      color.G = color.Y;
+      color.B = color.Y;
+      p->paint_hline (p, i, j, 1);
+    }
+  }
+#endif
+}
diff --git a/ext/gl/gltestsrc.h b/ext/gl/gltestsrc.h
new file mode 100644 (file)
index 0000000..f79ffee
--- /dev/null
@@ -0,0 +1,58 @@
+/* GStreamer
+ * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
+ *
+ * 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.
+ */
+
+#ifndef __GL_TEST_SRC_H__
+#define __GL_TEST_SRC_H__
+
+#include <glib.h>
+
+#include "gstgltestsrc.h"
+
+struct vts_color_struct {
+        guint8 Y, U, V;
+        guint8 R, G, B;
+       guint8 A;
+};
+
+void    gst_gl_test_src_smpte        (GstGLTestSrc * v,
+                                         GstBuffer *buffer, int w, int h);
+void    gst_gl_test_src_snow         (GstGLTestSrc * v,
+                                         GstBuffer *buffer, int w, int h);
+void    gst_gl_test_src_black        (GstGLTestSrc * v,
+                                         GstBuffer *buffer, int w, int h);
+void    gst_gl_test_src_white        (GstGLTestSrc * v,
+                                         GstBuffer *buffer, int w, int h);
+void    gst_gl_test_src_red          (GstGLTestSrc * v,
+                                         GstBuffer *buffer, int w, int h);
+void    gst_gl_test_src_green        (GstGLTestSrc * v,
+                                         GstBuffer *buffer, int w, int h);
+void    gst_gl_test_src_blue         (GstGLTestSrc * v,
+                                         GstBuffer *buffer, int w, int h);
+void    gst_gl_test_src_checkers1    (GstGLTestSrc * v,
+                                         GstBuffer *buffer, int w, int h);
+void    gst_gl_test_src_checkers2    (GstGLTestSrc * v,
+                                         GstBuffer *buffer, int w, int h);
+void    gst_gl_test_src_checkers4    (GstGLTestSrc * v,
+                                         GstBuffer *buffer, int w, int h);
+void    gst_gl_test_src_checkers8    (GstGLTestSrc * v,
+                                         GstBuffer *buffer, int w, int h);
+void    gst_gl_test_src_circular     (GstGLTestSrc * v,
+                                         GstBuffer *buffer, int w, int h);
+
+#endif
diff --git a/ext/gl/gstglbumper.c b/ext/gl/gstglbumper.c
new file mode 100644 (file)
index 0000000..cabc144
--- /dev/null
@@ -0,0 +1,546 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Cyril Comparon <cyril.comparon@gmail.com>
+ * Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.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.
+ */
+
+/**
+ * SECTION:element-glbumper
+ *
+ * Bump mapping using the normal method.
+ *
+ * <refsect2>
+ * <title>Examples</title>
+ * |[
+ * gst-launch -v videotestsrc ! glupload ! glbumper location=normalmap.bmp ! glimagesink
+ * ]| A pipeline to test normal mapping.
+ * FBO (Frame Buffer Object) and GLSL (OpenGL Shading Language) are required.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <png.h>
+#include "gstglbumper.h"
+
+#if PNG_LIBPNG_VER >= 10400
+#define int_p_NULL         NULL
+#define png_infopp_NULL    NULL
+#endif
+
+#define GST_CAT_DEFAULT gst_gl_bumper_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+enum
+{
+  PROP_0,
+  PROP_LOCATION
+};
+
+#define DEBUG_INIT \
+  GST_DEBUG_CATEGORY_INIT (gst_gl_bumper_debug, "glbumper", 0, "glbumper element");
+
+G_DEFINE_TYPE_WITH_CODE (GstGLBumper, gst_gl_bumper, GST_TYPE_GL_FILTER,
+    DEBUG_INIT);
+
+static void gst_gl_bumper_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_gl_bumper_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static void gst_gl_bumper_reset (GstGLFilter * filter);
+static gboolean gst_gl_bumper_init_shader (GstGLFilter * filter);
+static gboolean gst_gl_bumper_filter_texture (GstGLFilter * filter,
+    guint in_tex, guint out_tex);
+static void gst_gl_bumper_callback (gint width, gint height, guint texture,
+    gpointer stuff);
+
+//vertex source
+static const gchar *bumper_v_src =
+    "attribute vec3 aTangent;\n"
+    "\n"
+    "varying vec3 vNormal;\n"
+    "varying vec3 vTangent;\n"
+    "varying vec3 vVertexToLight0;\n"
+    "varying vec3 vVertexToLight1;\n"
+    "\n"
+    "void main()\n"
+    "{\n"
+    "  // transform the vertex\n"
+    "  gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n"
+    "\n"
+    "  // transform the normal and the tangent to scene coords\n"
+    "  vNormal = normalize(gl_NormalMatrix * gl_Normal);\n"
+    "  vTangent = normalize(gl_NormalMatrix * aTangent);\n"
+    "\n"
+    "  // transforming the vertex position to modelview-space\n"
+    "  //const vec4 vertexInSceneCoords = gl_ModelViewMatrix * gl_Vertex;\n"
+    "\n"
+    "  // calculate the vector from the vertex position to the light position\n"
+    "  vVertexToLight0 = normalize(gl_LightSource[0].position).xyz;\n"
+    "  vVertexToLight1 = normalize(gl_LightSource[1].position).xyz;\n"
+    "\n"
+    "  // transit vertex color\n"
+    "  gl_FrontColor = gl_BackColor = gl_Color;\n"
+    "\n"
+    "  // use the two first sets of texture coordinates in the fragment shader\n"
+    "  gl_TexCoord[0] = gl_MultiTexCoord0;\n"
+    "  gl_TexCoord[1] = gl_MultiTexCoord1;\n" "}\n";
+
+//fragment source
+static const gchar *bumper_f_src =
+    "uniform sampler2D texture0;\n"
+    "uniform sampler2D texture1;\n"
+    "\n"
+    "varying vec3 vNormal;\n"
+    "varying vec3 vTangent;\n"
+    "varying vec3 vVertexToLight0;\n"
+    "varying vec3 vVertexToLight1;\n"
+    "\n"
+    "void main()\n"
+    "{\n"
+    "  // get the color of the textures\n"
+    "  vec4 textureColor = texture2D(texture0, gl_TexCoord[0].st);\n"
+    "  vec3 normalmapItem = texture2D(texture1, gl_TexCoord[1].st).xyz * 2.0 - 1.0;\n"
+    "\n"
+    "  // calculate matrix that transform from tangent space to normalmap space (contrary of intuition)\n"
+    "  vec3 binormal = cross(vNormal, vTangent);\n"
+    "  mat3 tangentSpace2normalmapSpaceMat = mat3(vTangent, binormal, vNormal);\n"
+    "\n"
+    "  // disturb the normal\n"
+    "  vec3 disturbedNormal = tangentSpace2normalmapSpaceMat * normalmapItem;\n"
+    "\n"
+    "  // calculate the diffuse term and clamping it to [0;1]\n"
+    "  float diffuseTerm0 = clamp(dot(disturbedNormal, vVertexToLight0), 0.0, 1.0);\n"
+    "  float diffuseTerm1 = clamp(dot(disturbedNormal, vVertexToLight1), 0.0, 1.0);\n"
+    "\n"
+    "  vec3 irradiance = (diffuseTerm0 * gl_LightSource[0].diffuse.rgb + diffuseTerm1 * gl_LightSource[1].diffuse.rgb);\n"
+    "\n"
+    "  // calculate the final color\n"
+    "  gl_FragColor = vec4(irradiance * textureColor.rgb, textureColor.w);\n"
+    "}\n";
+
+#define LOAD_ERROR(context, msg) { gst_gl_context_set_error (context, "unable to load %s: %s", bumper->location, msg); return; }
+
+//png reading error handler
+static void
+user_warning_fn (png_structp png_ptr, png_const_charp warning_msg)
+{
+  g_warning ("%s\n", warning_msg);
+}
+
+//Called in the gl thread
+static void
+gst_gl_bumper_init_resources (GstGLFilter * filter)
+{
+  GstGLBumper *bumper = GST_GL_BUMPER (filter);
+  GstGLContext *context = filter->context;
+  const GstGLFuncs *gl = context->gl_vtable;
+
+  png_structp png_ptr;
+  png_infop info_ptr;
+  png_uint_32 width = 0;
+  png_uint_32 height = 0;
+  gint bit_depth = 0;
+  gint color_type = 0;
+  gint interlace_type = 0;
+  png_FILE_p fp = NULL;
+  guint y = 0;
+  guchar *raw_data = NULL;
+  guchar **rows = NULL;
+  png_byte magic[8];
+  gint n_read;
+
+  if (!context)
+    return;
+
+  if (!bumper->location) {
+    gst_gl_context_set_error (context, "A filename is required");
+    return;
+  }
+
+  /* BEGIN load png image file */
+
+  if ((fp = fopen (bumper->location, "rb")) == NULL)
+    LOAD_ERROR (context, "file not found");
+
+  /* Read magic number */
+  n_read = fread (magic, 1, sizeof (magic), fp);
+  if (n_read != sizeof (magic)) {
+    fclose (fp);
+    LOAD_ERROR (context, "can't read PNG magic number");
+  }
+
+  /* Check for valid magic number */
+  if (png_sig_cmp (magic, 0, sizeof (magic))) {
+    fclose (fp);
+    LOAD_ERROR (context, "not a valid PNG image");
+  }
+
+  png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+
+  if (png_ptr == NULL) {
+    fclose (fp);
+    LOAD_ERROR (context, "failed to initialize the png_struct");
+  }
+
+  png_set_error_fn (png_ptr, NULL, NULL, user_warning_fn);
+
+  info_ptr = png_create_info_struct (png_ptr);
+  if (info_ptr == NULL) {
+    fclose (fp);
+    png_destroy_read_struct (&png_ptr, png_infopp_NULL, png_infopp_NULL);
+    LOAD_ERROR (context,
+        "failed to initialize the memory for image information");
+  }
+
+  png_init_io (png_ptr, fp);
+
+  png_set_sig_bytes (png_ptr, sizeof (magic));
+
+  png_read_info (png_ptr, info_ptr);
+
+  png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
+      &interlace_type, int_p_NULL, int_p_NULL);
+
+  if (color_type != PNG_COLOR_TYPE_RGB) {
+    fclose (fp);
+    png_destroy_read_struct (&png_ptr, png_infopp_NULL, png_infopp_NULL);
+    LOAD_ERROR (context, "color type is not rgb");
+  }
+
+  raw_data = (guchar *) malloc (sizeof (guchar) * width * height * 3);
+
+  rows = (guchar **) malloc (sizeof (guchar *) * height);
+
+  for (y = 0; y < height; ++y)
+    rows[y] = (guchar *) (raw_data + y * width * 3);
+
+  png_read_image (png_ptr, rows);
+
+  free (rows);
+
+  png_read_end (png_ptr, info_ptr);
+  png_destroy_read_struct (&png_ptr, &info_ptr, png_infopp_NULL);
+  fclose (fp);
+
+  /* END load png image file */
+
+  bumper->bumpmap_width = width;
+  bumper->bumpmap_height = height;
+
+  gl->GenTextures (1, &bumper->bumpmap);
+  gl->BindTexture (GL_TEXTURE_2D, bumper->bumpmap);
+  gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGBA,
+      bumper->bumpmap_width, bumper->bumpmap_height, 0,
+      GL_RGB, GL_UNSIGNED_BYTE, raw_data);
+  gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+  gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+  gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+  gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+  free (raw_data);
+}
+
+//Called in the gl thread
+static void
+gst_gl_bumper_reset_resources (GstGLFilter * filter)
+{
+  GstGLBumper *bumper = GST_GL_BUMPER (filter);
+
+  if (bumper->bumpmap) {
+    glDeleteTextures (1, &bumper->bumpmap);
+    bumper->bumpmap = 0;
+  }
+}
+
+static void
+gst_gl_bumper_class_init (GstGLBumperClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *element_class;
+
+  gobject_class = (GObjectClass *) klass;
+  element_class = GST_ELEMENT_CLASS (klass);
+  gobject_class->set_property = gst_gl_bumper_set_property;
+  gobject_class->get_property = gst_gl_bumper_get_property;
+
+  GST_GL_FILTER_CLASS (klass)->filter_texture = gst_gl_bumper_filter_texture;
+  GST_GL_FILTER_CLASS (klass)->display_init_cb = gst_gl_bumper_init_resources;
+  GST_GL_FILTER_CLASS (klass)->display_reset_cb = gst_gl_bumper_reset_resources;
+  GST_GL_FILTER_CLASS (klass)->onInitFBO = gst_gl_bumper_init_shader;
+  GST_GL_FILTER_CLASS (klass)->onReset = gst_gl_bumper_reset;
+
+  g_object_class_install_property (gobject_class,
+      PROP_LOCATION, g_param_spec_string ("location",
+          "Normal map location",
+          "Normal map location", NULL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_metadata (element_class, "OpenGL bumper filter",
+      "Filter/Effect/Video", "Bump mapping filter",
+      "Cyril Comparon <cyril.comparon@gmail.com>, "
+      "Julien Isorce <julien.isorce@gmail.com>");
+}
+
+static void
+gst_gl_bumper_init (GstGLBumper * bumper)
+{
+  bumper->shader = NULL;
+  bumper->bumpmap = 0;
+  bumper->bumpmap_width = 0;
+  bumper->bumpmap_height = 0;
+  bumper->location = NULL;
+}
+
+static void
+gst_gl_bumper_reset (GstGLFilter * filter)
+{
+  GstGLBumper *bumper_filter = GST_GL_BUMPER (filter);
+
+  //blocking call, wait the opengl thread has destroyed the shader
+  if (bumper_filter->shader)
+    gst_gl_context_del_shader (filter->context, bumper_filter->shader);
+  bumper_filter->shader = NULL;
+}
+
+static void
+gst_gl_bumper_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstGLBumper *bumper = GST_GL_BUMPER (object);
+
+  switch (prop_id) {
+    case PROP_LOCATION:
+      if (bumper->location != NULL)
+        g_free (bumper->location);
+      bumper->location = g_value_dup_string (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_gl_bumper_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstGLBumper *bumper = GST_GL_BUMPER (object);
+
+  switch (prop_id) {
+    case PROP_LOCATION:
+      g_value_set_string (value, bumper->location);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_gl_bumper_init_shader (GstGLFilter * filter)
+{
+  GstGLBumper *bumper = GST_GL_BUMPER (filter);
+
+  //blocking call, wait the opengl thread has compiled the shader
+  return gst_gl_context_gen_shader (filter->context, bumper_v_src, bumper_f_src,
+      &bumper->shader);
+}
+
+static gboolean
+gst_gl_bumper_filter_texture (GstGLFilter * filter, guint in_tex, guint out_tex)
+{
+  gpointer bumper_filter = GST_GL_BUMPER (filter);
+
+  //blocking call, use a FBO
+  gst_gl_context_use_fbo (filter->context,
+      GST_VIDEO_INFO_WIDTH (&filter->out_info),
+      GST_VIDEO_INFO_HEIGHT (&filter->out_info),
+      filter->fbo, filter->depthbuffer, out_tex, gst_gl_bumper_callback,
+      GST_VIDEO_INFO_WIDTH (&filter->in_info),
+      GST_VIDEO_INFO_HEIGHT (&filter->in_info),
+      in_tex, 45,
+      (gdouble) GST_VIDEO_INFO_WIDTH (&filter->out_info) /
+      (gdouble) GST_VIDEO_INFO_HEIGHT (&filter->out_info), 0.1, 50,
+      GST_GL_DISPLAY_PROJECTION_PERSPECTIVE, bumper_filter);
+
+  return TRUE;
+}
+
+typedef struct _MeshData
+{
+  float x, y, z;                /* Vertex */
+  float nx, ny, nz;             /* Normal */
+  float s0, t0;                 /* TexCoord0 */
+  float s1, t1;                 /* TexCoord1 */
+  float va0, vb0, vc0;          /* VertexAttrib */
+} MeshData;
+
+//opengl scene, params: input texture (not the output filter->texture)
+static void
+gst_gl_bumper_callback (gint width, gint height, guint texture, gpointer stuff)
+{
+  static GLfloat xrot = 0;
+  static GLfloat yrot = 0;
+  static GLfloat zrot = 0;
+
+  GstGLFuncs *gl;
+  GstGLBumper *bumper = GST_GL_BUMPER (stuff);
+  GstGLContext *context = GST_GL_FILTER (bumper)->context;
+  GLint locTangent = 0;
+
+  //choose the lights
+  GLfloat light_direction0[] = { 1.0, 0.0, -1.0, 0.0 }; // light goes along -x
+  GLfloat light_direction1[] = { -1.0, 0.0, -1.0, 0.0 };        // light goes along x
+  GLfloat light_diffuse0[] = { 1.0, 1.0, 1.0, 1.0 };
+  GLfloat light_diffuse1[] = { 1.0, 1.0, 1.0, 1.0 };
+  GLfloat mat_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
+
+/* *INDENT-OFF* */
+  MeshData mesh[] = {
+   /* |     Vertex      |     Normal      |TexCoord0|TexCoord1|  VertexAttrib  | */
+/*F*/ { 1.0,  1.0, -1.0,  0.0,  0.0, -1.0, 0.0, 0.0, 0.0, 0.0,  0.0,  1.0,  0.0},
+/*r*/ { 1.0, -1.0, -1.0,  0.0,  0.0, -1.0, 1.0, 0.0, 1.0, 0.0,  0.0,  1.0,  0.0},
+/*o*/ {-1.0, -1.0, -1.0,  0.0,  0.0, -1.0, 1.0, 1.0, 1.0, 1.0,  0.0,  1.0,  0.0},
+      {-1.0,  1.0, -1.0,  0.0,  0.0, -1.0, 0.0, 1.0, 0.0, 1.0,  0.0,  1.0,  0.0},
+/*R*/ {-1.0,  1.0, -1.0, -1.0,  0.0,  0.0, 0.0, 0.0, 0.0, 0.0,  0.0,  1.0,  0.0},
+/*i*/ {-1.0, -1.0, -1.0, -1.0,  0.0,  0.0, 1.0, 0.0, 1.0, 0.0,  0.0,  1.0,  0.0},
+/*g*/ {-1.0, -1.0,  1.0, -1.0,  0.0,  0.0, 1.0, 1.0, 1.0, 1.0,  0.0,  1.0,  0.0},
+      {-1.0,  1.0,  1.0, -1.0,  0.0,  0.0, 0.0, 1.0, 0.0, 1.0,  0.0,  1.0,  0.0},
+/*B*/ {-1.0,  1.0,  1.0,  0.0,  0.0,  1.0, 0.0, 0.0, 0.0, 0.0,  0.0,  1.0,  0.0},
+/*a*/ {-1.0, -1.0,  1.0,  0.0,  0.0,  1.0, 1.0, 0.0, 1.0, 0.0,  0.0,  1.0,  0.0},
+/*c*/ { 1.0, -1.0,  1.0,  0.0,  0.0,  1.0, 1.0, 1.0, 1.0, 1.0,  0.0,  1.0,  0.0},
+      { 1.0,  1.0,  1.0,  0.0,  0.0,  1.0, 0.0, 1.0, 0.0, 1.0,  0.0,  1.0,  0.0},
+/*L*/ { 1.0,  1.0,  1.0,  1.0,  0.0,  0.0, 0.0, 0.0, 0.0, 0.0,  0.0,  1.0,  0.0},
+/*e*/ { 1.0, -1.0,  1.0,  1.0,  0.0,  0.0, 1.0, 0.0, 1.0, 0.0,  0.0,  1.0,  0.0},
+/*f*/ { 1.0, -1.0, -1.0,  1.0,  0.0,  0.0, 1.0, 1.0, 1.0, 1.0,  0.0,  1.0,  0.0},
+      { 1.0,  1.0, -1.0,  1.0,  0.0,  0.0, 0.0, 1.0, 0.0, 1.0,  0.0,  1.0,  0.0},
+/*T*/ { 1.0,  1.0,  1.0,  0.0,  1.0,  0.0, 0.0, 0.0, 0.0, 0.0,  0.0,  0.0,  1.0},
+/*o*/ { 1.0,  1.0, -1.0,  0.0,  1.0,  0.0, 1.0, 0.0, 1.0, 0.0,  0.0,  0.0,  1.0},
+/*p*/ {-1.0,  1.0, -1.0,  0.0,  1.0,  0.0, 1.0, 1.0, 1.0, 1.0,  0.0,  0.0,  1.0},
+      {-1.0,  1.0,  1.0,  0.0,  1.0,  0.0, 0.0, 1.0, 0.0, 1.0,  0.0,  0.0,  1.0},
+/*B*/ { 1.0, -1.0, -1.0,  0.0, -1.0,  0.0, 0.0, 0.0, 0.0, 0.0,  0.0,  0.0, -1.0},
+/*o*/ { 1.0, -1.0,  1.0,  0.0, -1.0,  0.0, 1.0, 0.0, 1.0, 0.0,  0.0,  0.0, -1.0},
+/*t*/ {-1.0, -1.0,  1.0,  0.0, -1.0,  0.0, 1.0, 1.0, 1.0, 1.0,  0.0,  0.0, -1.0},
+      {-1.0, -1.0, -1.0,  0.0, -1.0,  0.0, 0.0, 1.0, 0.0, 1.0,  0.0,  0.0, -1.0},
+  };
+
+  GLushort indices[] = {
+    0, 1, 2,
+    0, 2, 3,
+    4, 5, 6,
+    4, 6, 7,
+    8, 9, 10,
+    8, 10, 11,
+    12, 13, 14,
+    12, 14, 15,
+    16, 17, 18,
+    16, 18, 19,
+    20, 21, 22,
+    20, 22, 23
+  };
+
+/* *INDENT-ON* */
+
+  gl = GST_GL_FILTER (bumper)->context->gl_vtable;
+
+  //eye point
+  gl->MatrixMode (GL_PROJECTION);
+  gluLookAt (0.0, 0.0, -6.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
+  gl->MatrixMode (GL_MODELVIEW);
+
+  //scene conf
+  gl->Enable (GL_DEPTH_TEST);
+  gl->DepthFunc (GL_LEQUAL);
+  gl->Hint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
+
+  gl->ShadeModel (GL_SMOOTH);
+
+  //set the lights
+  gl->Lightfv (GL_LIGHT0, GL_POSITION, light_direction0);
+  gl->Lightfv (GL_LIGHT0, GL_DIFFUSE, light_diffuse0);
+  gl->Lightfv (GL_LIGHT1, GL_POSITION, light_direction1);
+  gl->Lightfv (GL_LIGHT1, GL_DIFFUSE, light_diffuse1);
+  gl->Materialfv (GL_FRONT, GL_DIFFUSE, mat_diffuse);
+  gl->ColorMaterial (GL_FRONT_AND_BACK, GL_DIFFUSE);
+  gl->Enable (GL_COLOR_MATERIAL);
+  gl->Enable (GL_LIGHTING);
+  gl->Enable (GL_LIGHT0);
+  gl->Enable (GL_LIGHT1);
+  //configure shader
+  gst_gl_shader_use (bumper->shader);
+  locTangent =
+      gst_gl_shader_get_attribute_location (bumper->shader, "aTangent");
+
+  //set the normal map
+  gl->ActiveTexture (GL_TEXTURE1);
+  gst_gl_shader_set_uniform_1i (bumper->shader, "texture1", 1);
+  gl->BindTexture (GL_TEXTURE_2D, bumper->bumpmap);
+
+  //set the video texture
+  gl->ActiveTexture (GL_TEXTURE0);
+  gst_gl_shader_set_uniform_1i (bumper->shader, "texture0", 0);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+
+  gl->Rotatef (xrot, 1.0f, 0.0f, 0.0f);
+  gl->Rotatef (yrot, 0.0f, 1.0f, 0.0f);
+  gl->Rotatef (zrot, 0.0f, 0.0f, 1.0f);
+
+  gl->EnableVertexAttribArray (locTangent);
+
+  gl->ClientActiveTexture (GL_TEXTURE0);
+  gl->EnableClientState (GL_TEXTURE_COORD_ARRAY);
+  gl->EnableClientState (GL_VERTEX_ARRAY);
+  gl->EnableClientState (GL_NORMAL_ARRAY);
+
+  gl->VertexAttribPointer (locTangent, 3, GL_FLOAT, 0, sizeof (MeshData),
+      &mesh[0].va0);
+  gl->VertexPointer (3, GL_FLOAT, sizeof (MeshData), &mesh[0].x);
+  gl->NormalPointer (GL_FLOAT, sizeof (MeshData), &mesh[0].nx);
+  gl->TexCoordPointer (2, GL_FLOAT, sizeof (MeshData), &mesh[0].s0);
+
+  gl->ClientActiveTexture (GL_TEXTURE1);
+  gl->EnableClientState (GL_TEXTURE_COORD_ARRAY);
+  gl->TexCoordPointer (2, GL_FLOAT, sizeof (MeshData), &mesh[0].s1);
+
+  gl->DrawElements (GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, indices);
+
+  gl->DisableClientState (GL_VERTEX_ARRAY);
+  gl->DisableClientState (GL_TEXTURE_COORD_ARRAY);
+  gl->DisableClientState (GL_NORMAL_ARRAY);
+
+  gl->ClientActiveTexture (GL_TEXTURE0);
+  gl->DisableClientState (GL_TEXTURE_COORD_ARRAY);
+
+  gl->DisableVertexAttribArray (locTangent);
+
+  gst_gl_context_clear_shader (context);
+
+  gl->Disable (GL_LIGHT0);
+  gl->Disable (GL_LIGHT1);
+  gl->Disable (GL_LIGHTING);
+  gl->Disable (GL_COLOR_MATERIAL);
+
+  xrot += 1.0f;
+  yrot += 0.9f;
+  zrot += 0.6f;
+}
diff --git a/ext/gl/gstglbumper.h b/ext/gl/gstglbumper.h
new file mode 100644 (file)
index 0000000..b1a1dc0
--- /dev/null
@@ -0,0 +1,57 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.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.
+ */
+
+#ifndef _GST_GL_BUMPER_H_
+#define _GST_GL_BUMPER_H_
+
+#include <gst/gl/gstglfilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_GL_BUMPER            (gst_gl_bumper_get_type())
+#define GST_GL_BUMPER(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_BUMPER,GstGLBumper))
+#define GST_IS_GL_BUMPER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_BUMPER))
+#define GST_GL_BUMPER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_BUMPER,GstGLBumperClass))
+#define GST_IS_GL_BUMPER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_BUMPER))
+#define GST_GL_BUMPER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_BUMPER,GstGLBumperClass))
+
+typedef struct _GstGLBumper GstGLBumper;
+typedef struct _GstGLBumperClass GstGLBumperClass;
+
+struct _GstGLBumper
+{
+  GstGLFilter filter;
+  GstGLShader *shader;
+  GLuint bumpmap;
+  gint bumpmap_width;
+  gint bumpmap_height;
+  gchar *location;
+};
+
+struct _GstGLBumperClass
+{
+  GstGLFilterClass filter_class;
+};
+
+GType gst_gl_bumper_get_type (void);
+
+G_END_DECLS
+
+#endif /* _GST_GLBUMPER_H_ */
diff --git a/ext/gl/gstglcolorscale.c b/ext/gl/gstglcolorscale.c
new file mode 100644 (file)
index 0000000..10ea7fc
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.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.
+ */
+
+/**
+ * SECTION:element-glcolorscale
+ *
+ * video frame scaling and colorspace conversion.
+ *
+ * <refsect2>
+ * <title>Scaling and Color space conversion</title>
+ * <para>
+ * Equivalent to glupload ! gldownload.
+ * </para>
+ * </refsect2>
+ * <refsect2>
+ * <title>Examples</title>
+ * |[
+ * gst-launch -v videotestsrc ! "video/x-raw-yuv" ! glcolorscale ! ximagesink
+ * ]| A pipeline to test colorspace conversion.
+ * FBO is required.
+  |[
+ * gst-launch -v videotestsrc ! "video/x-raw-yuv, width=640, height=480, format=(fourcc)AYUV" ! glcolorscale ! \
+ *   "video/x-raw-yuv, width=320, height=240, format=(fourcc)YV12" ! autovideosink
+ * ]| A pipeline to test hardware scaling and colorspace conversion.
+ * FBO and GLSL are required.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstglcolorscale.h"
+
+
+#define GST_CAT_DEFAULT gst_gl_colorscale_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+/* Properties */
+enum
+{
+  PROP_0
+};
+
+#define DEBUG_INIT \
+  GST_DEBUG_CATEGORY_INIT (gst_gl_colorscale_debug, "glcolorscale", 0, "glcolorscale element");
+
+G_DEFINE_TYPE_WITH_CODE (GstGLColorscale, gst_gl_colorscale,
+    GST_TYPE_GL_FILTER, DEBUG_INIT);
+
+static void gst_gl_colorscale_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_gl_colorscale_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_gl_colorscale_filter_texture (GstGLFilter * filter,
+    guint in_tex, guint out_tex);
+static void gst_gl_colorscale_callback (gint width, gint height,
+    guint texture, gpointer stuff);
+
+static void
+gst_gl_colorscale_class_init (GstGLColorscaleClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *element_class;
+  GstGLFilterClass *filter_class;
+
+  gobject_class = (GObjectClass *) klass;
+  element_class = GST_ELEMENT_CLASS (klass);
+  filter_class = GST_GL_FILTER_CLASS (klass);
+
+  gobject_class->set_property = gst_gl_colorscale_set_property;
+  gobject_class->get_property = gst_gl_colorscale_get_property;
+
+  gst_element_class_set_metadata (element_class, "OpenGL color scale",
+      "Filter/Effect/Video", "Colorspace converter and video scaler",
+      "Julien Isorce <julien.isorce@gmail.com>");
+
+  filter_class->filter_texture = gst_gl_colorscale_filter_texture;
+}
+
+static void
+gst_gl_colorscale_init (GstGLColorscale * colorscale)
+{
+}
+
+static void
+gst_gl_colorscale_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_gl_colorscale_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_gl_colorscale_filter_texture (GstGLFilter * filter, guint in_tex,
+    guint out_tex)
+{
+  GstGLColorscale *colorscale;
+
+  colorscale = GST_GL_COLORSCALE (filter);
+
+  gst_gl_filter_render_to_target (filter, TRUE, in_tex, out_tex,
+      gst_gl_colorscale_callback, colorscale);
+
+  return TRUE;
+}
+
+static void
+gst_gl_colorscale_callback (gint width, gint height, guint texture,
+    gpointer stuff)
+{
+  GstGLFilter *filter = GST_GL_FILTER (stuff);
+
+#if GST_GL_HAVE_OPENGL
+  if (gst_gl_context_get_gl_api (filter->context) & GST_GL_API_OPENGL) {
+    const GstGLFuncs *gl = filter->context->gl_vtable;
+
+    gl->MatrixMode (GL_PROJECTION);
+    gl->LoadIdentity ();
+  }
+#endif
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
diff --git a/ext/gl/gstglcolorscale.h b/ext/gl/gstglcolorscale.h
new file mode 100644 (file)
index 0000000..29e306e
--- /dev/null
@@ -0,0 +1,56 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.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.
+ */
+
+#ifndef _GST_GLCOLORSCALE_H_
+#define _GST_GLCOLORSCALE_H_
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+
+#include <gst/gl/gstglfilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_GL_COLORSCALE            (gst_gl_colorscale_get_type())
+#define GST_GL_COLORSCALE(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_COLORSCALE,GstGLColorscale))
+#define GST_IS_GL_COLORSCALE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_COLORSCALE))
+#define GST_GL_COLORSCALE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_COLORSCALE,GstGLColorscaleClass))
+#define GST_IS_GL_COLORSCALE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_COLORSCALE))
+#define GST_GL_COLORSCALE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_COLORSCALE,GstGLColorscaleClass))
+
+typedef struct _GstGLColorscale GstGLColorscale;
+typedef struct _GstGLColorscaleClass GstGLColorscaleClass;
+
+
+struct _GstGLColorscale
+{
+    GstGLFilter filter;
+};
+
+struct _GstGLColorscaleClass
+{
+    GstGLFilterClass filter_class;
+};
+
+GType gst_gl_colorscale_get_type (void);
+
+G_END_DECLS
+
+#endif /* _GST_GLCOLORSCALE_H_ */
diff --git a/ext/gl/gstgldeinterlace.c b/ext/gl/gstgldeinterlace.c
new file mode 100644 (file)
index 0000000..b420fa6
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+ * GStreamer
+ * Copyright (C) 2009 Julien Isorce <julien.isorce@mail.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.
+ */
+
+/**
+ * SECTION:element-deinterlace
+ *
+ * Deinterlacing using based on fragment shaders.
+ *
+ * <refsect2>
+ * <title>Examples</title>
+ * |[
+ * gst-launch videotestsrc ! glupload ! gldeinterlace ! glimagesink
+ * ]|
+ * FBO (Frame Buffer Object) and GLSL (OpenGL Shading Language) are required.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstgldeinterlace.h"
+
+#define GST_CAT_DEFAULT gst_gl_deinterlace_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+enum
+{
+  PROP_0
+};
+
+#define DEBUG_INIT \
+  GST_DEBUG_CATEGORY_INIT (gst_gl_deinterlace_debug, "gldeinterlace", 0, "gldeinterlace element");
+
+G_DEFINE_TYPE_WITH_CODE (GstGLDeinterlace, gst_gl_deinterlace,
+    GST_TYPE_GL_FILTER, DEBUG_INIT);
+
+static void gst_gl_deinterlace_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_gl_deinterlace_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+
+static void gst_gl_deinterlace_reset (GstGLFilter * filter);
+static gboolean gst_gl_deinterlace_init_shader (GstGLFilter * filter);
+static gboolean gst_gl_deinterlace_filter (GstGLFilter * filter,
+    GstBuffer * inbuf, GstBuffer * outbuf);
+static gboolean gst_gl_deinterlace_filter_texture (GstGLFilter * filter,
+    guint in_tex, guint out_tex);
+static void gst_gl_deinterlace_callback (gint width, gint height,
+    guint texture, gpointer stuff);
+
+/* *INDENT-OFF* */
+static const gchar *greedyh_fragment_source =
+  "uniform sampler2D tex;\n"
+  "uniform sampler2D tex_prev;\n"
+  "uniform float max_comb;\n"
+  "uniform float motion_threshold;\n"
+  "uniform float motion_sense;\n"
+  "uniform float width;\n"
+  "uniform float height;\n"
+
+  "void main () {\n"
+  "  vec2 texcoord = gl_TexCoord[0].xy;\n"
+  "  if (int(mod(texcoord.y * height, 2.0)) == 0) {\n"
+  "    gl_FragColor = vec4(texture2D(tex_prev, texcoord).rgb, 1.0);\n"
+  "  } else {\n"
+  "    vec2 texcoord_L1_a1, texcoord_L3_a1, texcoord_L1, texcoord_L3, texcoord_L1_1, texcoord_L3_1;\n"
+  "    vec3 L1_a1, L3_a1, L1, L3, L1_1, L3_1;\n"
+
+  "    texcoord_L1 = vec2(texcoord.x, texcoord.y - 1.0 / height);\n"
+  "    texcoord_L3 = vec2(texcoord.x, texcoord.y + 1.0 / height);\n"
+  "    L1 = texture2D(tex_prev, texcoord_L1).rgb;\n"
+  "    L3 = texture2D(tex_prev, texcoord_L3).rgb;\n"
+  "    if (texcoord.x == 1.0 && texcoord.y == 1.0) {\n"
+  "      L1_1 = L1;\n"
+  "      L3_1 = L3;\n"
+  "    } else {\n"
+  "      texcoord_L1_1 = vec2(texcoord.x + 1.0 / width, texcoord.y - 1.0 / height);\n"
+  "      texcoord_L3_1 = vec2(texcoord.x + 1.0 / width, texcoord.y + 1.0 / height);\n"
+  "      L1_1 = texture2D(tex_prev, texcoord_L1_1).rgb;\n"
+  "      L3_1 = texture2D(tex_prev, texcoord_L3_1).rgb;\n"
+  "    }\n"
+
+  "    if (int(ceil(texcoord.x + texcoord.y)) == 0) {\n"
+  "      L1_a1 = L1;\n"
+  "      L3_a1 = L3;\n"
+  "    } else {\n"
+  "      texcoord_L1_a1 = vec2(texcoord.x - 1.0 / width, texcoord.y - 1.0 / height);\n"
+  "      texcoord_L3_a1 = vec2(texcoord.x - 1.0 / width, texcoord.y + 1.0 / height);\n"
+  "      L1_a1 = texture2D(tex_prev, texcoord_L1_a1).rgb;\n"
+  "      L3_a1 = texture2D(tex_prev, texcoord_L3_a1).rgb;\n"
+  "    }\n"
+          //STEP 1
+  "    vec3 avg_a1 = (L1_a1 + L3_a1) / 2.0;\n"
+  "    vec3 avg = (L1 + L3) / 2.0;\n"
+  "    vec3 avg_1 = (L1_1 + L3_1) / 2.0;\n"
+  "    vec3 avg_s = (avg_a1 + avg_1) / 2.0;\n"
+  "    vec3 avg_sc = (avg_s + avg) / 2.0;\n"
+  "    vec3 L2 = texture2D(tex, texcoord).rgb;\n"
+  "    vec3 LP2 = texture2D(tex_prev, texcoord).rgb;\n"
+  "    vec3 best;\n"
+  "    if (abs(L2.r - avg_sc.r) < abs(LP2.r - avg_sc.r)) {\n"
+  "      best.r = L2.r;\n" "    } else {\n"
+  "      best.r = LP2.r;\n"
+  "    }\n"
+
+  "    if (abs(L2.g - avg_sc.g) < abs(LP2.g - avg_sc.g)) {\n"
+  "      best.g = L2.g;\n"
+  "    } else {\n"
+  "      best.g = LP2.g;\n"
+  "    }\n"
+
+  "    if (abs(L2.b - avg_sc.b) < abs(LP2.b - avg_sc.b)) {\n"
+  "      best.b = L2.b;\n"
+  "    } else {\n"
+  "      best.b = LP2.b;\n"
+  "    }\n"
+          //STEP 2
+  "    vec3 last;\n"
+  "    last.r = clamp(best.r, max(min(L1.r, L3.r) - max_comb, 0.0), min(max(L1.r, L3.r) + max_comb, 1.0));\n"
+  "    last.g = clamp(best.g, max(min(L1.g, L3.g) - max_comb, 0.0), min(max(L1.g, L3.g) + max_comb, 1.0));\n"
+  "    last.b = clamp(best.b, max(min(L1.b, L3.b) - max_comb, 0.0), min(max(L1.b, L3.b) + max_comb, 1.0));\n"
+          //STEP 3
+  "    const vec3 luma = vec3 (0.299011, 0.586987, 0.114001);"
+  "    float mov = min(max(abs(dot(L2 - LP2, luma)) - motion_threshold, 0.0) * motion_sense, 1.0);\n"
+  "    last = last * (1.0 - mov) + avg_sc * mov;\n"
+  "    gl_FragColor = vec4(last, 1.0);\n"
+  "  }\n"
+  "}\n";
+/* *INDENT-ON* */
+
+static void
+gst_gl_deinterlace_class_init (GstGLDeinterlaceClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *element_class;
+
+  gobject_class = (GObjectClass *) klass;
+  element_class = GST_ELEMENT_CLASS (klass);
+
+  gobject_class->set_property = gst_gl_deinterlace_set_property;
+  gobject_class->get_property = gst_gl_deinterlace_get_property;
+
+  gst_element_class_set_metadata (element_class,
+      "OpenGL deinterlacing filter", "Deinterlace",
+      "Deinterlacing based on fragment shaders",
+      "Julien Isorce <julien.isorce@mail.com>");
+
+  GST_GL_FILTER_CLASS (klass)->filter = gst_gl_deinterlace_filter;
+  GST_GL_FILTER_CLASS (klass)->filter_texture =
+      gst_gl_deinterlace_filter_texture;
+  GST_GL_FILTER_CLASS (klass)->onInitFBO = gst_gl_deinterlace_init_shader;
+  GST_GL_FILTER_CLASS (klass)->onReset = gst_gl_deinterlace_reset;
+}
+
+static void
+gst_gl_deinterlace_init (GstGLDeinterlace * filter)
+{
+  filter->shader = NULL;
+  filter->prev_buffer = NULL;
+  filter->prev_tex = 0;
+}
+
+static void
+gst_gl_deinterlace_reset (GstGLFilter * filter)
+{
+  GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (filter);
+
+  if (deinterlace_filter->prev_buffer) {
+    gst_buffer_unref (deinterlace_filter->prev_buffer);
+    deinterlace_filter->prev_buffer = NULL;
+  }
+  //blocking call, wait the opengl thread has destroyed the shader
+  if (deinterlace_filter->shader)
+    gst_gl_context_del_shader (filter->context, deinterlace_filter->shader);
+  deinterlace_filter->shader = NULL;
+}
+
+static void
+gst_gl_deinterlace_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  //GstGLDeinterlace *filter = GST_GL_DEINTERLACE (object);
+
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_gl_deinterlace_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  //GstGLDeinterlace *filter = GST_GL_DEINTERLACE (object);
+
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_gl_deinterlace_init_shader (GstGLFilter * filter)
+{
+  GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (filter);
+
+  //blocking call, wait the opengl thread has compiled the shader
+  return gst_gl_context_gen_shader (filter->context, 0, greedyh_fragment_source,
+      &deinterlace_filter->shader);
+}
+
+static gboolean
+gst_gl_deinterlace_filter_texture (GstGLFilter * filter, guint in_tex,
+    guint out_tex)
+{
+  GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (filter);
+
+  //blocking call, use a FBO
+  gst_gl_filter_render_to_target (filter, TRUE, in_tex, out_tex,
+      gst_gl_deinterlace_callback, deinterlace_filter);
+
+  return TRUE;
+}
+
+static gboolean
+gst_gl_deinterlace_filter (GstGLFilter * filter, GstBuffer * inbuf,
+    GstBuffer * outbuf)
+{
+  GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (filter);
+
+  gst_gl_filter_filter_texture (filter, inbuf, outbuf);
+
+  if (deinterlace_filter->prev_buffer) {
+    gst_buffer_unref (deinterlace_filter->prev_buffer);
+  }
+  deinterlace_filter->prev_buffer = gst_buffer_ref (inbuf);
+
+  return TRUE;
+}
+
+//opengl scene, params: input texture (not the output filter->texture)
+static void
+gst_gl_deinterlace_callback (gint width, gint height, guint texture,
+    gpointer stuff)
+{
+  GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (stuff);
+  GstGLFilter *filter = GST_GL_FILTER (stuff);
+  GstGLFuncs *gl = filter->context->gl_vtable;
+  guint temp;
+
+  GLfloat verts[] = { -1.0, -1.0,
+    1.0, -1.0,
+    1.0, 1.0,
+    -1.0, 1.0
+  };
+  GLfloat texcoords0[] = { 0.0f, 0.0f,
+    1.0f, 0.0f,
+    1.0f, 1.0f,
+    0.0f, 1.0f
+  };
+  GLfloat texcoords1[] = { 0.0f, 0.0f,
+    1.0f, 0.0f,
+    1.0f, 1.0f,
+    0.0f, 1.0f
+  };
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+
+  gst_gl_shader_use (deinterlace_filter->shader);
+
+  gl->Enable (GL_TEXTURE_2D);
+
+  if (G_UNLIKELY (deinterlace_filter->prev_tex == 0)) {
+    gst_gl_context_gen_texture (filter->context,
+        &deinterlace_filter->prev_tex,
+        GST_VIDEO_INFO_FORMAT (&filter->out_info),
+        GST_VIDEO_INFO_WIDTH (&filter->out_info),
+        GST_VIDEO_INFO_HEIGHT (&filter->out_info));
+  } else {
+    gl->ActiveTexture (GL_TEXTURE1);
+    gst_gl_shader_set_uniform_1i (deinterlace_filter->shader, "tex_prev", 1);
+    gl->BindTexture (GL_TEXTURE_2D, deinterlace_filter->prev_tex);
+  }
+
+  gl->ActiveTexture (GL_TEXTURE0);
+  gst_gl_shader_set_uniform_1i (deinterlace_filter->shader, "tex", 0);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+
+  gst_gl_shader_set_uniform_1f (deinterlace_filter->shader, "max_comb",
+      5.0f / 255.0f);
+  gst_gl_shader_set_uniform_1f (deinterlace_filter->shader, "motion_threshold",
+      25.0f / 255.0f);
+  gst_gl_shader_set_uniform_1f (deinterlace_filter->shader, "motion_sense",
+      30.0f / 255.0f);
+
+  gst_gl_shader_set_uniform_1f (deinterlace_filter->shader, "width",
+      GST_VIDEO_INFO_WIDTH (&filter->out_info));
+  gst_gl_shader_set_uniform_1f (deinterlace_filter->shader, "height",
+      GST_VIDEO_INFO_HEIGHT (&filter->out_info));
+
+  gl->ClientActiveTexture (GL_TEXTURE0);
+
+  gl->EnableClientState (GL_TEXTURE_COORD_ARRAY);
+  gl->EnableClientState (GL_VERTEX_ARRAY);
+
+  gl->VertexPointer (2, GL_FLOAT, 0, &verts);
+  gl->TexCoordPointer (2, GL_FLOAT, 0, &texcoords0);
+
+  gl->ClientActiveTexture (GL_TEXTURE1);
+  gl->EnableClientState (GL_TEXTURE_COORD_ARRAY);
+  gl->TexCoordPointer (2, GL_FLOAT, 0, &texcoords1);
+
+  gl->DrawArrays (GL_TRIANGLE_FAN, 0, 4);
+
+  gl->DisableClientState (GL_VERTEX_ARRAY);
+  gl->DisableClientState (GL_TEXTURE_COORD_ARRAY);
+
+  gl->ClientActiveTexture (GL_TEXTURE0);
+  gl->DisableClientState (GL_TEXTURE_COORD_ARRAY);
+
+  gl->Disable (GL_TEXTURE_2D);
+
+  if (texture == filter->in_tex_id) {
+    temp = filter->in_tex_id;
+    filter->in_tex_id = deinterlace_filter->prev_tex;
+    deinterlace_filter->prev_tex = temp;
+  } else {
+    deinterlace_filter->prev_tex = texture;
+  }
+}
diff --git a/ext/gl/gstgldeinterlace.h b/ext/gl/gstgldeinterlace.h
new file mode 100644 (file)
index 0000000..a81a2e7
--- /dev/null
@@ -0,0 +1,55 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2009 Julien Isorce <julien.isorce@gmail.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.
+ */
+
+#ifndef _GST_GL_DEINTERLACE_H_
+#define _GST_GL_DEINTERLACE_H_
+
+#include <gst/gl/gstglfilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_GL_DEINTERLACE            (gst_gl_deinterlace_get_type())
+#define GST_GL_DEINTERLACE(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_DEINTERLACE,GstGLDeinterlace))
+#define GST_IS_GL_DEINTERLACE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_DEINTERLACE))
+#define GST_GL_DEINTERLACE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_DEINTERLACE,GstGLDeinterlaceClass))
+#define GST_IS_GL_DEINTERLACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_DEINTERLACE))
+#define GST_GL_DEINTERLACE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_DEINTERLACE,GstGLDeinterlaceClass))
+
+typedef struct _GstGLDeinterlace GstGLDeinterlace;
+typedef struct _GstGLDeinterlaceClass GstGLDeinterlaceClass;
+
+struct _GstGLDeinterlace
+{
+  GstGLFilter  filter;
+  GstGLShader  *shader;
+  GstBuffer    *prev_buffer;
+  guint         prev_tex;
+};
+
+struct _GstGLDeinterlaceClass
+{
+  GstGLFilterClass filter_class;
+};
+
+GType gst_gl_deinterlace_get_type (void);
+
+G_END_DECLS
+
+#endif /* _GST_GLFILTERLAPLACIAN_H_ */
diff --git a/ext/gl/gstgldifferencematte.c b/ext/gl/gstgldifferencematte.c
new file mode 100644 (file)
index 0000000..f04c4c4
--- /dev/null
@@ -0,0 +1,581 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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.
+ */
+
+/**
+ * SECTION:element-gldifferencematte.
+ *
+ * Saves a background frame and replace it with a pixbuf.
+ *
+ * <refsect2>
+ * <title>Examples</title>
+ * |[
+ * gst-launch videotestsrc ! glupload ! gldifferencemate location=backgroundimagefile ! glimagesink
+ * ]|
+ * FBO (Frame Buffer Object) and GLSL (OpenGL Shading Language) are required.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <png.h>
+
+#include "gstgldifferencematte.h"
+#include "effects/gstgleffectssources.h"
+
+#if PNG_LIBPNG_VER >= 10400
+#define int_p_NULL         NULL
+#define png_infopp_NULL    NULL
+#endif
+
+#define GST_CAT_DEFAULT gst_gl_differencematte_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+#define DEBUG_INIT \
+  GST_DEBUG_CATEGORY_INIT (gst_gl_differencematte_debug, "gldifferencematte", 0, "gldifferencematte element");
+
+G_DEFINE_TYPE_WITH_CODE (GstGLDifferenceMatte, gst_gl_differencematte,
+    GST_TYPE_GL_FILTER, DEBUG_INIT);
+
+static void gst_gl_differencematte_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_gl_differencematte_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+
+static void gst_gl_differencematte_init_resources (GstGLFilter * filter);
+static void gst_gl_differencematte_reset_resources (GstGLFilter * filter);
+
+static gboolean gst_gl_differencematte_filter_texture (GstGLFilter * filter,
+    guint in_tex, guint out_tex);
+
+static gboolean gst_gl_differencematte_loader (GstGLFilter * filter);
+
+enum
+{
+  PROP_0,
+  PROP_LOCATION,
+};
+
+
+/* init resources that need a gl context */
+static void
+gst_gl_differencematte_init_gl_resources (GstGLFilter * filter)
+{
+  GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (filter);
+  GstGLFuncs *gl = filter->context->gl_vtable;
+  gint i;
+
+  for (i = 0; i < 4; i++) {
+    gl->GenTextures (1, &differencematte->midtexture[i]);
+    gl->BindTexture (GL_TEXTURE_2D, differencematte->midtexture[i]);
+    gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8,
+        GST_VIDEO_INFO_WIDTH (&filter->out_info),
+        GST_VIDEO_INFO_HEIGHT (&filter->out_info),
+        0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+    gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    differencematte->shader[i] = gst_gl_shader_new (filter->context);
+  }
+
+  if (!gst_gl_shader_compile_and_check (differencematte->shader[0],
+          difference_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
+    gst_gl_context_set_error (GST_GL_FILTER (differencematte)->context,
+        "Failed to initialize difference shader");
+    GST_ELEMENT_ERROR (differencematte, RESOURCE, NOT_FOUND,
+        ("%s", gst_gl_context_get_error ()), (NULL));
+    return;
+  }
+
+  if (!gst_gl_shader_compile_and_check (differencematte->shader[1],
+          hconv7_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
+    gst_gl_context_set_error (GST_GL_FILTER (differencematte)->context,
+        "Failed to initialize hconv7 shader");
+    GST_ELEMENT_ERROR (differencematte, RESOURCE, NOT_FOUND,
+        ("%s", gst_gl_context_get_error ()), (NULL));
+    return;
+  }
+
+  if (!gst_gl_shader_compile_and_check (differencematte->shader[2],
+          vconv7_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
+    gst_gl_context_set_error (GST_GL_FILTER (differencematte)->context,
+        "Failed to initialize vconv7 shader");
+    GST_ELEMENT_ERROR (differencematte, RESOURCE, NOT_FOUND,
+        ("%s", gst_gl_context_get_error ()), (NULL));
+    return;
+  }
+
+  if (!gst_gl_shader_compile_and_check (differencematte->shader[3],
+          texture_interp_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
+    gst_gl_context_set_error (GST_GL_FILTER (differencematte)->context,
+        "Failed to initialize interp shader");
+    GST_ELEMENT_ERROR (differencematte, RESOURCE, NOT_FOUND,
+        ("%s", gst_gl_context_get_error ()), (NULL));
+    return;
+  }
+}
+
+/* free resources that need a gl context */
+static void
+gst_gl_differencematte_reset_gl_resources (GstGLFilter * filter)
+{
+  GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (filter);
+  GstGLFuncs *gl = filter->context->gl_vtable;
+  gint i;
+
+  gl->DeleteTextures (1, &differencematte->savedbgtexture);
+  gl->DeleteTextures (1, &differencematte->newbgtexture);
+  for (i = 0; i < 4; i++) {
+    if (differencematte->shader[i]) {
+      gst_object_unref (differencematte->shader[i]);
+      differencematte->shader[i] = NULL;
+    }
+    if (differencematte->midtexture[i]) {
+      gl->DeleteTextures (1, &differencematte->midtexture[i]);
+      differencematte->midtexture[i] = 0;
+    }
+  }
+  differencematte->location = NULL;
+  differencematte->pixbuf = NULL;
+  differencematte->savedbgtexture = 0;
+  differencematte->newbgtexture = 0;
+  differencematte->bg_has_changed = FALSE;
+}
+
+static void
+gst_gl_differencematte_class_init (GstGLDifferenceMatteClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *element_class;
+
+  gobject_class = (GObjectClass *) klass;
+  element_class = GST_ELEMENT_CLASS (klass);
+  gobject_class->set_property = gst_gl_differencematte_set_property;
+  gobject_class->get_property = gst_gl_differencematte_get_property;
+
+  GST_GL_FILTER_CLASS (klass)->filter_texture =
+      gst_gl_differencematte_filter_texture;
+  GST_GL_FILTER_CLASS (klass)->display_init_cb =
+      gst_gl_differencematte_init_gl_resources;
+  GST_GL_FILTER_CLASS (klass)->display_reset_cb =
+      gst_gl_differencematte_reset_gl_resources;
+  GST_GL_FILTER_CLASS (klass)->onStart = gst_gl_differencematte_init_resources;
+  GST_GL_FILTER_CLASS (klass)->onStop = gst_gl_differencematte_reset_resources;
+
+  g_object_class_install_property (gobject_class,
+      PROP_LOCATION,
+      g_param_spec_string ("location",
+          "Background image location",
+          "Background image location", NULL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_metadata (element_class,
+      "Gstreamer OpenGL DifferenceMatte", "Filter/Effect/Video",
+      "Saves a background frame and replace it with a pixbuf",
+      "Filippo Argiolas <filippo.argiolas@gmail.com>");
+}
+
+static void
+gst_gl_differencematte_init (GstGLDifferenceMatte * differencematte)
+{
+  differencematte->shader[0] = NULL;
+  differencematte->shader[1] = NULL;
+  differencematte->shader[2] = NULL;
+  differencematte->shader[3] = NULL;
+  differencematte->location = NULL;
+  differencematte->pixbuf = NULL;
+  differencematte->savedbgtexture = 0;
+  differencematte->newbgtexture = 0;
+  differencematte->bg_has_changed = FALSE;
+
+  fill_gaussian_kernel (differencematte->kernel, 7, 30.0);
+}
+
+static void
+gst_gl_differencematte_reset_resources (GstGLFilter * filter)
+{
+//  GstGLDifferenceMatte* differencematte = GST_GL_DIFFERENCEMATTE(filter);
+}
+
+static void
+gst_gl_differencematte_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (object);
+
+  switch (prop_id) {
+    case PROP_LOCATION:
+      if (differencematte->location != NULL)
+        g_free (differencematte->location);
+      differencematte->bg_has_changed = TRUE;
+      differencematte->location = g_value_dup_string (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_gl_differencematte_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (object);
+
+  switch (prop_id) {
+    case PROP_LOCATION:
+      g_value_set_string (value, differencematte->location);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_gl_differencematte_init_resources (GstGLFilter * filter)
+{
+//  GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (filter);
+}
+
+static void
+gst_gl_differencematte_save_texture (gint width, gint height, guint texture,
+    gpointer stuff)
+{
+  GstGLFilter *filter = GST_GL_FILTER (stuff);
+  GstGLFuncs *gl = filter->context->gl_vtable;
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
+
+static void
+init_pixbuf_texture (GstGLContext * context, gpointer data)
+{
+  GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (data);
+  GstGLFilter *filter = GST_GL_FILTER (data);
+  GstGLFuncs *gl = filter->context->gl_vtable;
+
+  gl->DeleteTextures (1, &differencematte->newbgtexture);
+  gl->GenTextures (1, &differencematte->newbgtexture);
+  gl->BindTexture (GL_TEXTURE_2D, differencematte->newbgtexture);
+  gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGBA,
+      (gint) differencematte->pbuf_width, (gint) differencematte->pbuf_height,
+      0, GL_RGBA, GL_UNSIGNED_BYTE, differencematte->pixbuf);
+  gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+  gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+  gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+  gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+  if (differencematte->savedbgtexture == 0) {
+    gl->GenTextures (1, &differencematte->savedbgtexture);
+    gl->BindTexture (GL_TEXTURE_2D, differencematte->savedbgtexture);
+    gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8,
+        GST_VIDEO_INFO_WIDTH (&filter->out_info),
+        GST_VIDEO_INFO_HEIGHT (&filter->out_info),
+        0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+    gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+  }
+}
+
+static void
+gst_gl_differencematte_diff (gint width, gint height, guint texture,
+    gpointer stuff)
+{
+  GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (stuff);
+  GstGLFilter *filter = GST_GL_FILTER (stuff);
+  GstGLFuncs *gl = filter->context->gl_vtable;
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+
+  gst_gl_shader_use (differencematte->shader[0]);
+
+  gl->ActiveTexture (GL_TEXTURE0);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+  gl->Disable (GL_TEXTURE_2D);
+
+  gst_gl_shader_set_uniform_1i (differencematte->shader[0], "current", 0);
+
+  gl->ActiveTexture (GL_TEXTURE1);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, differencematte->savedbgtexture);
+  gl->Disable (GL_TEXTURE_2D);
+
+  gst_gl_shader_set_uniform_1i (differencematte->shader[0], "saved", 1);
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
+
+static void
+gst_gl_differencematte_hblur (gint width, gint height, guint texture,
+    gpointer stuff)
+{
+  GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (stuff);
+  GstGLFilter *filter = GST_GL_FILTER (stuff);
+  GstGLFuncs *gl = filter->context->gl_vtable;
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+
+  gst_gl_shader_use (differencematte->shader[1]);
+
+  gl->ActiveTexture (GL_TEXTURE0);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+  gl->Disable (GL_TEXTURE_2D);
+
+  gst_gl_shader_set_uniform_1i (differencematte->shader[1], "tex", 0);
+
+  gst_gl_shader_set_uniform_1fv (differencematte->shader[1], "kernel", 7,
+      differencematte->kernel);
+  gst_gl_shader_set_uniform_1f (differencematte->shader[1], "width", width);
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
+
+static void
+gst_gl_differencematte_vblur (gint width, gint height, guint texture,
+    gpointer stuff)
+{
+  GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (stuff);
+  GstGLFilter *filter = GST_GL_FILTER (stuff);
+  GstGLFuncs *gl = filter->context->gl_vtable;
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+
+  gst_gl_shader_use (differencematte->shader[2]);
+
+  gl->ActiveTexture (GL_TEXTURE0);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+  gl->Disable (GL_TEXTURE_2D);
+
+  gst_gl_shader_set_uniform_1i (differencematte->shader[2], "tex", 0);
+
+  gst_gl_shader_set_uniform_1fv (differencematte->shader[2], "kernel", 7,
+      differencematte->kernel);
+  gst_gl_shader_set_uniform_1f (differencematte->shader[2], "height", height);
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
+
+static void
+gst_gl_differencematte_interp (gint width, gint height, guint texture,
+    gpointer stuff)
+{
+  GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (stuff);
+  GstGLFilter *filter = GST_GL_FILTER (stuff);
+  GstGLFuncs *gl = filter->context->gl_vtable;
+
+  gl->MatrixMode (GL_PROJECTION);
+  glLoadIdentity ();
+
+  gst_gl_shader_use (differencematte->shader[3]);
+
+  gl->ActiveTexture (GL_TEXTURE0);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+  gl->Disable (GL_TEXTURE_2D);
+
+  gst_gl_shader_set_uniform_1i (differencematte->shader[3], "blend", 0);
+
+  gl->ActiveTexture (GL_TEXTURE1);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, differencematte->newbgtexture);
+  gl->Disable (GL_TEXTURE_2D);
+
+  gst_gl_shader_set_uniform_1i (differencematte->shader[3], "base", 1);
+
+  gl->ActiveTexture (GL_TEXTURE2);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, differencematte->midtexture[2]);
+  gl->Disable (GL_TEXTURE_2D);
+
+  gst_gl_shader_set_uniform_1i (differencematte->shader[3], "alpha", 2);
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
+
+static void
+gst_gl_differencematte_identity (gint width, gint height, guint texture,
+    gpointer stuff)
+{
+  GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (stuff);
+  GstGLFilter *filter = GST_GL_FILTER (differencematte);
+  GstGLFuncs *gl = filter->context->gl_vtable;
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
+
+static gboolean
+gst_gl_differencematte_filter_texture (GstGLFilter * filter, guint in_tex,
+    guint out_tex)
+{
+  GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (filter);
+
+  differencematte->intexture = in_tex;
+
+  if (differencematte->bg_has_changed && (differencematte->location != NULL)) {
+
+    if (!gst_gl_differencematte_loader (filter))
+      differencematte->pixbuf = NULL;
+
+    /* if loader failed then context is turned off */
+    gst_gl_context_thread_add (filter->context, init_pixbuf_texture,
+        differencematte);
+
+    /* save current frame, needed to calculate difference between
+     * this frame and next ones */
+    gst_gl_filter_render_to_target (filter, TRUE, in_tex,
+        differencematte->savedbgtexture,
+        gst_gl_differencematte_save_texture, differencematte);
+
+    if (differencematte->pixbuf) {
+      free (differencematte->pixbuf);
+      differencematte->pixbuf = NULL;
+    }
+
+    differencematte->bg_has_changed = FALSE;
+  }
+
+  if (differencematte->savedbgtexture != 0) {
+    gst_gl_filter_render_to_target (filter, TRUE, in_tex,
+        differencematte->midtexture[0], gst_gl_differencematte_diff,
+        differencematte);
+    gst_gl_filter_render_to_target (filter, FALSE,
+        differencematte->midtexture[0], differencematte->midtexture[1],
+        gst_gl_differencematte_hblur, differencematte);
+    gst_gl_filter_render_to_target (filter, FALSE,
+        differencematte->midtexture[1], differencematte->midtexture[2],
+        gst_gl_differencematte_vblur, differencematte);
+    gst_gl_filter_render_to_target (filter, TRUE, in_tex, out_tex,
+        gst_gl_differencematte_interp, differencematte);
+  } else {
+    gst_gl_filter_render_to_target (filter, TRUE, in_tex, out_tex,
+        gst_gl_differencematte_identity, differencematte);
+  }
+
+  return TRUE;
+}
+
+static void
+user_warning_fn (png_structp png_ptr, png_const_charp warning_msg)
+{
+  g_warning ("%s\n", warning_msg);
+}
+
+#define LOAD_ERROR(msg) { GST_WARNING ("unable to load %s: %s", differencematte->location, msg); return FALSE; }
+
+static gboolean
+gst_gl_differencematte_loader (GstGLFilter * filter)
+{
+  GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (filter);
+
+  png_structp png_ptr;
+  png_infop info_ptr;
+  guint sig_read = 0;
+  png_uint_32 width = 0;
+  png_uint_32 height = 0;
+  gint bit_depth = 0;
+  gint color_type = 0;
+  gint interlace_type = 0;
+  png_FILE_p fp = NULL;
+  guint y = 0;
+  guchar **rows = NULL;
+  gint filler;
+
+  if (!filter->context)
+    return TRUE;
+
+  if ((fp = fopen (differencematte->location, "rb")) == NULL)
+    LOAD_ERROR ("file not found");
+
+  png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+
+  if (png_ptr == NULL) {
+    fclose (fp);
+    LOAD_ERROR ("failed to initialize the png_struct");
+  }
+
+  png_set_error_fn (png_ptr, NULL, NULL, user_warning_fn);
+
+  info_ptr = png_create_info_struct (png_ptr);
+  if (info_ptr == NULL) {
+    fclose (fp);
+    png_destroy_read_struct (&png_ptr, png_infopp_NULL, png_infopp_NULL);
+    LOAD_ERROR ("failed to initialize the memory for image information");
+  }
+
+  png_init_io (png_ptr, fp);
+
+  png_set_sig_bytes (png_ptr, sig_read);
+
+  png_read_info (png_ptr, info_ptr);
+
+  png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
+      &interlace_type, int_p_NULL, int_p_NULL);
+
+  if (color_type == PNG_COLOR_TYPE_RGB) {
+    filler = 0xff;
+    png_set_filler (png_ptr, filler, PNG_FILLER_AFTER);
+    color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+  }
+
+  if (color_type != PNG_COLOR_TYPE_RGB_ALPHA) {
+    fclose (fp);
+    png_destroy_read_struct (&png_ptr, png_infopp_NULL, png_infopp_NULL);
+    LOAD_ERROR ("color type is not rgb");
+  }
+
+  differencematte->pbuf_width = width;
+  differencematte->pbuf_height = height;
+
+  differencematte->pixbuf =
+      (guchar *) malloc (sizeof (guchar) * width * height * 4);
+
+  rows = (guchar **) malloc (sizeof (guchar *) * height);
+
+  for (y = 0; y < height; ++y)
+    rows[y] = (guchar *) (differencematte->pixbuf + y * width * 4);
+
+  png_read_image (png_ptr, rows);
+
+  free (rows);
+
+  png_read_end (png_ptr, info_ptr);
+  png_destroy_read_struct (&png_ptr, &info_ptr, png_infopp_NULL);
+  fclose (fp);
+
+  return TRUE;
+}
diff --git a/ext/gl/gstgldifferencematte.h b/ext/gl/gstgldifferencematte.h
new file mode 100644 (file)
index 0000000..a153c38
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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.
+ */
+
+#ifndef _GST_GL_DIFFERENCEMATTE_H_
+#define _GST_GL_DIFFERENCEMATTE_H_
+
+#include <gst/gl/gstglfilter.h>
+
+#define GST_TYPE_GL_DIFFERENCEMATTE            (gst_gl_differencematte_get_type())
+#define GST_GL_DIFFERENCEMATTE(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_GL_DIFFERENCEMATTE,GstGLDifferenceMatte))
+#define GST_IS_GL_DIFFERENCEMATTE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_GL_DIFFERENCEMATTE))
+#define GST_GL_DIFFERENCEMATTE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) , GST_TYPE_GL_DIFFERENCEMATTE,GstGLDifferenceMatteClass))
+#define GST_IS_GL_DIFFERENCEMATTE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) , GST_TYPE_GL_DIFFERENCEMATTE))
+#define GST_GL_DIFFERENCEMATTE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) , GST_TYPE_GL_DIFFERENCEMATTE,GstGLDifferenceMatteClass))
+
+typedef struct _GstGLDifferenceMatte GstGLDifferenceMatte;
+typedef struct _GstGLDifferenceMatteClass GstGLDifferenceMatteClass;
+
+struct _GstGLDifferenceMatte
+{
+  GstGLFilter filter;
+
+  GstGLShader *shader[4];
+
+  gchar *location;
+  gboolean bg_has_changed;
+
+  guchar *pixbuf;
+  gint pbuf_width, pbuf_height;
+  GLuint savedbgtexture;
+  GLuint newbgtexture;
+  GLuint midtexture[4];
+  GLuint intexture;
+  float kernel[7];
+};
+
+struct _GstGLDifferenceMatteClass
+{
+  GstGLFilterClass filter_class;
+};
+
+#endif /* _GST_GL_DIFFERENCEMATTE_H_ */
diff --git a/ext/gl/gstgleffects.c b/ext/gl/gstgleffects.c
new file mode 100644 (file)
index 0000000..4f7338a
--- /dev/null
@@ -0,0 +1,398 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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.
+ */
+
+/**
+ * SECTION:element-gleffects.
+ *
+ * GL Shading Language effects.
+ *
+ * <refsect2>
+ * <title>Examples</title>
+ * |[
+ * gst-launch videotestsrc ! glupload ! gleffects effect=5 ! glimagesink
+ * ]|
+ * FBO (Frame Buffer Object) and GLSL (OpenGL Shading Language) are required.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gl/gstglconfig.h>
+#include "gstgleffects.h"
+
+#define GST_TYPE_GL_EFFECTS            (gst_gl_effects_get_type())
+#define GST_GL_EFFECTS(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_GL_EFFECTS,GstGLEffects))
+#define GST_IS_GL_EFFECTS(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_GL_EFFECTS))
+#define GST_GL_EFFECTS_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) , GST_TYPE_GL_EFFECTS,GstGLEffectsClass))
+#define GST_IS_GL_EFFECTS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) , GST_TYPE_GL_EFFECTS))
+#define GST_GL_EFFECTS_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) , GST_TYPE_GL_EFFECTS,GstGLEffectsClass))
+
+#define GST_CAT_DEFAULT gst_gl_effects_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+#define DEBUG_INIT \
+  GST_DEBUG_CATEGORY_INIT (gst_gl_effects_debug, "gleffects", 0, "gleffects element");
+
+G_DEFINE_TYPE_WITH_CODE (GstGLEffects, gst_gl_effects, GST_TYPE_GL_FILTER,
+    DEBUG_INIT);
+
+static void gst_gl_effects_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_gl_effects_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static void gst_gl_effects_init_resources (GstGLFilter * filter);
+static void gst_gl_effects_reset_resources (GstGLFilter * filter);
+
+static gboolean gst_gl_effects_on_init_gl_context (GstGLFilter * filter);
+
+static void gst_gl_effects_ghash_func_clean (gpointer key, gpointer value,
+    gpointer data);
+
+static gboolean gst_gl_effects_filter_texture (GstGLFilter * filter,
+    guint in_tex, guint out_tex);
+
+/* dont' forget to edit the following when a new effect is added */
+typedef enum
+{
+  GST_GL_EFFECT_IDENTITY,
+  GST_GL_EFFECT_MIRROR,
+  GST_GL_EFFECT_SQUEEZE,
+  GST_GL_EFFECT_STRETCH,
+  GST_GL_EFFECT_TUNNEL,
+  GST_GL_EFFECT_FISHEYE,
+  GST_GL_EFFECT_TWIRL,
+  GST_GL_EFFECT_BULGE,
+  GST_GL_EFFECT_SQUARE,
+  GST_GL_EFFECT_HEAT,
+  GST_GL_EFFECT_SEPIA,
+  GST_GL_EFFECT_XPRO,
+  GST_GL_EFFECT_LUMA_XPRO,
+  GST_GL_EFFECT_XRAY,
+  GST_GL_EFFECT_SIN,
+  GST_GL_EFFECT_GLOW,
+  GST_GL_N_EFFECTS
+} GstGLEffectsEffect;
+
+#define GST_TYPE_GL_EFFECTS_EFFECT (gst_gl_effects_effect_get_type ())
+static GType
+gst_gl_effects_effect_get_type (void)
+{
+  static GType gl_effects_effect_type = 0;
+  static const GEnumValue effect_types[] = {
+    {GST_GL_EFFECT_IDENTITY, "Do nothing Effect", "identity"},
+    {GST_GL_EFFECT_MIRROR, "Mirror Effect", "mirror"},
+    {GST_GL_EFFECT_SQUEEZE, "Squeeze Effect", "squeeze"},
+#if GST_GL_HAVE_OPENGL
+    {GST_GL_EFFECT_STRETCH, "Stretch Effect", "stretch"},
+    {GST_GL_EFFECT_FISHEYE, "FishEye Effect", "fisheye"},
+    {GST_GL_EFFECT_TWIRL, "Twirl Effect", "twirl"},
+    {GST_GL_EFFECT_BULGE, "Bulge Effect", "bulge"},
+    {GST_GL_EFFECT_TUNNEL, "Light Tunnel Effect", "tunnel"},
+    {GST_GL_EFFECT_SQUARE, "Square Effect", "square"},
+    {GST_GL_EFFECT_HEAT, "Heat Signature Effect", "heat"},
+    {GST_GL_EFFECT_SEPIA, "Sepia Toning Effect", "sepia"},
+    {GST_GL_EFFECT_XPRO, "Cross Processing Effect", "xpro"},
+    {GST_GL_EFFECT_LUMA_XPRO, "Luma Cross Processing Effect", "lumaxpro"},
+    {GST_GL_EFFECT_XRAY, "Glowing negative effect", "xray"},
+    {GST_GL_EFFECT_SIN, "All Grey but Red Effect", "sin"},
+    {GST_GL_EFFECT_GLOW, "Glow Lighting Effect", "glow"},
+#endif
+    {0, NULL, NULL}
+  };
+
+  if (!gl_effects_effect_type) {
+    gl_effects_effect_type =
+        g_enum_register_static ("GstGLEffectsEffect", effect_types);
+  }
+  return gl_effects_effect_type;
+}
+
+static void
+gst_gl_effects_set_effect (GstGLEffects * effects, gint effect_type)
+{
+
+  switch (effect_type) {
+    case GST_GL_EFFECT_IDENTITY:
+      effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_identity;
+      break;
+    case GST_GL_EFFECT_MIRROR:
+      effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_mirror;
+      break;
+    case GST_GL_EFFECT_SQUEEZE:
+      effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_squeeze;
+      break;
+#if GST_GL_HAVE_OPENGL
+    case GST_GL_EFFECT_STRETCH:
+      effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_stretch;
+      break;
+    case GST_GL_EFFECT_TUNNEL:
+      effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_tunnel;
+      break;
+    case GST_GL_EFFECT_FISHEYE:
+      effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_fisheye;
+      break;
+    case GST_GL_EFFECT_TWIRL:
+      effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_twirl;
+      break;
+    case GST_GL_EFFECT_BULGE:
+      effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_bulge;
+      break;
+    case GST_GL_EFFECT_SQUARE:
+      effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_square;
+      break;
+    case GST_GL_EFFECT_HEAT:
+      effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_heat;
+      break;
+    case GST_GL_EFFECT_SEPIA:
+      effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_sepia;
+      break;
+    case GST_GL_EFFECT_XPRO:
+      effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_xpro;
+      break;
+    case GST_GL_EFFECT_LUMA_XPRO:
+      effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_luma_xpro;
+      break;
+    case GST_GL_EFFECT_XRAY:
+      effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_xray;
+      break;
+    case GST_GL_EFFECT_SIN:
+      effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_sin;
+      break;
+    case GST_GL_EFFECT_GLOW:
+      effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_glow;
+      break;
+#endif
+    default:
+      g_assert_not_reached ();
+  }
+  effects->current_effect = effect_type;
+}
+
+/* init resources that need a gl context */
+static void
+gst_gl_effects_init_gl_resources (GstGLFilter * filter)
+{
+  GstGLEffects *effects = GST_GL_EFFECTS (filter);
+  gint i;
+
+  for (i = 0; i < NEEDED_TEXTURES; i++) {
+    glGenTextures (1, &effects->midtexture[i]);
+    glBindTexture (GL_TEXTURE_2D, effects->midtexture[i]);
+    glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8,
+        GST_VIDEO_INFO_WIDTH (&filter->out_info),
+        GST_VIDEO_INFO_HEIGHT (&filter->out_info),
+        0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+  }
+}
+
+/* free resources that need a gl context */
+static void
+gst_gl_effects_reset_gl_resources (GstGLFilter * filter)
+{
+  GstGLEffects *effects = GST_GL_EFFECTS (filter);
+  gint i;
+
+  for (i = 0; i < NEEDED_TEXTURES; i++) {
+    glDeleteTextures (1, &effects->midtexture[i]);
+    effects->midtexture[i] = 0;
+  }
+  for (i = 0; i < GST_GL_EFFECTS_N_CURVES; i++) {
+    glDeleteTextures (1, &effects->curve[i]);
+    effects->curve[i] = 0;
+  }
+}
+
+static void
+gst_gl_effects_class_init (GstGLEffectsClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *element_class;
+
+  gobject_class = (GObjectClass *) klass;
+  element_class = GST_ELEMENT_CLASS (klass);
+
+  gobject_class->set_property = gst_gl_effects_set_property;
+  gobject_class->get_property = gst_gl_effects_get_property;
+
+  GST_GL_FILTER_CLASS (klass)->filter_texture = gst_gl_effects_filter_texture;
+  GST_GL_FILTER_CLASS (klass)->display_init_cb =
+      gst_gl_effects_init_gl_resources;
+  GST_GL_FILTER_CLASS (klass)->display_reset_cb =
+      gst_gl_effects_reset_gl_resources;
+  GST_GL_FILTER_CLASS (klass)->onStart = gst_gl_effects_init_resources;
+  GST_GL_FILTER_CLASS (klass)->onStop = gst_gl_effects_reset_resources;
+  GST_GL_FILTER_CLASS (klass)->onInitFBO = gst_gl_effects_on_init_gl_context;
+
+  g_object_class_install_property (gobject_class,
+      PROP_EFFECT,
+      g_param_spec_enum ("effect",
+          "Effect",
+          "Select which effect apply to GL video texture",
+          GST_TYPE_GL_EFFECTS_EFFECT,
+          GST_GL_EFFECT_IDENTITY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+      PROP_HSWAP,
+      g_param_spec_boolean ("hswap",
+          "Horizontal Swap",
+          "Switch video texture left to right, useful with webcams",
+          FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_metadata (element_class,
+      "Gstreamer OpenGL Effects", "Filter/Effect/Video",
+      "GL Shading Language effects",
+      "Filippo Argiolas <filippo.argiolas@gmail.com>");
+}
+
+static void
+set_horizontal_swap (GstGLContext * context, gpointer data)
+{
+#if GST_GL_HAVE_OPENGL
+  GstGLFuncs *gl = context->gl_vtable;
+
+  if (gst_gl_context_get_gl_api (context) & GST_GL_API_OPENGL) {
+    const gfloat mirrormatrix[16] = {
+      -1.0, 0.0, 0.0, 0.0,
+      0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0
+    };
+
+    gl->MatrixMode (GL_MODELVIEW);
+    gl->LoadMatrixf (mirrormatrix);
+  }
+#endif
+}
+
+static void
+gst_gl_effects_init (GstGLEffects * effects)
+{
+  effects->effect = gst_gl_effects_identity;
+  effects->horizontal_swap = FALSE;
+}
+
+static void
+gst_gl_effects_ghash_func_clean (gpointer key, gpointer value, gpointer data)
+{
+  GstGLShader *shader = (GstGLShader *) value;
+  GstGLFilter *filter = (GstGLFilter *) data;
+
+  //blocking call, wait the opengl thread has destroyed the shader
+  gst_gl_context_del_shader (filter->context, shader);
+
+  value = NULL;
+}
+
+static void
+gst_gl_effects_reset_resources (GstGLFilter * filter)
+{
+  GstGLEffects *effects = GST_GL_EFFECTS (filter);
+
+  /* release shaders in the gl thread */
+  g_hash_table_foreach (effects->shaderstable, gst_gl_effects_ghash_func_clean,
+      filter);
+
+  /* clean the htable without calling values destructors
+   * because shaders have been released in the glthread
+   * through the foreach func */
+  g_hash_table_unref (effects->shaderstable);
+  effects->shaderstable = NULL;
+}
+
+static void
+gst_gl_effects_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstGLEffects *effects = GST_GL_EFFECTS (object);
+
+  switch (prop_id) {
+    case PROP_EFFECT:
+      gst_gl_effects_set_effect (effects, g_value_get_enum (value));
+      break;
+    case PROP_HSWAP:
+      effects->horizontal_swap = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_gl_effects_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstGLEffects *effects = GST_GL_EFFECTS (object);
+
+  switch (prop_id) {
+    case PROP_EFFECT:
+      g_value_set_enum (value, effects->current_effect);
+      break;
+    case PROP_HSWAP:
+      g_value_set_boolean (value, effects->horizontal_swap);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_gl_effects_init_resources (GstGLFilter * filter)
+{
+  GstGLEffects *effects = GST_GL_EFFECTS (filter);
+  gint i;
+
+  effects->shaderstable = g_hash_table_new (g_str_hash, g_str_equal);
+
+  for (i = 0; i < NEEDED_TEXTURES; i++) {
+    effects->midtexture[i] = 0;
+  }
+  for (i = 0; i < GST_GL_EFFECTS_N_CURVES; i++) {
+    effects->curve[i] = 0;
+  }
+}
+
+static gboolean
+gst_gl_effects_on_init_gl_context (GstGLFilter * filter)
+{
+  return TRUE;
+}
+
+static gboolean
+gst_gl_effects_filter_texture (GstGLFilter * filter, guint in_tex,
+    guint out_tex)
+{
+  GstGLEffects *effects = GST_GL_EFFECTS (filter);
+
+  effects->intexture = in_tex;
+  effects->outtexture = out_tex;
+
+  if (effects->horizontal_swap == TRUE)
+    gst_gl_context_thread_add (filter->context, set_horizontal_swap, effects);
+
+  effects->effect (effects);
+
+  return TRUE;
+}
diff --git a/ext/gl/gstgleffects.h b/ext/gl/gstgleffects.h
new file mode 100644 (file)
index 0000000..71bec25
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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.
+ */
+
+#ifndef __GST_GL_EFFECTS_H__
+#define __GST_GL_EFFECTS_H__
+
+#include <gst/gl/gstglfilter.h>
+#include "effects/gstgleffectssources.h"
+
+G_BEGIN_DECLS
+
+
+#define GST_TYPE_GL_EFFECTS            (gst_gl_effects_get_type())
+#define GST_GL_EFFECTS(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_GL_EFFECTS,GstGLEffects))
+#define GST_IS_GL_EFFECTS(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_GL_EFFECTS))
+#define GST_GL_EFFECTS_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) , GST_TYPE_GL_EFFECTS,GstGLEffectsClass))
+#define GST_IS_GL_EFFECTS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) , GST_TYPE_GL_EFFECTS))
+#define GST_GL_EFFECTS_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) , GST_TYPE_GL_EFFECTS,GstGLEffectsClass))
+
+typedef struct _GstGLEffects GstGLEffects;
+typedef struct _GstGLEffectsClass GstGLEffectsClass;
+
+typedef void (* GstGLEffectProcessFunc) (GstGLEffects *effects);
+
+#define NEEDED_TEXTURES 5
+
+enum {
+  GST_GL_EFFECTS_CURVE_HEAT,
+  GST_GL_EFFECTS_CURVE_SEPIA,
+  GST_GL_EFFECTS_CURVE_XPRO,
+  GST_GL_EFFECTS_CURVE_LUMA_XPRO,
+  GST_GL_EFFECTS_CURVE_XRAY,
+  GST_GL_EFFECTS_N_CURVES
+};
+
+struct _GstGLEffects
+{
+  GstGLFilter filter;
+
+  GstGLEffectProcessFunc effect;
+  gint current_effect;
+
+  GLuint intexture;
+  GLuint midtexture[NEEDED_TEXTURES];
+  GLuint outtexture;
+
+  GLuint curve[GST_GL_EFFECTS_N_CURVES];
+
+  GHashTable *shaderstable;
+
+  gboolean horizontal_swap; /* switch left to right */
+};
+
+struct _GstGLEffectsClass
+{
+  GstGLFilterClass filter_class;
+};
+
+enum
+{
+  PROP_0,
+  PROP_EFFECT,
+  PROP_HSWAP
+};
+
+
+GType gst_gl_effects_get_type (void);
+
+void gst_gl_effects_identity (GstGLEffects *effects);
+void gst_gl_effects_mirror (GstGLEffects *effects);
+void gst_gl_effects_squeeze (GstGLEffects *effects);
+void gst_gl_effects_stretch (GstGLEffects *effects);
+void gst_gl_effects_tunnel (GstGLEffects *effects);
+void gst_gl_effects_fisheye (GstGLEffects *effects);
+void gst_gl_effects_twirl (GstGLEffects *effects);
+void gst_gl_effects_bulge (GstGLEffects *effects);
+void gst_gl_effects_square (GstGLEffects *effects);
+void gst_gl_effects_heat (GstGLEffects *effects);
+void gst_gl_effects_sepia (GstGLEffects *effects);
+void gst_gl_effects_xpro (GstGLEffects *effects);
+void gst_gl_effects_xray (GstGLEffects *effects);
+void gst_gl_effects_luma_xpro (GstGLEffects *effects);
+void gst_gl_effects_sin (GstGLEffects *effects);
+void gst_gl_effects_glow (GstGLEffects *effects);
+
+G_END_DECLS
+
+#endif /*__GST_GL_EFFECTS_H__ */
diff --git a/ext/gl/gstglfilterapp.c b/ext/gl/gstglfilterapp.c
new file mode 100644 (file)
index 0000000..ba60a46
--- /dev/null
@@ -0,0 +1,214 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.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.
+ */
+
+/**
+ * SECTION:element-glfilterapp
+ *
+ * The resize and redraw callbacks can be set from a client code.
+ *
+ * <refsect2>
+ * <title>CLient callbacks</title>
+ * <para>
+ * The graphic scene can be written from a client code through the 
+ * two glfilterapp properties.
+ * </para>
+ * </refsect2>
+ * <refsect2>
+ * <title>Examples</title>
+ * see gst-plugins-gl/tests/examples/generic/recordgraphic
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstglfilterapp.h"
+
+#define GST_CAT_DEFAULT gst_gl_filter_app_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+enum
+{
+  PROP_0,
+  PROP_CLIENT_RESHAPE_CALLBACK,
+  PROP_CLIENT_DRAW_CALLBACK,
+  PROP_CLIENT_DATA
+};
+
+#define DEBUG_INIT \
+  GST_DEBUG_CATEGORY_INIT (gst_gl_filter_app_debug, "glfilterapp", 0, "glfilterapp element");
+
+G_DEFINE_TYPE_WITH_CODE (GstGLFilterApp, gst_gl_filter_app,
+    GST_TYPE_GL_FILTER, DEBUG_INIT);
+
+static void gst_gl_filter_app_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_gl_filter_app_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_gl_filter_app_set_caps (GstGLFilter * filter,
+    GstCaps * incaps, GstCaps * outcaps);
+static gboolean gst_gl_filter_app_filter_texture (GstGLFilter * filter,
+    guint in_tex, guint out_tex);
+static void gst_gl_filter_app_callback (gint width, gint height, guint texture,
+    gpointer stuff);
+
+
+static void
+gst_gl_filter_app_class_init (GstGLFilterAppClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *element_class;
+
+  gobject_class = (GObjectClass *) klass;
+  element_class = GST_ELEMENT_CLASS (klass);
+
+  gobject_class->set_property = gst_gl_filter_app_set_property;
+  gobject_class->get_property = gst_gl_filter_app_get_property;
+
+  GST_GL_FILTER_CLASS (klass)->set_caps = gst_gl_filter_app_set_caps;
+  GST_GL_FILTER_CLASS (klass)->filter_texture =
+      gst_gl_filter_app_filter_texture;
+
+  g_object_class_install_property (gobject_class, PROP_CLIENT_RESHAPE_CALLBACK,
+      g_param_spec_pointer ("client-reshape-callback",
+          "Client reshape callback",
+          "Define a custom reshape callback in a client code",
+          G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_CLIENT_DRAW_CALLBACK,
+      g_param_spec_pointer ("client-draw-callback", "Client draw callback",
+          "Define a custom draw callback in a client code",
+          G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_CLIENT_DATA,
+      g_param_spec_pointer ("client-data", "Client data",
+          "Pass data to the draw and reshape callbacks",
+          G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_metadata (element_class,
+      "OpenGL application filter", "Filter/Effect",
+      "Use client callbacks to define the scene",
+      "Julien Isorce <julien.isorce@gmail.com>");
+}
+
+static void
+gst_gl_filter_app_init (GstGLFilterApp * filter)
+{
+  filter->clientReshapeCallback = NULL;
+  filter->clientDrawCallback = NULL;
+  filter->client_data = NULL;
+}
+
+static void
+gst_gl_filter_app_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstGLFilterApp *filter = GST_GL_FILTER_APP (object);
+
+  switch (prop_id) {
+    case PROP_CLIENT_RESHAPE_CALLBACK:
+    {
+      filter->clientReshapeCallback = g_value_get_pointer (value);
+      break;
+    }
+    case PROP_CLIENT_DRAW_CALLBACK:
+    {
+      filter->clientDrawCallback = g_value_get_pointer (value);
+      break;
+    }
+    case PROP_CLIENT_DATA:
+    {
+      filter->client_data = g_value_get_pointer (value);
+      break;
+    }
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_gl_filter_app_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  //GstGLFilterApp* filter = GST_GL_FILTER_APP (object);
+
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_gl_filter_app_set_caps (GstGLFilter * filter, GstCaps * incaps,
+    GstCaps * outcaps)
+{
+  //GstGLFilterApp* app_filter = GST_GL_FILTER_APP(filter);
+
+  return TRUE;
+}
+
+static gboolean
+gst_gl_filter_app_filter_texture (GstGLFilter * filter, guint in_tex,
+    guint out_tex)
+{
+  GstGLFilterApp *app_filter = GST_GL_FILTER_APP (filter);
+
+  if (app_filter->clientDrawCallback) {
+    //blocking call, use a FBO
+    gst_gl_context_use_fbo (filter->context,
+        GST_VIDEO_INFO_WIDTH (&filter->out_info),
+        GST_VIDEO_INFO_HEIGHT (&filter->out_info),
+        filter->fbo, filter->depthbuffer, out_tex,
+        app_filter->clientDrawCallback,
+        GST_VIDEO_INFO_WIDTH (&filter->in_info),
+        GST_VIDEO_INFO_HEIGHT (&filter->in_info),
+        in_tex, 45,
+        (gfloat) GST_VIDEO_INFO_WIDTH (&filter->out_info) /
+        (gfloat) GST_VIDEO_INFO_HEIGHT (&filter->out_info),
+        0.1, 100, GST_GL_DISPLAY_PROJECTION_PERSPECTIVE,
+        app_filter->client_data);
+  }
+  //default
+  else {
+    //blocking call, use a FBO
+    gst_gl_filter_render_to_target (filter, TRUE, in_tex, out_tex,
+        gst_gl_filter_app_callback, filter);
+  }
+
+  return TRUE;
+}
+
+//opengl scene, params: input texture (not the output filter->texture)
+static void
+gst_gl_filter_app_callback (gint width, gint height, guint texture,
+    gpointer stuff)
+{
+  GstGLFilter *filter = GST_GL_FILTER (stuff);
+  GstGLFuncs *gl = filter->context->gl_vtable;
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
diff --git a/ext/gl/gstglfilterapp.h b/ext/gl/gstglfilterapp.h
new file mode 100644 (file)
index 0000000..f582ae3
--- /dev/null
@@ -0,0 +1,55 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.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.
+ */
+
+#ifndef _GST_GL_FILTERAPP_H_
+#define _GST_GL_FILTERAPP_H_
+
+#include <gst/gl/gstglfilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_GL_FILTER_APP            (gst_gl_filter_app_get_type())
+#define GST_GL_FILTER_APP(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_FILTER_APP,GstGLFilterApp))
+#define GST_IS_GL_FILTER_APP(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_FILTER_APP))
+#define GST_GL_FILTER_APP_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_FILTER_APP,GstGLFilterAppClass))
+#define GST_IS_GL_FILTER_APP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_FILTER_APP))
+#define GST_GL_FILTER_APP_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_FILTER_APP,GstGLFilterAppClass))
+typedef struct _GstGLFilterApp GstGLFilterApp;
+typedef struct _GstGLFilterAppClass GstGLFilterAppClass;
+
+struct _GstGLFilterApp
+{
+    GstGLFilter filter;
+
+    CRCB clientReshapeCallback;
+    GLCB clientDrawCallback;
+    gpointer client_data;
+};
+
+struct _GstGLFilterAppClass
+{
+    GstGLFilterClass filter_class;
+};
+
+GType gst_gl_glfilterapp_get_type (void);
+
+G_END_DECLS
+
+#endif /* _GST_GLFILTERAPP_H_ */
diff --git a/ext/gl/gstglfilterblur.c b/ext/gl/gstglfilterblur.c
new file mode 100644 (file)
index 0000000..fd275ec
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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.
+ */
+
+/**
+ * SECTION:element-glfilterblur
+ *
+ * Blur with 9x9 separable convolution.
+ *
+ * <refsect2>
+ * <title>Examples</title>
+ * |[
+ * gst-launch videotestsrc ! glupload ! glfilterblur ! glimagesink
+ * ]|
+ * FBO (Frame Buffer Object) and GLSL (OpenGL Shading Language) are required.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstglfilterblur.h"
+#include "effects/gstgleffectssources.h"
+
+#define GST_CAT_DEFAULT gst_gl_filterblur_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+#define DEBUG_INIT \
+  GST_DEBUG_CATEGORY_INIT (gst_gl_filterblur_debug, "glfilterblur", 0, "glfilterblur element");
+
+G_DEFINE_TYPE_WITH_CODE (GstGLFilterBlur, gst_gl_filterblur,
+    GST_TYPE_GL_FILTER, DEBUG_INIT);
+
+static void gst_gl_filterblur_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_gl_filterblur_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_gl_filter_filterblur_reset (GstGLFilter * filter);
+
+static gboolean gst_gl_filterblur_init_shader (GstGLFilter * filter);
+static gboolean gst_gl_filterblur_filter_texture (GstGLFilter * filter,
+    guint in_tex, guint out_tex);
+static void gst_gl_filterblur_hcallback (gint width, gint height, guint texture,
+    gpointer stuff);
+static void gst_gl_filterblur_vcallback (gint width, gint height, guint texture,
+    gpointer stuff);
+
+
+static void
+gst_gl_filterblur_init_resources (GstGLFilter * filter)
+{
+  GstGLFilterBlur *filterblur = GST_GL_FILTERBLUR (filter);
+  GstGLFuncs *gl = filter->context->gl_vtable;
+
+  gl->GenTextures (1, &filterblur->midtexture);
+  gl->BindTexture (GL_TEXTURE_2D, filterblur->midtexture);
+  gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8,
+      GST_VIDEO_INFO_WIDTH (&filter->out_info),
+      GST_VIDEO_INFO_HEIGHT (&filter->out_info),
+      0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+  gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+  gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+  gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+  gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+}
+
+static void
+gst_gl_filterblur_reset_resources (GstGLFilter * filter)
+{
+  GstGLFilterBlur *filterblur = GST_GL_FILTERBLUR (filter);
+  GstGLFuncs *gl = filter->context->gl_vtable;
+
+  gl->DeleteTextures (1, &filterblur->midtexture);
+}
+
+static void
+gst_gl_filterblur_class_init (GstGLFilterBlurClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *element_class;
+
+  gobject_class = (GObjectClass *) klass;
+  element_class = GST_ELEMENT_CLASS (klass);
+
+  gobject_class->set_property = gst_gl_filterblur_set_property;
+  gobject_class->get_property = gst_gl_filterblur_get_property;
+
+  gst_element_class_set_metadata (element_class, "Gstreamer OpenGL Blur",
+      "Filter/Effect/Video", "Blur with 9x9 separable convolution",
+      "Filippo Argiolas <filippo.argiolas@gmail.com>");
+
+  GST_GL_FILTER_CLASS (klass)->filter_texture =
+      gst_gl_filterblur_filter_texture;
+  GST_GL_FILTER_CLASS (klass)->display_init_cb =
+      gst_gl_filterblur_init_resources;
+  GST_GL_FILTER_CLASS (klass)->display_reset_cb =
+      gst_gl_filterblur_reset_resources;
+  GST_GL_FILTER_CLASS (klass)->onInitFBO = gst_gl_filterblur_init_shader;
+  GST_GL_FILTER_CLASS (klass)->onReset = gst_gl_filter_filterblur_reset;
+}
+
+static void
+gst_gl_filterblur_init (GstGLFilterBlur * filterblur)
+{
+  filterblur->shader0 = NULL;
+  filterblur->shader1 = NULL;
+  filterblur->midtexture = 0;
+  /* gaussian kernel (well, actually vector), size 9, standard
+   * deviation 3.0 */
+  /* FIXME: eventually make this a runtime property */
+  fill_gaussian_kernel (filterblur->gauss_kernel, 7, 3.0);
+}
+
+static void
+gst_gl_filter_filterblur_reset (GstGLFilter * filter)
+{
+  GstGLFilterBlur *filterblur = GST_GL_FILTERBLUR (filter);
+
+  //blocking call, wait the opengl thread has destroyed the shader
+  if (filterblur->shader0)
+    gst_gl_context_del_shader (filter->context, filterblur->shader0);
+  filterblur->shader0 = NULL;
+
+  //blocking call, wait the opengl thread has destroyed the shader
+  if (filterblur->shader1)
+    gst_gl_context_del_shader (filter->context, filterblur->shader1);
+  filterblur->shader1 = NULL;
+}
+
+static void
+gst_gl_filterblur_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  /* GstGLFilterBlur *filterblur = GST_GL_FILTERBLUR (object); */
+
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_gl_filterblur_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  /* GstGLFilterBlur *filterblur = GST_GL_FILTERBLUR (object); */
+
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_gl_filterblur_init_shader (GstGLFilter * filter)
+{
+  GstGLFilterBlur *blur_filter = GST_GL_FILTERBLUR (filter);
+
+  //blocking call, wait the opengl thread has compiled the shader
+  if (!gst_gl_context_gen_shader (filter->context, 0, hconv7_fragment_source,
+          &blur_filter->shader0))
+    return FALSE;
+
+  //blocking call, wait the opengl thread has compiled the shader
+  if (!gst_gl_context_gen_shader (filter->context, 0, vconv7_fragment_source,
+          &blur_filter->shader1))
+    return FALSE;
+
+  return TRUE;
+}
+
+static gboolean
+gst_gl_filterblur_filter_texture (GstGLFilter * filter, guint in_tex,
+    guint out_tex)
+{
+  GstGLFilterBlur *filterblur = GST_GL_FILTERBLUR (filter);
+
+  gst_gl_filter_render_to_target (filter, TRUE, in_tex,
+      filterblur->midtexture, gst_gl_filterblur_hcallback, filterblur);
+
+  gst_gl_filter_render_to_target (filter, FALSE, filterblur->midtexture,
+      out_tex, gst_gl_filterblur_vcallback, filterblur);
+
+  return TRUE;
+}
+
+static void
+gst_gl_filterblur_hcallback (gint width, gint height, guint texture,
+    gpointer stuff)
+{
+  GstGLFilter *filter = GST_GL_FILTER (stuff);
+  GstGLFilterBlur *filterblur = GST_GL_FILTERBLUR (filter);
+  GstGLFuncs *gl = filter->context->gl_vtable;
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+
+  gst_gl_shader_use (filterblur->shader0);
+
+  gl->ActiveTexture (GL_TEXTURE1);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+  gl->Disable (GL_TEXTURE_2D);
+
+  gst_gl_shader_set_uniform_1i (filterblur->shader0, "tex", 1);
+  gst_gl_shader_set_uniform_1fv (filterblur->shader0, "kernel", 7,
+      filterblur->gauss_kernel);
+  gst_gl_shader_set_uniform_1f (filterblur->shader0, "width", width);
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
+
+
+static void
+gst_gl_filterblur_vcallback (gint width, gint height, guint texture,
+    gpointer stuff)
+{
+  GstGLFilter *filter = GST_GL_FILTER (stuff);
+  GstGLFilterBlur *filterblur = GST_GL_FILTERBLUR (filter);
+  GstGLFuncs *gl = filter->context->gl_vtable;
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+
+  gst_gl_shader_use (filterblur->shader1);
+
+  gl->ActiveTexture (GL_TEXTURE1);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+  gl->Disable (GL_TEXTURE_2D);
+
+  gst_gl_shader_set_uniform_1i (filterblur->shader1, "tex", 1);
+  gst_gl_shader_set_uniform_1fv (filterblur->shader1, "kernel", 7,
+      filterblur->gauss_kernel);
+  gst_gl_shader_set_uniform_1f (filterblur->shader1, "height", height);
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
diff --git a/ext/gl/gstglfilterblur.h b/ext/gl/gstglfilterblur.h
new file mode 100644 (file)
index 0000000..5561cb5
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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.
+ */
+
+#ifndef _GST_GL_FILTERBLUR_H_
+#define _GST_GL_FILTERBLUR_H_
+
+#include <gst/gl/gstglfilter.h>
+
+#define GST_TYPE_GL_FILTERBLUR            (gst_gl_filterblur_get_type())
+#define GST_GL_FILTERBLUR(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_FILTERBLUR,GstGLFilterBlur))
+#define GST_IS_GL_FILTERBLUR(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_FILTERBLUR))
+#define GST_GL_FILTERBLUR_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_FILTERBLUR,GstGLFilterBlurClass))
+#define GST_IS_GL_FILTERBLUR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_FILTERBLUR))
+#define GST_GL_FILTERBLUR_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_FILTERBLUR,GstGLFilterBlurClass))
+
+typedef struct _GstGLFilterBlur GstGLFilterBlur;
+typedef struct _GstGLFilterBlurClass GstGLFilterBlurClass;
+
+struct _GstGLFilterBlur
+{
+  GstGLFilter filter;
+  GstGLShader *shader0;
+  GstGLShader *shader1;
+
+  GLuint midtexture;
+  float gauss_kernel[7];
+};
+
+struct _GstGLFilterBlurClass
+{
+  GstGLFilterClass filter_class;
+};
+
+GType gst_gl_glfilterblur_get_type (void);
+
+#endif /* _GST_GL_FILTERBLUR_H_ */
diff --git a/ext/gl/gstglfiltercube.c b/ext/gl/gstglfiltercube.c
new file mode 100644 (file)
index 0000000..35bf677
--- /dev/null
@@ -0,0 +1,561 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.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.
+ */
+
+/**
+ * SECTION:element-glfiltercube
+ *
+ * The resize and redraw callbacks can be set from a client code.
+ *
+ * <refsect2>
+ * <title>Examples</title>
+ * |[
+ * gst-launch -v videotestsrc ! glupload ! glfiltercube ! glimagesink
+ * ]| A pipeline to mpa textures on the 6 cube faces..
+ * FBO is required.
+ * |[
+ * gst-launch -v videotestsrc ! glupload ! glfiltercube ! video/x-raw-gl, width=640, height=480 ! glimagesink
+ * ]| Resize scene after drawing the cube.
+ * The scene size is greater than the input video size.
+  |[
+ * gst-launch -v videotestsrc ! glupload ! video/x-raw-gl, width=640, height=480  ! glfiltercube ! glimagesink
+ * ]| Resize scene before drawing the cube.
+ * The scene size is greater than the input video size.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gl/gstglapi.h>
+#include "gstglfiltercube.h"
+
+#define GST_CAT_DEFAULT gst_gl_filter_cube_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+enum
+{
+  PROP_0,
+  PROP_RED,
+  PROP_GREEN,
+  PROP_BLUE,
+  PROP_FOVY,
+  PROP_ASPECT,
+  PROP_ZNEAR,
+  PROP_ZFAR
+};
+
+#define DEBUG_INIT \
+    GST_DEBUG_CATEGORY_INIT (gst_gl_filter_cube_debug, "glfiltercube", 0, "glfiltercube element");
+
+G_DEFINE_TYPE_WITH_CODE (GstGLFilterCube, gst_gl_filter_cube,
+    GST_TYPE_GL_FILTER, DEBUG_INIT);
+
+static void gst_gl_filter_cube_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_gl_filter_cube_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_gl_filter_cube_set_caps (GstGLFilter * filter,
+    GstCaps * incaps, GstCaps * outcaps);
+#if GST_GL_HAVE_GLES2
+static void gst_gl_filter_cube_reset (GstGLFilter * filter);
+static gboolean gst_gl_filter_cube_init_shader (GstGLFilter * filter);
+static void _callback_gles2 (gint width, gint height, guint texture,
+    gpointer stuff);
+#endif
+#if GST_GL_HAVE_OPENGL
+static void _callback_opengl (gint width, gint height, guint texture,
+    gpointer stuff);
+#endif
+static gboolean gst_gl_filter_cube_filter_texture (GstGLFilter * filter,
+    guint in_tex, guint out_tex);
+
+#if GST_GL_HAVE_GLES2
+/* vertex source */
+static const gchar *cube_v_src =
+    "attribute vec4 a_position;                                   \n"
+    "attribute vec2 a_texCoord;                                   \n"
+    "uniform mat4 u_matrix;                                       \n"
+    "uniform float xrot_degree, yrot_degree, zrot_degree;         \n"
+    "varying vec2 v_texCoord;                                     \n"
+    "void main()                                                  \n"
+    "{                                                            \n"
+    "   float PI = 3.14159265;                                    \n"
+    "   float xrot = xrot_degree*2.0*PI/360.0;                    \n"
+    "   float yrot = yrot_degree*2.0*PI/360.0;                    \n"
+    "   float zrot = zrot_degree*2.0*PI/360.0;                    \n"
+    "   mat4 matX = mat4 (                                        \n"
+    "            1.0,        0.0,        0.0, 0.0,                \n"
+    "            0.0,  cos(xrot),  sin(xrot), 0.0,                \n"
+    "            0.0, -sin(xrot),  cos(xrot), 0.0,                \n"
+    "            0.0,        0.0,        0.0, 1.0 );              \n"
+    "   mat4 matY = mat4 (                                        \n"
+    "      cos(yrot),        0.0, -sin(yrot), 0.0,                \n"
+    "            0.0,        1.0,        0.0, 0.0,                \n"
+    "      sin(yrot),        0.0,  cos(yrot), 0.0,                \n"
+    "            0.0,        0.0,       0.0,  1.0 );              \n"
+    "   mat4 matZ = mat4 (                                        \n"
+    "      cos(zrot),  sin(zrot),        0.0, 0.0,                \n"
+    "     -sin(zrot),  cos(zrot),        0.0, 0.0,                \n"
+    "            0.0,        0.0,        1.0, 0.0,                \n"
+    "            0.0,        0.0,        0.0, 1.0 );              \n"
+    "   gl_Position = u_matrix * matZ * matY * matX * a_position; \n"
+    "   v_texCoord = a_texCoord;                                  \n"
+    "}                                                            \n";
+
+/* fragment source */
+static const gchar *cube_f_src =
+    "precision mediump float;                            \n"
+    "varying vec2 v_texCoord;                            \n"
+    "uniform sampler2D s_texture;                        \n"
+    "void main()                                         \n"
+    "{                                                   \n"
+    "  gl_FragColor = texture2D( s_texture, v_texCoord );\n"
+    "}                                                   \n";
+#endif
+
+static void
+gst_gl_filter_cube_class_init (GstGLFilterCubeClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *element_class;
+
+  gobject_class = (GObjectClass *) klass;
+  element_class = GST_ELEMENT_CLASS (klass);
+
+  gobject_class->set_property = gst_gl_filter_cube_set_property;
+  gobject_class->get_property = gst_gl_filter_cube_get_property;
+
+#if GST_GL_HAVE_GLES2
+  GST_GL_FILTER_CLASS (klass)->onInitFBO = gst_gl_filter_cube_init_shader;
+  GST_GL_FILTER_CLASS (klass)->onReset = gst_gl_filter_cube_reset;
+#endif
+  GST_GL_FILTER_CLASS (klass)->set_caps = gst_gl_filter_cube_set_caps;
+  GST_GL_FILTER_CLASS (klass)->filter_texture =
+      gst_gl_filter_cube_filter_texture;
+
+  g_object_class_install_property (gobject_class, PROP_RED,
+      g_param_spec_float ("red", "Red", "Background red color",
+          0.0f, 1.0f, 0.0f, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_GREEN,
+      g_param_spec_float ("green", "Green", "Background reen color",
+          0.0f, 1.0f, 0.0f, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_BLUE,
+      g_param_spec_float ("blue", "Blue", "Background blue color",
+          0.0f, 1.0f, 0.0f, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_FOVY,
+      g_param_spec_double ("fovy", "Fovy", "Field of view angle in degrees",
+          0.0, 180.0, 45.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_ASPECT,
+      g_param_spec_double ("aspect", "Aspect",
+          "Field of view in the x direction", 0.0, 100, 0.0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_ZNEAR,
+      g_param_spec_double ("znear", "Znear",
+          "Specifies the distance from the viewer to the near clipping plane",
+          0.0, 100.0, 0.1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_ZFAR,
+      g_param_spec_double ("zfar", "Zfar",
+          "Specifies the distance from the viewer to the far clipping plane",
+          0.0, 1000.0, 100.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_metadata (element_class, "OpenGL cube filter",
+      "Filter/Effect/Video", "Map input texture on the 6 cube faces",
+      "Julien Isorce <julien.isorce@gmail.com>");
+}
+
+static void
+gst_gl_filter_cube_init (GstGLFilterCube * filter)
+{
+  filter->shader = NULL;
+  filter->fovy = 45;
+  filter->aspect = 0;
+  filter->znear = 0.1;
+  filter->zfar = 100;
+}
+
+static void
+gst_gl_filter_cube_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstGLFilterCube *filter = GST_GL_FILTER_CUBE (object);
+
+  switch (prop_id) {
+    case PROP_RED:
+      filter->red = g_value_get_float (value);
+      break;
+    case PROP_GREEN:
+      filter->green = g_value_get_float (value);
+      break;
+    case PROP_BLUE:
+      filter->blue = g_value_get_float (value);
+      break;
+    case PROP_FOVY:
+      filter->fovy = g_value_get_double (value);
+      break;
+    case PROP_ASPECT:
+      filter->aspect = g_value_get_double (value);
+      break;
+    case PROP_ZNEAR:
+      filter->znear = g_value_get_double (value);
+      break;
+    case PROP_ZFAR:
+      filter->zfar = g_value_get_double (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_gl_filter_cube_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstGLFilterCube *filter = GST_GL_FILTER_CUBE (object);
+
+  switch (prop_id) {
+    case PROP_RED:
+      g_value_set_float (value, filter->red);
+      break;
+    case PROP_GREEN:
+      g_value_set_float (value, filter->green);
+      break;
+    case PROP_BLUE:
+      g_value_set_float (value, filter->blue);
+      break;
+    case PROP_FOVY:
+      g_value_set_double (value, filter->fovy);
+      break;
+    case PROP_ASPECT:
+      g_value_set_double (value, filter->aspect);
+      break;
+    case PROP_ZNEAR:
+      g_value_set_double (value, filter->znear);
+      break;
+    case PROP_ZFAR:
+      g_value_set_double (value, filter->zfar);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_gl_filter_cube_set_caps (GstGLFilter * filter, GstCaps * incaps,
+    GstCaps * outcaps)
+{
+  GstGLFilterCube *cube_filter = GST_GL_FILTER_CUBE (filter);
+
+  if (cube_filter->aspect == 0)
+    cube_filter->aspect = (gdouble) GST_VIDEO_INFO_WIDTH (&filter->out_info) /
+        (gdouble) GST_VIDEO_INFO_HEIGHT (&filter->out_info);
+
+  return TRUE;
+}
+
+#if GST_GL_HAVE_GLES2
+static void
+gst_gl_filter_cube_reset (GstGLFilter * filter)
+{
+  GstGLFilterCube *cube_filter = GST_GL_FILTER_CUBE (filter);
+
+  /* blocking call, wait the opengl thread has destroyed the shader */
+  if (cube_filter->shader)
+    gst_gl_context_del_shader (filter->context, cube_filter->shader);
+  cube_filter->shader = NULL;
+}
+
+static gboolean
+gst_gl_filter_cube_init_shader (GstGLFilter * filter)
+{
+  GstGLFilterCube *cube_filter = GST_GL_FILTER_CUBE (filter);
+
+  if (gst_gl_context_get_gl_api (filter->context) & GST_GL_API_GLES2) {
+    /* blocking call, wait the opengl thread has compiled the shader */
+    return gst_gl_context_gen_shader (filter->context, cube_v_src, cube_f_src,
+        &cube_filter->shader);
+  }
+  return TRUE;
+}
+#endif
+
+static gboolean
+gst_gl_filter_cube_filter_texture (GstGLFilter * filter, guint in_tex,
+    guint out_tex)
+{
+  GstGLFilterCube *cube_filter = GST_GL_FILTER_CUBE (filter);
+  GLCB cb = NULL;
+  GstGLAPI api;
+
+  api = gst_gl_context_get_gl_api (GST_GL_FILTER (cube_filter)->context);
+
+#if GST_GL_HAVE_OPENGL
+  if (api & GST_GL_API_OPENGL)
+    cb = _callback_opengl;
+#endif
+#if GST_GL_HAVE_GLES2
+  if (api & GST_GL_API_GLES2)
+    cb = _callback_gles2;
+#endif
+
+  /* blocking call, use a FBO */
+  gst_gl_context_use_fbo (filter->context,
+      GST_VIDEO_INFO_WIDTH (&filter->out_info),
+      GST_VIDEO_INFO_HEIGHT (&filter->out_info),
+      filter->fbo, filter->depthbuffer, out_tex,
+      cb,
+      GST_VIDEO_INFO_WIDTH (&filter->in_info),
+      GST_VIDEO_INFO_HEIGHT (&filter->in_info),
+      in_tex, cube_filter->fovy, cube_filter->aspect,
+      cube_filter->znear, cube_filter->zfar,
+      GST_GL_DISPLAY_PROJECTION_PERSPECTIVE, (gpointer) cube_filter);
+
+  return TRUE;
+}
+
+/* opengl scene, params: input texture (not the output filter->texture) */
+#if GST_GL_HAVE_OPENGL
+static void
+_callback_opengl (gint width, gint height, guint texture, gpointer stuff)
+{
+  GstGLFilterCube *cube_filter = GST_GL_FILTER_CUBE (stuff);
+  GstGLFilter *filter = GST_GL_FILTER (stuff);
+  GstGLFuncs *gl = filter->context->gl_vtable;
+
+  static GLfloat xrot = 0;
+  static GLfloat yrot = 0;
+  static GLfloat zrot = 0;
+
+/* *INDENT-OFF* */
+  const GLfloat v_vertices[] = {
+ /*|     Vertex     | TexCoord |*/ 
+    /* front face */
+     1.0,  1.0, -1.0, 0.0, 0.0,
+     1.0, -1.0, -1.0, 1.0, 0.0,
+    -1.0, -1.0, -1.0, 1.0, 1.0,
+    -1.0,  1.0, -1.0, 0.0, 1.0,
+    /* back face */
+    -1.0,  1.0,  1.0, 0.0, 0.0,
+    -1.0, -1.0,  1.0, 1.0, 0.0,
+     1.0, -1.0,  1.0, 1.0, 1.0,
+     1.0,  1.0,  1.0, 0.0, 1.0,
+    /* right face */
+    -1.0,  1.0, -1.0, 0.0, 0.0,
+    -1.0, -1.0, -1.0, 1.0, 0.0,
+    -1.0, -1.0,  1.0, 1.0, 1.0,
+    -1.0,  1.0,  1.0, 0.0, 1.0,
+    /* left face */
+     1.0,  1.0,  1.0, 0.0, 0.0,
+     1.0, -1.0,  1.0, 1.0, 0.0,
+     1.0, -1.0, -1.0, 1.0, 1.0,
+     1.0,  1.0, -1.0, 0.0, 1.0,
+    /* top face */
+     1.0,  1.0,  1.0, 0.0, 0.0,
+     1.0,  1.0, -1.0, 1.0, 0.0,
+    -1.0,  1.0, -1.0, 1.0, 1.0,
+    -1.0,  1.0,  1.0, 0.0, 1.0,
+    /* bottom face */
+     1.0, -1.0,  1.0, 0.0, 0.0,
+     1.0, -1.0, -1.0, 1.0, 0.0,
+    -1.0, -1.0, -1.0, 1.0, 1.0,
+    -1.0, -1.0,  1.0, 0.0, 1.0,
+  };
+/* *INDENT-ON* */
+
+  GLushort indices[] = {
+    0, 1, 2,
+    0, 2, 3,
+    4, 5, 6,
+    4, 6, 7,
+    8, 9, 10,
+    8, 10, 11,
+    12, 13, 14,
+    12, 14, 15,
+    16, 17, 18,
+    16, 18, 19,
+    20, 21, 22,
+    20, 22, 23
+  };
+
+  gl->Enable (GL_DEPTH_TEST);
+
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+
+  gl->ClearColor (cube_filter->red, cube_filter->green, cube_filter->blue, 0.0);
+  gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+  gl->MatrixMode (GL_PROJECTION);
+  gluLookAt (0.0, 0.0, -6.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
+  gl->MatrixMode (GL_MODELVIEW);
+  gl->LoadIdentity ();
+
+//  gl->Translatef (0.0f, 0.0f, -5.0f);
+
+  gl->Rotatef (xrot, 1.0f, 0.0f, 0.0f);
+  gl->Rotatef (yrot, 0.0f, 1.0f, 0.0f);
+  gl->Rotatef (zrot, 0.0f, 0.0f, 1.0f);
+
+  gl->ClientActiveTexture (GL_TEXTURE0);
+  gl->EnableClientState (GL_TEXTURE_COORD_ARRAY);
+  gl->EnableClientState (GL_VERTEX_ARRAY);
+
+  gl->VertexPointer (3, GL_FLOAT, 5 * sizeof (float), v_vertices);
+  gl->TexCoordPointer (2, GL_FLOAT, 5 * sizeof (float), &v_vertices[3]);
+
+  gl->DrawElements (GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, indices);
+
+  gl->DisableClientState (GL_TEXTURE_COORD_ARRAY);
+  gl->DisableClientState (GL_VERTEX_ARRAY);
+
+  gl->Disable (GL_DEPTH_TEST);
+
+  xrot += 0.3f;
+  yrot += 0.2f;
+  zrot += 0.4f;
+}
+#endif
+
+#if GST_GL_HAVE_GLES2
+static void
+_callback_gles2 (gint width, gint height, guint texture, gpointer stuff)
+{
+  GstGLFilter *filter = GST_GL_FILTER (stuff);
+  GstGLFilterCube *cube_filter = GST_GL_FILTER_CUBE (filter);
+  GstGLFuncs *gl = filter->context->gl_vtable;
+
+  static GLfloat xrot = 0;
+  static GLfloat yrot = 0;
+  static GLfloat zrot = 0;
+
+/* *INDENT-OFF* */
+  const GLfloat v_vertices[] = {
+ /*|     Vertex     | TexCoord |*/ 
+    /* front face */
+     1.0,  1.0, -1.0, 1.0, 0.0,
+     1.0, -1.0, -1.0, 1.0, 1.0,
+    -1.0, -1.0, -1.0, 0.0, 1.0,
+    -1.0,  1.0, -1.0, 0.0, 0.0,
+    /* back face */
+     1.0,  1.0,  1.0, 1.0, 0.0,
+    -1.0,  1.0,  1.0, 0.0, 0.0,
+    -1.0, -1.0,  1.0, 0.0, 1.0,
+     1.0, -1.0,  1.0, 1.0, 1.0,
+    /* right face */
+     1.0,  1.0,  1.0, 1.0, 0.0,
+     1.0, -1.0,  1.0, 0.0, 0.0,
+     1.0, -1.0, -1.0, 0.0, 1.0,
+     1.0,  1.0, -1.0, 1.0, 1.0,
+    /* left face */
+    -1.0,  1.0,  1.0, 1.0, 0.0,
+    -1.0,  1.0, -1.0, 1.0, 1.0,
+    -1.0, -1.0, -1.0, 0.0, 1.0,
+    -1.0, -1.0,  1.0, 0.0, 0.0,
+    /* top face */
+     1.0, -1.0,  1.0, 1.0, 0.0,
+    -1.0, -1.0,  1.0, 0.0, 0.0,
+    -1.0, -1.0, -1.0, 0.0, 1.0,
+     1.0, -1.0, -1.0, 1.0, 1.0,
+    /* bottom face */
+     1.0,  1.0,  1.0, 1.0, 0.0,
+     1.0,  1.0, -1.0, 1.0, 1.0,
+    -1.0,  1.0, -1.0, 0.0, 1.0,
+    -1.0,  1.0,  1.0, 0.0, 0.0
+  };
+/* *INDENT-ON* */
+
+  GLushort indices[] = {
+    0, 1, 2,
+    0, 2, 3,
+    4, 5, 6,
+    4, 6, 7,
+    8, 9, 10,
+    8, 10, 11,
+    12, 13, 14,
+    12, 14, 15,
+    16, 17, 18,
+    16, 18, 19,
+    20, 21, 22,
+    20, 22, 23
+  };
+
+  GLint attr_position_loc = 0;
+  GLint attr_texture_loc = 0;
+
+  const GLfloat matrix[] = {
+    0.5f, 0.0f, 0.0f, 0.0f,
+    0.0f, 0.5f, 0.0f, 0.0f,
+    0.0f, 0.0f, 0.5f, 0.0f,
+    0.0f, 0.0f, 0.0f, 1.0f
+  };
+
+  gl->Enable (GL_DEPTH_TEST);
+
+  gl->ClearColor (cube_filter->red, cube_filter->green, cube_filter->blue, 0.0);
+  gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+  gst_gl_shader_use (cube_filter->shader);
+
+  attr_position_loc =
+      gst_gl_shader_get_attribute_location (cube_filter->shader, "a_position");
+  attr_texture_loc =
+      gst_gl_shader_get_attribute_location (cube_filter->shader, "a_texCoord");
+
+  /* Load the vertex position */
+  gl->VertexAttribPointer (attr_position_loc, 3, GL_FLOAT,
+      GL_FALSE, 5 * sizeof (GLfloat), v_vertices);
+
+  /* Load the texture coordinate */
+  gl->VertexAttribPointer (attr_texture_loc, 2, GL_FLOAT,
+      GL_FALSE, 5 * sizeof (GLfloat), &v_vertices[3]);
+
+  gl->EnableVertexAttribArray (attr_position_loc);
+  gl->EnableVertexAttribArray (attr_texture_loc);
+
+  gl->ActiveTexture (GL_TEXTURE0);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+  gst_gl_shader_set_uniform_1i (cube_filter->shader, "s_texture", 0);
+  gst_gl_shader_set_uniform_1f (cube_filter->shader, "xrot_degree", xrot);
+  gst_gl_shader_set_uniform_1f (cube_filter->shader, "yrot_degree", yrot);
+  gst_gl_shader_set_uniform_1f (cube_filter->shader, "zrot_degree", zrot);
+  gst_gl_shader_set_uniform_matrix_4fv (cube_filter->shader, "u_matrix", 1,
+      GL_FALSE, matrix);
+
+  gl->DrawElements (GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, indices);
+
+  gl->DisableVertexAttribArray (attr_position_loc);
+  gl->DisableVertexAttribArray (attr_texture_loc);
+
+  gl->Disable (GL_DEPTH_TEST);
+
+  xrot += 0.3f;
+  yrot += 0.2f;
+  zrot += 0.4f;
+}
+#endif
diff --git a/ext/gl/gstglfiltercube.h b/ext/gl/gstglfiltercube.h
new file mode 100644 (file)
index 0000000..a72d09a
--- /dev/null
@@ -0,0 +1,65 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.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.
+ */
+
+#ifndef _GST_GL_FILTERCUBE_H_
+#define _GST_GL_FILTERCUBE_H_
+
+#include <gst/gl/gstglfilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_GL_FILTER_CUBE            (gst_gl_filter_cube_get_type())
+#define GST_GL_FILTER_CUBE(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_FILTER_CUBE,GstGLFilterCube))
+#define GST_IS_GL_FILTER_CUBE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_FILTER_CUBE))
+#define GST_GL_FILTER_CUBE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_FILTER_CUBE,GstGLFilterCubeClass))
+#define GST_IS_GL_FILTER_CUBE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_FILTER_CUBE))
+#define GST_GL_FILTER_CUBE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_FILTER_CUBE,GstGLFilterCubeClass))
+
+typedef struct _GstGLFilterCube GstGLFilterCube;
+typedef struct _GstGLFilterCubeClass GstGLFilterCubeClass;
+
+struct _GstGLFilterCube
+{
+    GstGLFilter filter;
+
+    GstGLShader *shader;
+
+    /* background color */
+    gfloat red;
+    gfloat green;
+    gfloat blue;
+
+    /* perspective */
+    gdouble fovy;
+    gdouble aspect;
+    gdouble znear;
+    gdouble zfar;
+};
+
+struct _GstGLFilterCubeClass
+{
+    GstGLFilterClass filter_class;
+};
+
+GType gst_gl_glfiltercube_get_type (void);
+
+G_END_DECLS
+
+#endif /* _GST_GLFILTERCUBE_H_ */
diff --git a/ext/gl/gstglfilterglass.c b/ext/gl/gstglfilterglass.c
new file mode 100644 (file)
index 0000000..4b26552
--- /dev/null
@@ -0,0 +1,406 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.com>
+ * Inspired from http://www.mdk.org.pl/2007/11/17/gl-colorspace-conversions
+ *
+ * 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.
+ */
+
+/**
+ * SECTION:element-glfilterglass
+ *
+ * Map textures on moving glass.
+ *
+ * <refsect2>
+ * <title>Examples</title>
+ * |[
+ * gst-launch -v videotestsrc ! glupload ! glfilterglass ! glimagesink
+ * ]| A pipeline inspired from http://www.mdk.org.pl/2007/11/17/gl-colorspace-conversions
+ * FBO is required.
+ * |[
+ * gst-launch -v videotestsrc ! glupload ! glfilterglass ! "video/x-raw-gl, width=640, height=480" ! glimagesink
+ * ]| The scene is greater than the input size.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include "gstglfilterglass.h"
+
+#define GST_CAT_DEFAULT gst_gl_filter_glass_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+enum
+{
+  PROP_0
+};
+
+#define DEBUG_INIT \
+  GST_DEBUG_CATEGORY_INIT (gst_gl_filter_glass_debug, "glfilterglass", 0, "glfilterglass element");
+
+G_DEFINE_TYPE_WITH_CODE (GstGLFilterGlass, gst_gl_filter_glass,
+    GST_TYPE_GL_FILTER, DEBUG_INIT);
+
+static void gst_gl_filter_glass_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_gl_filter_glass_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static void gst_gl_filter_glass_reset (GstGLFilter * filter);
+static gboolean gst_gl_filter_glass_init_shader (GstGLFilter * filter);
+static gboolean gst_gl_filter_glass_filter_texture (GstGLFilter * filter,
+    guint in_tex, guint out_tex);
+
+static void gst_gl_filter_glass_draw_background_gradient ();
+static void gst_gl_filter_glass_draw_video_plane (GstGLFilter * filter,
+    gint width, gint height, guint texture, gfloat center_x, gfloat center_y,
+    gfloat start_alpha, gfloat stop_alpha, gboolean reversed, gfloat rotation);
+
+static void gst_gl_filter_glass_callback (gpointer stuff);
+
+/* *INDENT-OFF* */
+static const gchar *glass_fragment_source =
+    "uniform sampler2D tex;\n"
+    "varying float alpha;\n"
+    "void main () {\n"
+    "  float p = 0.0525;\n"
+    "  float L1 = p*1.0;\n"
+    "  float L2 = 1.0 - L1;\n"
+    "  float L3 = 1.0 - L1;\n"
+    "  float w = 1.0;\n"
+    "  float r = L1;\n"
+    "  if (gl_TexCoord[0].x < L1 && gl_TexCoord[0].y < L1)\n"
+    "      r = sqrt( (gl_TexCoord[0].x - L1) * (gl_TexCoord[0].x - L1) + (gl_TexCoord[0].y - L1) * (gl_TexCoord[0].y - L1) );\n"
+    "  else if (gl_TexCoord[0].x > L2 && gl_TexCoord[0].y < L1)\n"
+    "      r = sqrt( (gl_TexCoord[0].x - L2) * (gl_TexCoord[0].x - L2) + (gl_TexCoord[0].y - L1) * (gl_TexCoord[0].y - L1) );\n"
+    "  else if (gl_TexCoord[0].x > L2 && gl_TexCoord[0].y > L3)\n"
+    "      r = sqrt( (gl_TexCoord[0].x - L2) * (gl_TexCoord[0].x - L2) + (gl_TexCoord[0].y - L3) * (gl_TexCoord[0].y - L3) );\n"
+    "  else if (gl_TexCoord[0].x < L1 && gl_TexCoord[0].y > L3)\n"
+    "      r = sqrt( (gl_TexCoord[0].x - L1) * (gl_TexCoord[0].x - L1) + (gl_TexCoord[0].y - L3) * (gl_TexCoord[0].y - L3) );\n"
+    "  if (r > L1)\n"
+    "      w = 0.0;\n"
+    "  vec4 color = texture2D (tex, gl_TexCoord[0].st);\n"
+    "  gl_FragColor = vec4(color.rgb, alpha * w);\n"
+    "}\n";
+
+static const gchar *glass_vertex_source =
+    "uniform float yrot;\n"
+    "uniform float aspect;\n"
+    "const float fovy = 80.0;\n"
+    "const float znear = 1.0;\n"
+    "const float zfar = 5000.0;\n"
+    "varying float alpha;\n"
+    "void main () {\n"
+    "   float f = 1.0/(tan(radians(fovy/2.0)));\n"
+    "   float rot = radians (yrot);\n"
+    "   // replacement for gluPerspective\n"
+    "   mat4 perspective = mat4 (\n"
+    "            f/aspect, 0.0,  0.0,                      0.0,\n"
+    "            0.0,      f,    0.0,                      0.0,\n"
+    "            0.0,      0.0, (znear+zfar)/(znear-zfar), 2.0*znear*zfar/(znear-zfar),\n"
+    "            0.0,      0.0, -1.0,                      0.0 );\n"
+    "   mat4 trans = mat4 (\n"
+    "            1.0, 0.0, 0.0, 0.0,\n"
+    "            0.0, 1.0, 0.0, 0.0,\n"
+    "            0.0, 0.0, 1.0, -3.0,\n"
+    "            0.0, 0.0, 0.0, 1.0 );\n"
+    "   mat4 rotation = mat4 (\n"
+    "            cos(rot),  0.0, sin(rot), 0.0,\n"
+    "            0.0,       1.0, 0.0,      0.0,\n"
+    "            -sin(rot), 0.0, cos(rot), 0.0,\n"
+    "            0.0,       0.0, 0.0,      1.0 );\n"
+    "  gl_Position = trans * perspective * rotation * gl_ModelViewProjectionMatrix * gl_Vertex;\n"
+    "  gl_TexCoord[0] = gl_MultiTexCoord0;\n"
+    "  alpha = gl_Color.a;\n"
+    "}\n";
+
+static const gchar * passthrough_vertex = 
+    "void main () {\n"
+    "  gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
+    "  gl_FrontColor = gl_Color;\n"
+    "}\n";
+
+static const gchar * passthrough_fragment = 
+    "void main () {\n"
+    "  gl_FragColor = gl_Color;\n"
+    "}\n";
+/* *INDENT-ON* */
+
+static void
+gst_gl_filter_glass_class_init (GstGLFilterGlassClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *element_class;
+
+  gobject_class = (GObjectClass *) klass;
+  element_class = GST_ELEMENT_CLASS (klass);
+
+  gobject_class->set_property = gst_gl_filter_glass_set_property;
+  gobject_class->get_property = gst_gl_filter_glass_get_property;
+
+  gst_element_class_set_metadata (element_class, "OpenGL glass filter",
+      "Filter/Effect/Video", "Glass Filter",
+      "Julien Isorce <julien.isorce@gmail.com>");
+
+  GST_GL_FILTER_CLASS (klass)->filter_texture =
+      gst_gl_filter_glass_filter_texture;
+  GST_GL_FILTER_CLASS (klass)->onInitFBO = gst_gl_filter_glass_init_shader;
+  GST_GL_FILTER_CLASS (klass)->onReset = gst_gl_filter_glass_reset;
+}
+
+static void
+gst_gl_filter_glass_init (GstGLFilterGlass * filter)
+{
+  filter->shader = NULL;
+  filter->timestamp = 0;
+}
+
+static void
+gst_gl_filter_glass_reset (GstGLFilter * filter)
+{
+  GstGLFilterGlass *glass_filter = GST_GL_FILTER_GLASS (filter);
+
+  //blocking call, wait the opengl thread has destroyed the shader
+  if (glass_filter->shader)
+    gst_gl_context_del_shader (filter->context, glass_filter->shader);
+  glass_filter->shader = NULL;
+  if (glass_filter->passthrough_shader)
+    gst_gl_context_del_shader (filter->context,
+        glass_filter->passthrough_shader);
+  glass_filter->passthrough_shader = NULL;
+}
+
+static void
+gst_gl_filter_glass_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  //GstGLFilterGlass *filter = GST_GL_FILTER_GLASS (object);
+
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_gl_filter_glass_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  //GstGLFilterGlass *filter = GST_GL_FILTER_GLASS (object);
+
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_gl_filter_glass_init_shader (GstGLFilter * filter)
+{
+  gboolean ret;
+  GstGLFilterGlass *glass_filter = GST_GL_FILTER_GLASS (filter);
+
+  //blocking call, wait the opengl thread has compiled the shader
+  ret =
+      gst_gl_context_gen_shader (filter->context, glass_vertex_source,
+      glass_fragment_source, &glass_filter->shader);
+  if (ret)
+    ret =
+        gst_gl_context_gen_shader (filter->context, passthrough_vertex,
+        passthrough_fragment, &glass_filter->passthrough_shader);
+
+  return ret;
+}
+
+static gboolean
+gst_gl_filter_glass_filter_texture (GstGLFilter * filter, guint in_tex,
+    guint out_tex)
+{
+  GstGLFilterGlass *glass_filter = GST_GL_FILTER_GLASS (filter);
+  glass_filter->in_tex = in_tex;
+
+  //blocking call, use a FBO
+  gst_gl_context_use_fbo_v2 (filter->context,
+      GST_VIDEO_INFO_WIDTH (&filter->out_info),
+      GST_VIDEO_INFO_HEIGHT (&filter->out_info),
+      filter->fbo, filter->depthbuffer, out_tex,
+      gst_gl_filter_glass_callback, (gpointer) glass_filter);
+
+  return TRUE;
+}
+
+static gint64
+get_time (void)
+{
+  static GTimeVal val;
+  g_get_current_time (&val);
+
+  return (val.tv_sec * G_USEC_PER_SEC) + val.tv_usec;
+}
+
+static void
+gst_gl_filter_glass_draw_background_gradient (GstGLFilterGlass * glass)
+{
+  GstGLFilter *filter = GST_GL_FILTER (glass);
+  GstGLFuncs *gl = filter->context->gl_vtable;
+
+/* *INDENT-OFF* */
+  gfloat mesh[] = {
+  /* |       Vertex       |        Color         | */
+      -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
+       1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
+       1.0f,  0.8f, 0.0f, 0.0f, 0.0f, 0.2f, 1.0f,
+      -1.0f,  0.8f, 0.0f, 0.0f, 0.0f, 0.2f, 1.0f,
+      -1.0f,  1.0f, 0.0f, 0.0f, 0.0f, 0.2f, 1.0f,
+       1.0f,  1.0f, 0.0f, 0.0f, 0.0f, 0.2f, 1.0f,
+  };
+/* *INDENT-ON* */
+
+  GLushort indices[] = {
+    0, 1, 2,
+    0, 2, 3,
+    2, 3, 4,
+    2, 4, 5
+  };
+
+  gl->ClientActiveTexture (GL_TEXTURE0);
+  gl->EnableClientState (GL_VERTEX_ARRAY);
+  gl->EnableClientState (GL_COLOR_ARRAY);
+
+  gl->VertexPointer (3, GL_FLOAT, 7 * sizeof (gfloat), mesh);
+  gl->ColorPointer (4, GL_FLOAT, 7 * sizeof (gfloat), &mesh[3]);
+
+  gl->DrawElements (GL_TRIANGLES, 12, GL_UNSIGNED_SHORT, indices);
+
+  gl->DisableClientState (GL_VERTEX_ARRAY);
+  gl->DisableClientState (GL_COLOR_ARRAY);
+}
+
+static void
+gst_gl_filter_glass_draw_video_plane (GstGLFilter * filter,
+    gint width, gint height, guint texture,
+    gfloat center_x, gfloat center_y,
+    gfloat start_alpha, gfloat stop_alpha, gboolean reversed, gfloat rotation)
+{
+  GstGLFilterGlass *glass_filter = GST_GL_FILTER_GLASS (filter);
+  GstGLFuncs *gl = filter->context->gl_vtable;
+
+  gfloat topy = reversed ? center_y - 1.0f : center_y + 1.0f;
+  gfloat bottomy = reversed ? center_y + 1.0f : center_y - 1.0f;
+
+/* *INDENT-OFF* */
+  gfloat mesh[] = {
+ /*|           Vertex          |TexCoord0|      Colour               |*/
+    center_x-1.6, topy,    0.0, 0.0, 1.0, 1.0, 1.0, 1.0, start_alpha,
+    center_x+1.6, topy,    0.0, 1.0, 1.0, 1.0, 1.0, 1.0, start_alpha,
+    center_x+1.6, bottomy, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, stop_alpha,
+    center_x-1.6, bottomy, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, stop_alpha,
+  };
+/* *INDENT-ON* */
+
+  GLushort indices[] = {
+    0, 1, 2,
+    0, 2, 3
+  };
+
+  gl->ActiveTexture (GL_TEXTURE0);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+  gl->Disable (GL_TEXTURE_2D);
+
+  gst_gl_shader_set_uniform_1i (glass_filter->shader, "tex", 0);
+  gst_gl_shader_set_uniform_1f (glass_filter->shader, "yrot", rotation);
+  gst_gl_shader_set_uniform_1f (glass_filter->shader, "aspect",
+      (gfloat) width / (gfloat) height);
+
+  gl->ClientActiveTexture (GL_TEXTURE0);
+  gl->EnableClientState (GL_TEXTURE_COORD_ARRAY);
+  gl->EnableClientState (GL_VERTEX_ARRAY);
+  gl->EnableClientState (GL_COLOR_ARRAY);
+
+  gl->VertexPointer (3, GL_FLOAT, 9 * sizeof (gfloat), mesh);
+  gl->TexCoordPointer (2, GL_FLOAT, 9 * sizeof (gfloat), &mesh[3]);
+  gl->ColorPointer (4, GL_FLOAT, 9 * sizeof (gfloat), &mesh[5]);
+
+  gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
+
+  gl->DisableClientState (GL_TEXTURE_COORD_ARRAY);
+  gl->DisableClientState (GL_VERTEX_ARRAY);
+  gl->DisableClientState (GL_COLOR_ARRAY);
+}
+
+//opengl scene, params: input texture (not the output filter->texture)
+static void
+gst_gl_filter_glass_callback (gpointer stuff)
+{
+  static gint64 start_time = 0;
+  gfloat rotation;
+
+  GstGLFilter *filter = GST_GL_FILTER (stuff);
+  GstGLFilterGlass *glass_filter = GST_GL_FILTER_GLASS (stuff);
+  GstGLFuncs *gl = filter->context->gl_vtable;
+
+  gint width = GST_VIDEO_INFO_WIDTH (&filter->out_info);
+  gint height = GST_VIDEO_INFO_HEIGHT (&filter->out_info);
+  guint texture = glass_filter->in_tex;
+
+  if (start_time == 0)
+    start_time = get_time ();
+  else {
+    gint64 time_left =
+        (glass_filter->timestamp / 1000) - (get_time () - start_time);
+    time_left -= 1000000 / 25;
+    if (time_left > 2000) {
+      GST_LOG ("escape");
+      return;
+    }
+  }
+
+  gst_gl_shader_use (glass_filter->passthrough_shader);
+
+  gst_gl_filter_glass_draw_background_gradient (glass_filter);
+
+  //Rotation
+  if (start_time != 0) {
+    gint64 time_passed = get_time () - start_time;
+    rotation = sin (time_passed / 1200000.0) * 45.0f;
+  } else {
+    rotation = 0.0f;
+  }
+
+  gl->Enable (GL_BLEND);
+  gl->BlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+  gst_gl_shader_use (glass_filter->shader);
+
+  //Reflection
+  gst_gl_filter_glass_draw_video_plane (filter, width, height, texture,
+      0.0f, 2.0f, 0.3f, 0.0f, TRUE, rotation);
+
+  //Main video
+  gst_gl_filter_glass_draw_video_plane (filter, width, height, texture,
+      0.0f, 0.0f, 1.0f, 1.0f, FALSE, rotation);
+
+  gst_gl_context_clear_shader (filter->context);
+
+  gl->Disable (GL_TEXTURE_2D);
+  gl->Disable (GL_BLEND);
+}
diff --git a/ext/gl/gstglfilterglass.h b/ext/gl/gstglfilterglass.h
new file mode 100644 (file)
index 0000000..0048851
--- /dev/null
@@ -0,0 +1,56 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.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.
+ */
+
+#ifndef _GST_GL_FILTERGLASS_H_
+#define _GST_GL_FILTERGLASS_H_
+
+#include <gst/gl/gstglfilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_GL_FILTER_GLASS            (gst_gl_filter_glass_get_type())
+#define GST_GL_FILTER_GLASS(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_FILTER_GLASS,GstGLFilterGlass))
+#define GST_IS_GL_FILTER_GLASS(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_FILTER_GLASS))
+#define GST_GL_FILTER_GLASS_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_FILTER_GLASS,GstGLFilterGlassClass))
+#define GST_IS_GL_FILTER_GLASS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_FILTER_GLASS))
+#define GST_GL_FILTER_GLASS_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_FILTER_GLASS,GstGLFilterGlassClass))
+
+typedef struct _GstGLFilterGlass GstGLFilterGlass;
+typedef struct _GstGLFilterGlassClass GstGLFilterGlassClass;
+
+struct _GstGLFilterGlass
+{
+  GstGLFilter filter;
+  GstGLShader *passthrough_shader;
+  GstGLShader *shader;
+  gint64 timestamp;
+  guint in_tex;
+};
+
+struct _GstGLFilterGlassClass
+{
+  GstGLFilterClass filter_class;
+};
+
+GType gst_gl_glfilterglass_get_type (void);
+
+G_END_DECLS
+
+#endif /* _GST_GLFILTERGLASS_H_ */
diff --git a/ext/gl/gstglfilterlaplacian.c b/ext/gl/gstglfilterlaplacian.c
new file mode 100644 (file)
index 0000000..6424a9c
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008-2010 Filippo Argiolas <filippo.argiolas@gmail.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.
+ */
+
+/**
+ * SECTION:element-glfilterlaplacian
+ *
+ * Laplacian Convolution Demo Filter.
+ *
+ * <refsect2>
+ * <title>Examples</title>
+ * |[
+ * gst-launch videotestsrc ! glupload ! glfilterlaplacian ! glimagesink
+ * ]|
+ * FBO (Frame Buffer Object) and GLSL (OpenGL Shading Language) are required.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstglfilterlaplacian.h"
+
+#define GST_CAT_DEFAULT gst_gl_filter_laplacian_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+enum
+{
+  PROP_0
+};
+
+#define DEBUG_INIT \
+  GST_DEBUG_CATEGORY_INIT (gst_gl_filter_laplacian_debug, "glfilterlaplacian", 0, "glfilterlaplacian element");
+
+G_DEFINE_TYPE_WITH_CODE (GstGLFilterLaplacian, gst_gl_filter_laplacian,
+    GST_TYPE_GL_FILTER, DEBUG_INIT);
+
+static void gst_gl_filter_laplacian_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_gl_filter_laplacian_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+
+static void gst_gl_filter_laplacian_reset (GstGLFilter * filter);
+static gboolean gst_gl_filter_laplacian_init_shader (GstGLFilter * filter);
+static gboolean gst_gl_filter_laplacian_filter_texture (GstGLFilter * filter,
+    guint in_tex, guint out_tex);
+static void gst_gl_filter_laplacian_callback (gint width, gint height,
+    guint texture, gpointer stuff);
+
+/* *INDENT-OFF* */
+
+/* This filter is meant as a demo of gst-plugins-gl + glsl
+   capabilities. So I'm keeping this shader readable enough. If and
+   when this shader will be used in production be careful to hard code
+   kernel into the shader and remove unneeded zero multiplications in
+   the convolution */
+static const gchar *convolution_fragment_source =
+  "uniform sampler2D tex;"
+  "uniform float kernel[9];"
+  "uniform float width, height;"
+  "void main () {"
+  "  float w = 1.0 / width;"
+  "  float h = 1.0 / height;"
+  "  vec2 texturecoord[9];"
+  "  texturecoord[4] = gl_TexCoord[0].st;"                /*  0  0 */
+  "  texturecoord[5] = texturecoord[4] + vec2(w,   0.0);" /*  1  0 */
+  "  texturecoord[2] = texturecoord[5] - vec2(0.0, h);" /*  1 -1 */
+  "  texturecoord[1] = texturecoord[2] - vec2(w,   0.0);" /*  0 -1 */
+  "  texturecoord[0] = texturecoord[1] - vec2(w,   0.0);" /* -1 -1 */
+  "  texturecoord[3] = texturecoord[0] + vec2(0.0, h);" /* -1  0 */
+  "  texturecoord[6] = texturecoord[3] + vec2(0.0, h);" /* -1  1 */
+  "  texturecoord[7] = texturecoord[6] + vec2(w,   0.0);" /*  0  1 */
+  "  texturecoord[8] = texturecoord[7] + vec2(w,   0.0);" /*  1  1 */
+  "  int i;"
+  "  vec4 sum = vec4 (0.0);"
+  "  for (i = 0; i < 9; i++) { "
+  "    vec4 neighbor = texture2D(tex, texturecoord[i]);"
+  "    sum += neighbor * kernel[i];"
+  "  }"
+  "  gl_FragColor = sum;"
+  "}";
+/* *INDENT-ON* */
+
+static void
+gst_gl_filter_laplacian_class_init (GstGLFilterLaplacianClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *element_class;
+
+  gobject_class = (GObjectClass *) klass;
+  element_class = GST_ELEMENT_CLASS (klass);
+
+  gobject_class->set_property = gst_gl_filter_laplacian_set_property;
+  gobject_class->get_property = gst_gl_filter_laplacian_get_property;
+
+  gst_element_class_set_metadata (element_class,
+      "OpenGL laplacian filter", "Filter/Effect/Video",
+      "Laplacian Convolution Demo Filter",
+      "Filippo Argiolas <filippo.argiolas@gmail.com>");
+
+  GST_GL_FILTER_CLASS (klass)->filter_texture =
+      gst_gl_filter_laplacian_filter_texture;
+  GST_GL_FILTER_CLASS (klass)->onInitFBO = gst_gl_filter_laplacian_init_shader;
+  GST_GL_FILTER_CLASS (klass)->onReset = gst_gl_filter_laplacian_reset;
+}
+
+static void
+gst_gl_filter_laplacian_init (GstGLFilterLaplacian * filter)
+{
+  filter->shader = NULL;
+}
+
+static void
+gst_gl_filter_laplacian_reset (GstGLFilter * filter)
+{
+  GstGLFilterLaplacian *laplacian_filter = GST_GL_FILTER_LAPLACIAN (filter);
+
+  //blocking call, wait the opengl thread has destroyed the shader
+  if (laplacian_filter->shader)
+    gst_gl_context_del_shader (filter->context, laplacian_filter->shader);
+  laplacian_filter->shader = NULL;
+}
+
+static void
+gst_gl_filter_laplacian_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  //GstGLFilterLaplacian *filter = GST_GL_FILTER_LAPLACIAN (object);
+
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_gl_filter_laplacian_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  //GstGLFilterLaplacian *filter = GST_GL_FILTER_LAPLACIAN (object);
+
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_gl_filter_laplacian_init_shader (GstGLFilter * filter)
+{
+  GstGLFilterLaplacian *laplacian_filter = GST_GL_FILTER_LAPLACIAN (filter);
+
+  //blocking call, wait the opengl thread has compiled the shader
+  return gst_gl_context_gen_shader (filter->context, 0,
+      convolution_fragment_source, &laplacian_filter->shader);
+}
+
+static gboolean
+gst_gl_filter_laplacian_filter_texture (GstGLFilter * filter, guint in_tex,
+    guint out_tex)
+{
+  gpointer laplacian_filter = GST_GL_FILTER_LAPLACIAN (filter);
+
+
+  //blocking call, use a FBO
+  gst_gl_filter_render_to_target (filter, TRUE, in_tex, out_tex,
+      gst_gl_filter_laplacian_callback, laplacian_filter);
+
+  return TRUE;
+}
+
+//opengl scene, params: input texture (not the output filter->texture)
+static void
+gst_gl_filter_laplacian_callback (gint width, gint height, guint texture,
+    gpointer stuff)
+{
+  GstGLFilter *filter = GST_GL_FILTER (stuff);
+  GstGLFilterLaplacian *laplacian_filter = GST_GL_FILTER_LAPLACIAN (filter);
+  GstGLFuncs *gl = filter->context->gl_vtable;
+
+  gfloat kernel[9] = { 0.0, -1.0, 0.0,
+    -1.0, 4.0, -1.0,
+    0.0, -1.0, 0.0
+  };
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+
+  gst_gl_shader_use (laplacian_filter->shader);
+
+  gl->ActiveTexture (GL_TEXTURE0);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+
+  gst_gl_shader_set_uniform_1i (laplacian_filter->shader, "tex", 0);
+  gst_gl_shader_set_uniform_1fv (laplacian_filter->shader, "kernel", 9, kernel);
+  gst_gl_shader_set_uniform_1f (laplacian_filter->shader, "width",
+      (gfloat) width);
+  gst_gl_shader_set_uniform_1f (laplacian_filter->shader, "height",
+      (gfloat) height);
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
diff --git a/ext/gl/gstglfilterlaplacian.h b/ext/gl/gstglfilterlaplacian.h
new file mode 100644 (file)
index 0000000..acfa376
--- /dev/null
@@ -0,0 +1,53 @@
+/* 
+ * GStreamer
+ * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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.
+ */
+
+#ifndef _GST_GL_FILTERLAPLACIAN_H_
+#define _GST_GL_FILTERLAPLACIAN_H_
+
+#include <gst/gl/gstglfilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_GL_FILTER_LAPLACIAN            (gst_gl_filter_laplacian_get_type())
+#define GST_GL_FILTER_LAPLACIAN(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_FILTER_LAPLACIAN,GstGLFilterLaplacian))
+#define GST_IS_GL_FILTER_LAPLACIAN(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_FILTER_LAPLACIAN))
+#define GST_GL_FILTER_LAPLACIAN_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_FILTER_LAPLACIAN,GstGLFilterLaplacianClass))
+#define GST_IS_GL_FILTER_LAPLACIAN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_FILTER_LAPLACIAN))
+#define GST_GL_FILTER_LAPLACIAN_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_FILTER_LAPLACIAN,GstGLFilterLaplacianClass))
+
+typedef struct _GstGLFilterLaplacian GstGLFilterLaplacian;
+typedef struct _GstGLFilterLaplacianClass GstGLFilterLaplacianClass;
+
+struct _GstGLFilterLaplacian
+{
+  GstGLFilter filter;
+  GstGLShader *shader;
+};
+
+struct _GstGLFilterLaplacianClass
+{
+  GstGLFilterClass filter_class;
+};
+
+GType gst_gl_glfilterlaplacian_get_type (void);
+
+G_END_DECLS
+
+#endif /* _GST_GLFILTERLAPLACIAN_H_ */
diff --git a/ext/gl/gstglfilterreflectedscreen.c b/ext/gl/gstglfilterreflectedscreen.c
new file mode 100644 (file)
index 0000000..4934bca
--- /dev/null
@@ -0,0 +1,482 @@
+/*
+ * GStreamer
+ * Copyright (C) 2010 Pierre Pouzol<pierre.pouzol@hotmail.fr>
+ *
+ * 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.
+ */
+
+/**
+ * SECTION:element-glfilterreflectedscreen
+ *
+ * Map Video Texture upon a screen, on a reflecting surface
+ *
+ * <refsect2>
+ * <title>Examples</title>
+ * |[
+ * gst-launch videotestsrc ! glupload ! glfilterreflectedscreen ! glimagesink
+ * ]|
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include "gstglfilterreflectedscreen.h"
+
+#define GST_CAT_DEFAULT gst_gl_filter_reflected_screen_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+enum
+{
+  PROP_0,
+  PROP_ACTIVE_GRAPHIC_MODE,
+  PROP_SEPARATED_SCREEN,
+  PROP_SHOW_FLOOR,
+  PROP_FOVY,
+  PROP_ASPECT,
+  PROP_ZNEAR,
+  PROP_ZFAR
+};
+
+#define DEBUG_INIT \
+  GST_DEBUG_CATEGORY_INIT (gst_gl_filter_reflected_screen_debug, "glfilterreflectedscreen", 0, "glfilterreflectedscreen element");
+
+G_DEFINE_TYPE_WITH_CODE (GstGLFilterReflectedScreen,
+    gst_gl_filter_reflected_screen, GST_TYPE_GL_FILTER, DEBUG_INIT);
+
+static void gst_gl_filter_reflected_screen_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_gl_filter_reflected_screen_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+
+static gboolean gst_gl_filter_reflected_screen_filter_texture (GstGLFilter *
+    filter, guint in_tex, guint out_tex);
+
+static void gst_gl_filter_reflected_screen_draw_background ();
+static void gst_gl_filter_reflected_screen_draw_floor ();
+static void gst_gl_filter_reflected_screen_draw_screen (GstGLFilter * filter,
+    gint width, gint height, guint texture);
+static void gst_gl_filter_reflected_screen_draw_separated_screen (GstGLFilter *
+    filter, gint width, gint height, guint texture, gfloat alphs, gfloat alphe);
+
+static void gst_gl_filter_reflected_screen_callback (gint width, gint height,
+    guint texture, gpointer stuff);
+
+static GLfloat LightPos[] = { 4.0f, -4.0f, 6.0f, 1.0f };        // Light Position
+static GLfloat LightAmb[] = { 4.0f, 4.0f, 4.0f, 1.0f }; // Ambient Light
+static GLfloat LightDif[] = { 1.0f, 1.0f, 1.0f, 1.0f }; // Diffuse Light
+
+static void
+gst_gl_filter_reflected_screen_class_init (GstGLFilterReflectedScreenClass *
+    klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *element_class;
+
+  gobject_class = (GObjectClass *) klass;
+  element_class = GST_ELEMENT_CLASS (klass);
+
+  gobject_class->set_property = gst_gl_filter_reflected_screen_set_property;
+  gobject_class->get_property = gst_gl_filter_reflected_screen_get_property;
+
+  GST_GL_FILTER_CLASS (klass)->filter_texture =
+      gst_gl_filter_reflected_screen_filter_texture;
+
+  g_object_class_install_property (gobject_class, PROP_ACTIVE_GRAPHIC_MODE,
+      g_param_spec_boolean ("active-graphic-mode",
+          "Activate graphic mode",
+          "Allow user to activate stencil buffer and blending.",
+          TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_SEPARATED_SCREEN,
+      g_param_spec_boolean ("separated-screen",
+          "Create a separation space",
+          "Allow to insert a space between the two screen. Will cancel 'show floor' if active. Value are TRUE or FALSE(default)",
+          FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_SHOW_FLOOR,
+      g_param_spec_boolean ("show-floor",
+          "Show the support",
+          "Allow the user to show the supportive floor. Will cancel 'separated screen' if active. Value are TRUE(default) or FALSE",
+          TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_FOVY,
+      g_param_spec_double ("fovy", "Fovy", "Field of view angle in degrees",
+          0.0, 180.0, 60, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_ASPECT,
+      g_param_spec_double ("aspect", "Aspect",
+          "Field of view in the x direction", 1.0, 100, 1.0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_ZNEAR,
+      g_param_spec_double ("znear", "Znear",
+          "Specifies the distance from the viewer to the near clipping plane",
+          0.0000000001, 100.0, 0.1,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_ZFAR,
+      g_param_spec_double ("zfar", "Zfar",
+          "Specifies the distance from the viewer to the far clipping plane",
+          0.0, 1000.0, 100.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_metadata (element_class,
+      "OpenGL Reflected Screen filter", "Filter/Effect/Video",
+      "Reflected Screen Filter", "Pierre POUZOL <pierre.pouzol@hotmail.fr>");
+}
+
+static void
+gst_gl_filter_reflected_screen_init (GstGLFilterReflectedScreen * filter)
+{
+  filter->active_graphic_mode = TRUE;
+  filter->separated_screen = FALSE;
+  filter->show_floor = TRUE;
+  filter->fovy = 90;
+  filter->aspect = 1.0;
+  filter->znear = 0.1;
+  filter->zfar = 1000;
+}
+
+static void
+gst_gl_filter_reflected_screen_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstGLFilterReflectedScreen *filter = GST_GL_FILTER_REFLECTED_SCREEN (object);
+
+  switch (prop_id) {
+    case PROP_ACTIVE_GRAPHIC_MODE:
+      filter->active_graphic_mode = g_value_get_boolean (value);
+      break;
+    case PROP_SEPARATED_SCREEN:
+      filter->separated_screen = g_value_get_boolean (value);
+      break;
+    case PROP_SHOW_FLOOR:
+      filter->show_floor = g_value_get_boolean (value);
+      break;
+    case PROP_FOVY:
+      filter->fovy = g_value_get_double (value);
+      break;
+    case PROP_ASPECT:
+      filter->aspect = g_value_get_double (value);
+      break;
+    case PROP_ZNEAR:
+      filter->znear = g_value_get_double (value);
+      break;
+    case PROP_ZFAR:
+      filter->zfar = g_value_get_double (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_gl_filter_reflected_screen_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstGLFilterReflectedScreen *filter = GST_GL_FILTER_REFLECTED_SCREEN (object);
+
+  switch (prop_id) {
+    case PROP_ACTIVE_GRAPHIC_MODE:
+      g_value_set_boolean (value, filter->active_graphic_mode);
+      break;
+    case PROP_SEPARATED_SCREEN:
+      g_value_set_boolean (value, filter->separated_screen);
+      break;
+    case PROP_SHOW_FLOOR:
+      g_value_set_boolean (value, filter->show_floor);
+      break;
+    case PROP_FOVY:
+      g_value_set_double (value, filter->fovy);
+      break;
+    case PROP_ASPECT:
+      g_value_set_double (value, filter->aspect);
+      break;
+    case PROP_ZNEAR:
+      g_value_set_double (value, filter->znear);
+      break;
+    case PROP_ZFAR:
+      g_value_set_double (value, filter->zfar);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_gl_filter_reflected_screen_filter_texture (GstGLFilter * filter,
+    guint in_tex, guint out_tex)
+{
+  GstGLFilterReflectedScreen *reflected_screen_filter =
+      GST_GL_FILTER_REFLECTED_SCREEN (filter);
+
+  //blocking call, use a FBO
+  gst_gl_context_use_fbo (filter->context,
+      GST_VIDEO_INFO_WIDTH (&filter->out_info),
+      GST_VIDEO_INFO_HEIGHT (&filter->out_info),
+      filter->fbo, filter->depthbuffer, out_tex,
+      gst_gl_filter_reflected_screen_callback,
+      GST_VIDEO_INFO_WIDTH (&filter->in_info),
+      GST_VIDEO_INFO_HEIGHT (&filter->in_info), in_tex,
+      reflected_screen_filter->fovy, reflected_screen_filter->aspect,
+      reflected_screen_filter->znear, reflected_screen_filter->zfar,
+      GST_GL_DISPLAY_PROJECTION_PERSPECTIVE,
+      (gpointer) reflected_screen_filter);
+
+  return TRUE;
+}
+
+static void
+gst_gl_filter_reflected_screen_draw_separated_screen (GstGLFilter * filter,
+    gint width, gint height, guint texture, gfloat alphs, gfloat alphe)
+{
+  //enable ARB Rectangular texturing
+  //that's necessary to have the video displayed on our screen (with gstreamer)
+  glEnable (GL_TEXTURE_2D);
+  glBindTexture (GL_TEXTURE_2D, texture);
+  //configure parameters for the texturing
+  //the two first are used to specified how the texturing will be done if the screen is greater than the texture herself
+  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+  //the next two specified how the texture will comport near the limits
+  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+  //creating screen and setting the texture (depending on texture's height and width)
+  glBegin (GL_QUADS);
+
+  // right Face
+  glColor4f (1.0f, 1.0f, 1.0f, alphs);
+  glTexCoord2f (0.5f, 1.0f);
+  glVertex3f (-0.75f, 0.0f, -1.0f);
+  glColor4f (1.0f, 1.0f, 1.0f, alphe);
+  glTexCoord2f (0.5f, 0.0f);
+  glVertex3f (-0.75f, 1.25f, -1.0f);
+  glTexCoord2f (1.0f, 0.0f);
+  glVertex3f (1.25f, 1.25f, -1.0f);
+  glColor4f (1.0f, 1.0f, 1.0f, alphs);
+  glTexCoord2f (1.0f, 1.0f);
+  glVertex3f (1.25f, 0.0f, -1.0f);
+  // Left Face
+  glColor4f (1.0f, 1.0f, 1.0f, alphs);
+  glTexCoord2f (0.5f, 1.0f);
+  glVertex3f (-1.0f, 0.0f, -0.75f);
+  glTexCoord2f (0.0f, 1.0f);
+  glVertex3f (-1.0f, 0.0f, 1.25f);
+  glColor4f (1.0f, 1.0f, 1.0f, alphe);
+  glTexCoord2f (0.0f, 0.0f);
+  glVertex3f (-1.0f, 1.25f, 1.25f);
+  glTexCoord2f (0.5f, 0.0f);
+  glVertex3f (-1.0f, 1.25f, -0.75f);
+
+  glEnd ();
+  glDisable (GL_TEXTURE_2D);
+}
+
+static void
+gst_gl_filter_reflected_screen_draw_screen (GstGLFilter * filter,
+    gint width, gint height, guint texture)
+{
+  //enable ARB Rectangular texturing
+  //that's necessary to have the video displayed on our screen (with gstreamer)
+  glEnable (GL_TEXTURE_2D);
+  glBindTexture (GL_TEXTURE_2D, texture);
+  //configure parameters for the texturing
+  //the two first are used to specified how the texturing will be done if the screen is greater than the texture herself
+  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+  //the next two specified how the texture will comport near the limits
+  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+  //creating screen and setting the texture (depending on texture's height and width)
+  glBegin (GL_QUADS);
+
+  glTexCoord2f (0.5f, 1.0f);
+  glVertex3f (-1.0f, 0.0f, -1.0f);
+  glTexCoord2f (0.5f, 0.0f);
+  glVertex3f (-1.0f, 1.0f, -1.0f);
+  glTexCoord2f (1.0f, 0.0f);
+  glVertex3f (1.0f, 1.0f, -1.0f);
+  glTexCoord2f (1.0f, 1.0f);
+  glVertex3f (1.0f, 0.0f, -1.0f);
+  // Left Face
+  glTexCoord2f (0.5f, 1.0f);
+  glVertex3f (-1.0f, 0.0f, -1.0f);
+  glTexCoord2f (0.0f, 1.0f);
+  glVertex3f (-1.0f, 0.0f, 1.0f);
+  glTexCoord2f (0.0f, 0.0f);
+  glVertex3f (-1.0f, 1.0f, 1.0f);
+  glTexCoord2f (0.5f, 0.0f);
+  glVertex3f (-1.0f, 1.0f, -1.0f);
+
+  glEnd ();
+
+  //disable this kind of texturing (useless for the gluDisk)
+  glDisable (GL_TEXTURE_2D);
+}
+
+static void
+gst_gl_filter_reflected_screen_draw_background ()
+{
+  glBegin (GL_QUADS);
+
+  // right Face
+
+  glColor4f (0.0f, 0.0f, 0.0f, 1.0f);
+  glVertex3f (-10.0f, -10.0f, -1.0f);
+
+  glColor4f (0.0f, 0.0f, 0.2f, 1.0f);
+  glVertex3f (-10.0f, 10.0f, -1.0f);
+  glVertex3f (10.0f, 10.0f, -1.0f);
+  glVertex3f (10.0f, -10.0f, -1.0f);
+
+  glEnd ();
+}
+
+static void
+gst_gl_filter_reflected_screen_draw_floor ()
+{
+  GLUquadricObj *q;
+  //create a quadric for the floor's drawing
+  q = gluNewQuadric ();
+  //configure this quadric's parameter (for lighting and texturing)
+  gluQuadricNormals (q, GL_SMOOTH);
+  gluQuadricTexture (q, GL_FALSE);
+
+  //drawing the disk. The texture are mapped thanks to the parameter we gave to the GLUquadric q
+  gluDisk (q, 0.0, 2.2, 50, 1);
+}
+
+//opengl scene, params: input texture (not the output filter->texture)
+static void
+gst_gl_filter_reflected_screen_callback (gint width, gint height, guint texture,
+    gpointer stuff)
+{
+  GstGLFilter *filter = GST_GL_FILTER (stuff);
+  GstGLFilterReflectedScreen *reflected_screen_filter =
+      GST_GL_FILTER_REFLECTED_SCREEN (stuff);
+
+  glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+
+  //load identity befor tracing
+  glLoadIdentity ();
+  //camera translation
+  glTranslatef (0.0f, 0.1f, -1.3f);
+  //camera configuration
+  if (reflected_screen_filter->separated_screen)
+    gluLookAt (0.1, -0.25, 2.0, 0.025, 0.0, 0.0, 0.0, 1.0, 0.0);
+  else
+    gluLookAt (0.1, -0.35, 2.0, 0.025, 0.0, 0.0, 0.0, 1.0, 0.0);
+
+  gst_gl_filter_reflected_screen_draw_background ();
+
+  if (reflected_screen_filter->separated_screen) {
+    glEnable (GL_BLEND);
+
+    glPushMatrix ();
+    glScalef (1.0f, -1.0f, 1.0f);
+    glTranslatef (0.0f, 0.0f, 1.2f);
+    glRotatef (-45.0f, 0.0, 1.0, 0.0);
+    gst_gl_filter_reflected_screen_draw_separated_screen (filter, width, height,
+        texture, 1.0f, 1.0f);
+    glPopMatrix ();
+
+    if (reflected_screen_filter->active_graphic_mode) {
+      //configuration of the transparency function
+      glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+      glTranslatef (0.0f, 0.0f, 1.2f);
+      glRotatef (-45.0f, 0.0, 1.0, 0.0);
+      gst_gl_filter_reflected_screen_draw_separated_screen (filter, width,
+          height, texture, 0.5f, 0.0f);
+      glDisable (GL_BLEND);
+    }
+  }
+  if (reflected_screen_filter->show_floor) {
+    glLightfv (GL_LIGHT0, GL_AMBIENT, LightAmb);
+    glLightfv (GL_LIGHT0, GL_DIFFUSE, LightDif);
+    glLightfv (GL_LIGHT0, GL_POSITION, LightPos);
+
+    //enable lighting
+    glEnable (GL_LIGHT0);
+    glEnable (GL_LIGHTING);
+
+    if (reflected_screen_filter->active_graphic_mode) {
+      glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+      //enable stencil buffer use
+      glEnable (GL_STENCIL_TEST);
+      //setting the stencil buffer. Each time a pixel will be drawn by now, this pixel value will be set to 1
+      glStencilFunc (GL_ALWAYS, 1, 1);
+      glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE);
+
+      //disable the zbuffer
+      glDisable (GL_DEPTH_TEST);
+      //make a rotation of 90 degree on x axis. By default, gluDisk draw a disk on z axis
+      glRotatef (-90.0f, 1.0, 0.0, 0.0);
+      //draw the floor. Each pixel representing this floor will now have a value of 1 on stencil buffer
+      gst_gl_filter_reflected_screen_draw_floor ();
+      //make an anti-rotation of 90 degree to draw the rest of the scene on the right angle
+      glRotatef (90.0f, 1.0, 0.0, 0.0);
+      //enable zbuffer again
+      glEnable (GL_DEPTH_TEST);
+      //enable the drawing to be shown
+      glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+      //say that the next object have to be drawn ONLY where the stencil buffer's pixel's value is 1
+      glStencilFunc (GL_EQUAL, 1, 1);
+      glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
+
+      //save the actual matrix
+      glPushMatrix ();
+      glLightfv (GL_LIGHT0, GL_POSITION, LightPos);
+      //translate the object on z axis
+      glTranslatef (0.0f, 0.0f, 1.4f);
+      //rotate it (because the drawing method place the user behind the left part of the screen)
+      glRotatef (-45.0f, 0.0, 1.0, 0.0);
+      //draw the reflexion
+      gst_gl_filter_reflected_screen_draw_screen (filter, width, height,
+          texture);
+      //return to the saved matrix position
+      glPopMatrix ();
+      //end of the stencil buffer uses
+      glDisable (GL_STENCIL_TEST);
+
+      //enable the blending to mix the floor and reflexion color
+      glEnable (GL_BLEND);
+      glDisable (GL_LIGHTING);
+      //specified a white color (for the floor) with 20% transparency
+      glColor4f (1.0f, 1.0f, 1.0f, 0.8f);
+      //configuration of the transparency function
+      glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    }
+    //draw the floor (which will appear this time)
+    glRotatef (-90.0f, 1.0, 0.0, 0.0);
+    gst_gl_filter_reflected_screen_draw_floor ();
+    glRotatef (90.0f, 1.0, 0.0, 0.0);
+    glDisable (GL_BLEND);
+    glEnable (GL_LIGHTING);
+    //draw the real object
+    //scale on y axis. The object must be drawn upside down (to suggest a reflexion)
+    glScalef (1.0f, -1.0f, 1.0f);
+    glTranslatef (0.0f, 0.0f, 1.4f);
+    glRotatef (-45.0f, 0.0, 1.0, 0.0);
+    gst_gl_filter_reflected_screen_draw_screen (filter, width, height, texture);
+    glDisable (GL_LIGHTING);
+  }
+}
diff --git a/ext/gl/gstglfilterreflectedscreen.h b/ext/gl/gstglfilterreflectedscreen.h
new file mode 100644 (file)
index 0000000..7f6c5cf
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Pierre Pouzol<pierre.pouzol@hotmail.fr>
+ *
+ * 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.
+ */
+
+#ifndef _GST_GL_FILTERREFLECTEDSCREEN_H_
+#define _GST_GL_FILTERREFLECTEDSCREEN_H_
+
+#include <gst/gl/gstglfilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_GL_FILTER_REFLECTED_SCREEN          (gst_gl_filter_reflected_screen_get_type())
+#define GST_GL_FILTER_REFLECTED_SCREEN(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_FILTER_REFLECTED_SCREEN,GstGLFilterReflectedScreen))
+#define GST_IS_GL_FILTER_REFLECTED_SCREEN(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_FILTER_REFLECTED_SCREEN))
+#define GST_GL_FILTER_REFLECTED_SCREEN_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_FILTER_REFLECTED_SCREEN,GstGLFilterReflectedScreenClass))
+#define GST_IS_GL_FILTER_REFLECTED_SCREEN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_FILTER_REFLECTED_SCREEN))
+#define GST_GL_FILTER_REFLECTED_SCREEN_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_FILTER_REFLECTED_SCREEN,GstGLFilterReflectedScreenClass))
+
+typedef struct _GstGLFilterReflectedScreen GstGLFilterReflectedScreen;
+typedef struct _GstGLFilterReflectedScreenClass GstGLFilterReflectedScreenClass;
+
+struct _GstGLFilterReflectedScreen
+{
+       GstGLFilter filter;
+       gdouble fovy;
+       gdouble aspect;
+       gdouble znear;
+       gdouble zfar;
+
+       gboolean active_graphic_mode;
+       gboolean separated_screen;
+       gboolean show_floor;
+};
+
+struct _GstGLFilterReflectedScreenClass
+{
+       GstGLFilterClass filter_class;
+};
+
+GType gst_gl_glfilterreflectedscreen_get_type (void);
+
+G_END_DECLS
+
+#endif /* _GST_GLFILTERREFLECTEDSCREEN_H_ */
+
diff --git a/ext/gl/gstglfiltershader.c b/ext/gl/gstglfiltershader.c
new file mode 100644 (file)
index 0000000..6cf88d5
--- /dev/null
@@ -0,0 +1,382 @@
+/*
+ * glshader gstreamer plugin
+ * Copyrithg (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
+ * Copyright (C) 2009 Luc Deschenaux <luc.deschenaux@freesurf.ch>
+ *
+ * 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.
+ */
+
+/**
+ * SECTION:element-glshader
+ *
+ * Filter loading OpenGL fragment shader from file
+ *
+ * <refsect2>
+ * <title>Examples</title>
+ * |[
+ * gst-launch videotestsrc ! glupload ! glshader location=myshader.fs ! glimagesink
+ * ]|
+ * FBO (Frame Buffer Object) and GLSL (OpenGL Shading Language) are required.
+ * </refsect2>
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <gst/gst.h>
+#include <gst/gl/gstglshadervariables.h>
+
+#include "gstglfiltershader.h"
+
+/* horizontal filter */
+static gchar *hfilter_fragment_source;
+static gchar *hfilter_fragment_variables[2];
+
+enum
+{
+  PROP_0,
+  PROP_LOCATION,
+  PROP_PRESET,
+  PROP_VARIABLES
+};
+
+#define GST_CAT_DEFAULT gst_gl_filtershader_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+#define DEBUG_INIT \
+  GST_DEBUG_CATEGORY_INIT (gst_gl_filtershader_debug, "glshader", 0, "glshader element");
+
+G_DEFINE_TYPE_WITH_CODE (GstGLFilterShader, gst_gl_filtershader,
+    GST_TYPE_GL_FILTER, DEBUG_INIT);
+
+static void gst_gl_filtershader_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_gl_filtershader_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_gl_filter_filtershader_reset (GstGLFilter * filter);
+
+static gboolean gst_gl_filtershader_load_shader (GstGLFilterShader *
+    filter_shader, char *filename, char **storage);
+static gboolean gst_gl_filtershader_load_variables (GstGLFilterShader *
+    filter_shader, char *filename, char **storage);
+static gboolean gst_gl_filtershader_init_shader (GstGLFilter * filter);
+static gboolean gst_gl_filtershader_filter_texture (GstGLFilter * filter,
+    guint in_tex, guint out_tex);
+static void gst_gl_filtershader_hcallback (gint width, gint height,
+    guint texture, gpointer stuff);
+
+
+static void
+gst_gl_filtershader_init_resources (GstGLFilter * filter)
+{
+  glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8,
+      GST_VIDEO_INFO_WIDTH (&filter->out_info),
+      GST_VIDEO_INFO_HEIGHT (&filter->out_info),
+      0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+}
+
+static void
+gst_gl_filtershader_reset_resources (GstGLFilter * filter)
+{
+  //GstGLFilterShader *filtershader = GST_GL_FILTERSHADER (filter);
+}
+
+static void
+gst_gl_filtershader_class_init (GstGLFilterShaderClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *element_class;
+
+  gobject_class = (GObjectClass *) klass;
+  element_class = GST_ELEMENT_CLASS (klass);
+
+  gobject_class->set_property = gst_gl_filtershader_set_property;
+  gobject_class->get_property = gst_gl_filtershader_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_LOCATION,
+      g_param_spec_string ("location", "File Location",
+          "Location of the GLSL file to load", NULL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_PRESET,
+      g_param_spec_string ("preset", "Preset File Location",
+          "Location of the shader uniform variables preset file", NULL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_VARIABLES,
+      g_param_spec_string ("vars", "Uniform variables",
+          "Set the shader uniform variables", NULL,
+          G_PARAM_WRITABLE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_metadata (element_class,
+      "OpenGL fragment shader filter", "Filter/Effect",
+      "Load GLSL fragment shader from file", "<luc.deschenaux@freesurf.ch>");
+
+  GST_GL_FILTER_CLASS (klass)->filter_texture =
+      gst_gl_filtershader_filter_texture;
+  GST_GL_FILTER_CLASS (klass)->display_init_cb =
+      gst_gl_filtershader_init_resources;
+  GST_GL_FILTER_CLASS (klass)->display_reset_cb =
+      gst_gl_filtershader_reset_resources;
+  GST_GL_FILTER_CLASS (klass)->onInitFBO = gst_gl_filtershader_init_shader;
+  GST_GL_FILTER_CLASS (klass)->onReset = gst_gl_filter_filtershader_reset;
+}
+
+static void
+gst_gl_filtershader_init (GstGLFilterShader * filtershader)
+{
+  filtershader->shader0 = NULL;
+}
+
+static void
+gst_gl_filter_filtershader_reset (GstGLFilter * filter)
+{
+  GstGLFilterShader *filtershader = GST_GL_FILTERSHADER (filter);
+
+  //blocking call, wait the opengl thread has destroyed the shader
+  if (filtershader->shader0)
+    gst_gl_context_del_shader (filter->context, filtershader->shader0);
+  filtershader->shader0 = NULL;
+}
+
+static void
+gst_gl_filtershader_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstGLFilterShader *filtershader = GST_GL_FILTERSHADER (object);
+
+  switch (prop_id) {
+
+    case PROP_LOCATION:
+
+      if (filtershader->filename) {
+        g_free (filtershader->filename);
+      }
+      if (filtershader->compiled) {
+        //gst_gl_context_del_shader (filtershader->filter.context, filtershader->shader0);
+        gst_gl_filter_filtershader_reset (&filtershader->filter);
+        filtershader->shader0 = 0;
+      }
+      filtershader->filename = g_strdup (g_value_get_string (value));
+      filtershader->compiled = 0;
+      filtershader->texSet = 0;
+
+      break;
+
+    case PROP_PRESET:
+
+      if (filtershader->presetfile) {
+        g_free (filtershader->presetfile);
+      }
+
+      filtershader->presetfile = g_strdup (g_value_get_string (value));
+
+      if (hfilter_fragment_variables[0]) {
+        g_free (hfilter_fragment_variables[0]);
+        hfilter_fragment_variables[0] = 0;
+      }
+
+      if (!filtershader->presetfile[0]) {
+        g_free (filtershader->presetfile);
+        filtershader->presetfile = 0;
+      }
+
+      break;
+
+    case PROP_VARIABLES:
+
+      if (hfilter_fragment_variables[1]) {
+        g_free (hfilter_fragment_variables[1]);
+      }
+
+      hfilter_fragment_variables[1] = g_strdup (g_value_get_string (value));
+
+      if (!hfilter_fragment_variables[1][0]) {
+        g_free (hfilter_fragment_variables[1]);
+        hfilter_fragment_variables[1] = 0;
+      }
+
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_gl_filtershader_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstGLFilterShader *filtershader = GST_GL_FILTERSHADER (object);
+
+  switch (prop_id) {
+    case PROP_LOCATION:
+      g_value_set_string (value, filtershader->filename);
+      break;
+
+    case PROP_PRESET:
+      g_value_set_string (value, filtershader->presetfile);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_gl_filtershader_load_shader (GstGLFilterShader * filter_shader,
+    char *filename, char **storage)
+{
+  GError *error = NULL;
+  gsize length;
+
+  g_return_val_if_fail (storage != NULL, FALSE);
+
+  if (!filename) {
+    GST_ELEMENT_ERROR (filter_shader, RESOURCE, NOT_FOUND,
+        ("A shader file is required"), (NULL));
+    return FALSE;
+  }
+
+  if (!g_file_get_contents (filename, storage, &length, &error)) {
+    GST_ELEMENT_ERROR (filter_shader, RESOURCE, NOT_FOUND, ("%s",
+            error->message), (NULL));
+    g_error_free (error);
+
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_gl_filtershader_load_variables (GstGLFilterShader * filter_shader,
+    char *filename, char **storage)
+{
+  GError *error = NULL;
+  gsize length;
+
+  if (storage[0]) {
+    g_free (storage[0]);
+    storage[0] = 0;
+  }
+
+  if (!filename)
+    return TRUE;
+
+  if (!g_file_get_contents (filename, storage, &length, &error)) {
+    GST_ELEMENT_ERROR (filter_shader, RESOURCE, NOT_FOUND, ("%s",
+            error->message), (NULL));
+    g_error_free (error);
+
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+static void
+gst_gl_filtershader_variables_parse (GstGLShader * shader, gchar * variables)
+{
+  gst_gl_shadervariables_parse (shader, variables, 0);
+}
+
+static gboolean
+gst_gl_filtershader_init_shader (GstGLFilter * filter)
+{
+
+  GstGLFilterShader *filtershader = GST_GL_FILTERSHADER (filter);
+
+  if (!gst_gl_filtershader_load_shader (filtershader, filtershader->filename,
+          &hfilter_fragment_source))
+    return FALSE;
+
+  //blocking call, wait the opengl thread has compiled the shader
+  if (!gst_gl_context_gen_shader (filter->context, 0, hfilter_fragment_source,
+          &filtershader->shader0))
+    return FALSE;
+
+
+  if (!gst_gl_filtershader_load_variables (filtershader,
+          filtershader->presetfile, &hfilter_fragment_variables[0]))
+    return FALSE;
+
+  filtershader->compiled = 1;
+
+  return TRUE;
+}
+
+static gboolean
+gst_gl_filtershader_filter_texture (GstGLFilter * filter, guint in_tex,
+    guint out_tex)
+{
+  GstGLFilterShader *filtershader = GST_GL_FILTERSHADER (filter);
+
+  gst_gl_filter_render_to_target (filter, TRUE, in_tex, out_tex,
+      gst_gl_filtershader_hcallback, filtershader);
+
+  return TRUE;
+}
+
+static void
+gst_gl_filtershader_hcallback (gint width, gint height, guint texture,
+    gpointer stuff)
+{
+  GstGLFilter *filter = GST_GL_FILTER (stuff);
+  GstGLFilterShader *filtershader = GST_GL_FILTERSHADER (filter);
+  GstGLFuncs *gl = filter->context->gl_vtable;
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+
+  gst_gl_shader_use (filtershader->shader0);
+
+  gl->ActiveTexture (GL_TEXTURE1);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+  gl->Disable (GL_TEXTURE_2D);
+
+  gst_gl_shader_set_uniform_1i (filtershader->shader0, "tex", 1);
+
+  if (hfilter_fragment_variables[0]) {
+    gst_gl_filtershader_variables_parse (filtershader->shader0,
+        hfilter_fragment_variables[0]);
+    g_free (hfilter_fragment_variables[0]);
+    hfilter_fragment_variables[0] = 0;
+  }
+  if (hfilter_fragment_variables[1]) {
+    gst_gl_filtershader_variables_parse (filtershader->shader0,
+        hfilter_fragment_variables[1]);
+    g_free (hfilter_fragment_variables[1]);
+    hfilter_fragment_variables[1] = 0;
+  }
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+
+}
diff --git a/ext/gl/gstglfiltershader.h b/ext/gl/gstglfiltershader.h
new file mode 100644 (file)
index 0000000..00fa587
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * glshader gstreamer plugin
+ * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
+ * Copyright (C) 2009 Luc Deschenaux <luc.deschenaux@freesurf.ch>
+ *
+ * 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.
+ */
+
+#ifndef _GST_GL_FILTERSHADER_H_
+#define _GST_GL_FILTERSHADER_H_
+
+#include <gst/gl/gstglfilter.h>
+
+#define GST_TYPE_GL_FILTERSHADER            (gst_gl_filtershader_get_type())
+#define GST_GL_FILTERSHADER(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_FILTERSHADER,GstGLFilterShader))
+#define GST_IS_GL_FILTERSHADER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_FILTERSHADER))
+#define GST_GL_FILTERSHADER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_FILTERSHADER,GstGLFilterShaderClass))
+#define GST_IS_GL_FILTERSHADER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_FILTERSHADER))
+#define GST_GL_FILTERSHADER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_FILTERSHADER,GstGLFilterShaderClass))
+
+typedef struct _GstGLFilterShader GstGLFilterShader;
+typedef struct _GstGLFilterShaderClass GstGLFilterShaderClass;
+
+struct _GstGLFilterShader
+{
+  GstGLFilter filter;
+  GstGLShader *shader0;
+  int compiled;
+  gchar *filename;
+  gchar *presetfile;
+  int texSet;
+
+};
+
+struct _GstGLFilterShaderClass
+{
+  GstGLFilterClass filter_class;
+};
+
+GType gst_gl_glfiltershader_get_type (void);
+
+#endif /* _GST_GL_FILTERSHADER_H_ */
diff --git a/ext/gl/gstglfiltersobel.c b/ext/gl/gstglfiltersobel.c
new file mode 100644 (file)
index 0000000..538f96e
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008-2010 Filippo Argiolas <filippo.argiolas@gmail.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.
+ */
+
+/**
+ * SECTION:element-glfiltersobel.
+ *
+ * Sobel Edge Detection.
+ *
+ * <refsect2>
+ * <title>Examples</title>
+ * |[
+ * gst-launch videotestsrc ! glupload ! glfiltersobel ! glimagesink
+ * ]|
+ * FBO (Frame Buffer Object) and GLSL (OpenGL Shading Language) are required.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstglfiltersobel.h"
+#include "effects/gstgleffectssources.h"
+
+enum
+{
+  PROP_0,
+  PROP_INVERT
+};
+
+#define GST_CAT_DEFAULT gst_gl_filtersobel_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+#define DEBUG_INIT \
+  GST_DEBUG_CATEGORY_INIT (gst_gl_filtersobel_debug, "glfiltersobel", 0, "glfiltersobel element");
+
+G_DEFINE_TYPE_WITH_CODE (GstGLFilterSobel, gst_gl_filtersobel,
+    GST_TYPE_GL_FILTER, DEBUG_INIT);
+
+static void gst_gl_filtersobel_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_gl_filtersobel_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static void gst_gl_filter_filtersobel_reset (GstGLFilter * filter);
+
+static gboolean gst_gl_filtersobel_init_shader (GstGLFilter * filter);
+static gboolean gst_gl_filtersobel_filter_texture (GstGLFilter * filter,
+    guint in_tex, guint out_tex);
+
+static void gst_gl_filtersobel_length (gint width, gint height, guint texture,
+    gpointer stuff);
+
+static void
+gst_gl_filtersobel_init_resources (GstGLFilter * filter)
+{
+  GstGLFilterSobel *filtersobel = GST_GL_FILTERSOBEL (filter);
+  GstGLFuncs *gl = filter->context->gl_vtable;
+  int i;
+
+  for (i = 0; i < 2; i++) {
+    gl->GenTextures (1, &filtersobel->midtexture[i]);
+    gl->BindTexture (GL_TEXTURE_2D, filtersobel->midtexture[i]);
+    gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8,
+        GST_VIDEO_INFO_WIDTH (&filter->out_info),
+        GST_VIDEO_INFO_HEIGHT (&filter->out_info),
+        0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+    gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+  }
+}
+
+static void
+gst_gl_filtersobel_reset_resources (GstGLFilter * filter)
+{
+  GstGLFilterSobel *filtersobel = GST_GL_FILTERSOBEL (filter);
+  GstGLFuncs *gl = filter->context->gl_vtable;
+  int i;
+
+  for (i = 0; i < 2; i++) {
+    gl->DeleteTextures (1, &filtersobel->midtexture[i]);
+  }
+}
+
+static void
+gst_gl_filtersobel_class_init (GstGLFilterSobelClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *element_class;
+
+  gobject_class = (GObjectClass *) klass;
+  element_class = GST_ELEMENT_CLASS (klass);
+
+  gobject_class->set_property = gst_gl_filtersobel_set_property;
+  gobject_class->get_property = gst_gl_filtersobel_get_property;
+
+  GST_GL_FILTER_CLASS (klass)->filter_texture =
+      gst_gl_filtersobel_filter_texture;
+  GST_GL_FILTER_CLASS (klass)->display_init_cb =
+      gst_gl_filtersobel_init_resources;
+  GST_GL_FILTER_CLASS (klass)->display_reset_cb =
+      gst_gl_filtersobel_reset_resources;
+  GST_GL_FILTER_CLASS (klass)->onInitFBO = gst_gl_filtersobel_init_shader;
+  GST_GL_FILTER_CLASS (klass)->onReset = gst_gl_filter_filtersobel_reset;
+
+  g_object_class_install_property (gobject_class,
+      PROP_INVERT,
+      g_param_spec_boolean ("invert",
+          "Invert the colors",
+          "Invert colors to get dark edges on bright background",
+          FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_metadata (element_class,
+      "Gstreamer OpenGL Sobel", "Filter/Effect/Video", "Sobel edge detection",
+      "Filippo Argiolas <filippo.argiolas@gmail.com>");
+}
+
+static void
+gst_gl_filtersobel_init (GstGLFilterSobel * filtersobel)
+{
+  int i;
+  filtersobel->hconv = NULL;
+  filtersobel->vconv = NULL;
+  filtersobel->invert = FALSE;
+  for (i = 0; i < 2; i++) {
+    filtersobel->midtexture[i] = 0;
+  }
+}
+
+static void
+gst_gl_filter_filtersobel_reset (GstGLFilter * filter)
+{
+  GstGLFilterSobel *filtersobel = GST_GL_FILTERSOBEL (filter);
+
+  //blocking call, wait the opengl thread has destroyed the shader
+  if (filtersobel->desat)
+    gst_gl_context_del_shader (filter->context, filtersobel->desat);
+  filtersobel->desat = NULL;
+
+  if (filtersobel->hconv)
+    gst_gl_context_del_shader (filter->context, filtersobel->hconv);
+  filtersobel->hconv = NULL;
+
+  if (filtersobel->vconv)
+    gst_gl_context_del_shader (filter->context, filtersobel->vconv);
+  filtersobel->vconv = NULL;
+
+  if (filtersobel->len)
+    gst_gl_context_del_shader (filter->context, filtersobel->len);
+  filtersobel->len = NULL;
+}
+
+static void
+gst_gl_filtersobel_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstGLFilterSobel *filtersobel = GST_GL_FILTERSOBEL (object);
+
+  switch (prop_id) {
+    case PROP_INVERT:
+      filtersobel->invert = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_gl_filtersobel_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstGLFilterSobel *filtersobel = GST_GL_FILTERSOBEL (object);
+
+  switch (prop_id) {
+    case PROP_INVERT:
+      g_value_set_boolean (value, filtersobel->invert);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_gl_filtersobel_init_shader (GstGLFilter * filter)
+{
+  GstGLFilterSobel *filtersobel = GST_GL_FILTERSOBEL (filter);
+  gboolean ret = TRUE;
+
+  //blocking call, wait the opengl thread has compiled the shader
+  ret =
+      gst_gl_context_gen_shader (filter->context, 0, desaturate_fragment_source,
+      &filtersobel->desat);
+  ret &=
+      gst_gl_context_gen_shader (filter->context, 0,
+      sep_sobel_hconv3_fragment_source, &filtersobel->hconv);
+  ret &=
+      gst_gl_context_gen_shader (filter->context, 0,
+      sep_sobel_vconv3_fragment_source, &filtersobel->vconv);
+  ret &=
+      gst_gl_context_gen_shader (filter->context, 0,
+      sep_sobel_length_fragment_source, &filtersobel->len);
+
+  return ret;
+}
+
+static gboolean
+gst_gl_filtersobel_filter_texture (GstGLFilter * filter, guint in_tex,
+    guint out_tex)
+{
+  GstGLFilterSobel *filtersobel = GST_GL_FILTERSOBEL (filter);
+
+  gst_gl_filter_render_to_target_with_shader (filter, TRUE, in_tex,
+      filtersobel->midtexture[0], filtersobel->desat);
+  gst_gl_filter_render_to_target_with_shader (filter, FALSE,
+      filtersobel->midtexture[0], filtersobel->midtexture[1],
+      filtersobel->hconv);
+  gst_gl_filter_render_to_target_with_shader (filter, FALSE,
+      filtersobel->midtexture[1], filtersobel->midtexture[0],
+      filtersobel->vconv);
+  gst_gl_filter_render_to_target (filter, FALSE, filtersobel->midtexture[0],
+      out_tex, gst_gl_filtersobel_length, filtersobel);
+
+  return TRUE;
+}
+
+static void
+gst_gl_filtersobel_length (gint width, gint height, guint texture,
+    gpointer stuff)
+{
+  GstGLFilter *filter = GST_GL_FILTER (stuff);
+  GstGLFuncs *gl = filter->context->gl_vtable;
+  GstGLFilterSobel *filtersobel = GST_GL_FILTERSOBEL (filter);
+
+  glMatrixMode (GL_PROJECTION);
+  glLoadIdentity ();
+
+  gst_gl_shader_use (filtersobel->len);
+
+  gl->ActiveTexture (GL_TEXTURE1);
+  gl->Enable (GL_TEXTURE_2D);
+  gl->BindTexture (GL_TEXTURE_2D, texture);
+  gl->Disable (GL_TEXTURE_2D);
+
+  gst_gl_shader_set_uniform_1i (filtersobel->len, "tex", 1);
+  gst_gl_shader_set_uniform_1i (filtersobel->len, "invert",
+      filtersobel->invert);
+
+  gst_gl_filter_draw_texture (filter, texture, width, height);
+}
diff --git a/ext/gl/gstglfiltersobel.h b/ext/gl/gstglfiltersobel.h
new file mode 100644 (file)
index 0000000..1a73891
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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.
+ */
+
+#ifndef _GST_GL_FILTERSOBEL_H_
+#define _GST_GL_FILTERSOBEL_H_
+
+#include <gst/gl/gstglfilter.h>
+
+#define GST_TYPE_GL_FILTERSOBEL            (gst_gl_filtersobel_get_type())
+#define GST_GL_FILTERSOBEL(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_FILTERSOBEL,GstGLFilterSobel))
+#define GST_IS_GL_FILTERSOBEL(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_FILTERSOBEL))
+#define GST_GL_FILTERSOBEL_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_FILTERSOBEL,GstGLFilterSobelClass))
+#define GST_IS_GL_FILTERSOBEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_FILTERSOBEL))
+#define GST_GL_FILTERSOBEL_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_FILTERSOBEL,GstGLFilterSobelClass))
+
+typedef struct _GstGLFilterSobel GstGLFilterSobel;
+typedef struct _GstGLFilterSobelClass GstGLFilterSobelClass;
+
+struct _GstGLFilterSobel
+{
+  GstGLFilter filter;
+  GstGLShader *hconv;
+  GstGLShader *vconv;
+  GstGLShader *len;
+  GstGLShader *desat;
+
+  GLuint midtexture[5];
+
+  gboolean invert;
+};
+
+struct _GstGLFilterSobelClass
+{
+  GstGLFilterClass filter_class;
+};
+
+GType gst_gl_glfiltersobel_get_type (void);
+
+#endif /* _GST_GL_FILTERSOBEL_H_ */
diff --git a/ext/gl/gstglimagesink.c b/ext/gl/gstglimagesink.c
new file mode 100644 (file)
index 0000000..f49422c
--- /dev/null
@@ -0,0 +1,1206 @@
+/*
+ * GStreamer
+ * Copyright (C) 2003 Julien Moutte <julien@moutte.net>
+ * Copyright (C) 2005,2006,2007 David A. Schleef <ds@schleef.org>
+ * Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.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.
+ */
+
+/**
+ * SECTION:element-glimagesink
+ *
+ * glimagesink renders video frames to a drawable on a local or remote
+ * display using OpenGL. This element can receive a Window ID from the
+ * application through the VideoOverlay interface and will then render video
+ * frames in this drawable.
+ * If no Window ID was provided by the application, the element will
+ * create its own internal window and render into it.
+ *
+ * <refsect2>
+ * <title>Scaling</title>
+ * <para>
+ * Depends on the driver, OpenGL handles hardware accelerated
+ * scaling of video frames. This means that the element will just accept
+ * incoming video frames no matter their geometry and will then put them to the
+ * drawable scaling them on the fly. Using the #GstGLImageSink:force-aspect-ratio
+ * property it is possible to enforce scaling with a constant aspect ratio,
+ * which means drawing black borders around the video frame.
+ * </para>
+ * </refsect2>
+ * <refsect2>
+ * <title>Events</title>
+ * <para>
+ * Through the gl thread, glimagesink handle some events coming from the drawable
+ * to manage its appearance even when the data is not flowing (GST_STATE_PAUSED).
+ * That means that even when the element is paused, it will receive expose events
+ * from the drawable and draw the latest frame with correct borders/aspect-ratio.
+ * </para>
+ * </refsect2>
+ * <refsect2>
+ * <title>Examples</title>
+ * |[
+ * gst-launch -v videotestsrc ! "video/x-raw-rgb" ! glimagesink
+ * ]| A pipeline to test hardware scaling.
+ * No special opengl extension is used in this pipeline, that's why it should work
+ * with OpenGL >= 1.1. That's the case if you are using the MESA3D driver v1.3.
+ * |[
+ * gst-launch -v videotestsrc ! "video/x-raw-yuv, format=(fourcc)I420" ! glimagesink
+ * ]| A pipeline to test hardware scaling and hardware colorspace conversion.
+ * When your driver supports GLSL (OpenGL Shading Language needs OpenGL >= 2.1),
+ * the 4 following format YUY2, UYVY, I420, YV12 and AYUV are converted to RGB32
+ * through some fragment shaders and using one framebuffer (FBO extension OpenGL >= 1.4).
+ * If your driver does not support GLSL but supports MESA_YCbCr extension then
+ * the you can use YUY2 and UYVY. In this case the colorspace conversion is automatically
+ * made when loading the texture and therefore no framebuffer is used.
+ * |[
+ * gst-launch -v gltestsrc ! glimagesink
+ * ]| A pipeline 100% OpenGL.
+ * No special opengl extension is used in this pipeline, that's why it should work
+ * with OpenGL >= 1.1. That's the case if you are using the MESA3D driver v1.3.
+ * |[
+ * gst-plugins-gl/tests/examples/generic/cube
+ * ]| The graphic FPS scene can be greater than the input video FPS.
+ * The graphic scene can be written from a client code through the
+ * two glfilterapp properties.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/video/videooverlay.h>
+
+#include "gstglimagesink.h"
+
+GST_DEBUG_CATEGORY (gst_debug_glimage_sink);
+#define GST_CAT_DEFAULT gst_debug_glimage_sink
+
+#define GST_GLIMAGE_SINK_GET_LOCK(glsink) \
+  (GST_GLIMAGE_SINK(glsink)->drawing_lock)
+#define GST_GLIMAGE_SINK_LOCK(glsink) \
+  (g_mutex_lock(&GST_GLIMAGE_SINK_GET_LOCK (glsink)))
+#define GST_GLIMAGE_SINK_UNLOCK(glsink) \
+  (g_mutex_unlock(&GST_GLIMAGE_SINK_GET_LOCK (glsink)))
+
+#define USING_OPENGL(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_OPENGL)
+#define USING_OPENGL3(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_OPENGL3)
+#define USING_GLES(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES)
+#define USING_GLES2(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES2)
+#define USING_GLES3(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES3)
+
+#if GST_GL_HAVE_GLES2
+static void gst_glimage_sink_thread_init_redisplay (GstGLImageSink * gl_sink);
+#endif
+static void gst_glimage_sink_on_close (GstGLImageSink * gl_sink);
+static void gst_glimage_sink_on_resize (const GstGLImageSink * gl_sink,
+    gint width, gint height);
+static void gst_glimage_sink_on_draw (const GstGLImageSink * gl_sink);
+static gboolean gst_glimage_sink_redisplay (GstGLImageSink * gl_sink);
+
+static void gst_glimage_sink_finalize (GObject * object);
+static void gst_glimage_sink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * param_spec);
+static void gst_glimage_sink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * param_spec);
+
+static gboolean gst_glimage_sink_stop (GstBaseSink * bsink);
+
+static gboolean gst_glimage_sink_query (GstBaseSink * bsink, GstQuery * query);
+static void gst_glimage_sink_set_context (GstElement * element,
+    GstContext * context);
+
+static GstStateChangeReturn
+gst_glimage_sink_change_state (GstElement * element, GstStateChange transition);
+
+static void gst_glimage_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
+    GstClockTime * start, GstClockTime * end);
+static gboolean gst_glimage_sink_set_caps (GstBaseSink * bsink, GstCaps * caps);
+static GstFlowReturn gst_glimage_sink_render (GstBaseSink * bsink,
+    GstBuffer * buf);
+static gboolean gst_glimage_sink_propose_allocation (GstBaseSink * bsink,
+    GstQuery * query);
+
+static void gst_glimage_sink_video_overlay_init (GstVideoOverlayInterface *
+    iface);
+static void gst_glimage_sink_set_window_handle (GstVideoOverlay * overlay,
+    guintptr id);
+static void gst_glimage_sink_expose (GstVideoOverlay * overlay);
+
+
+#if GST_GL_HAVE_GLES2
+/* *INDENT-OFF* */
+static const gchar *redisplay_vertex_shader_str_gles2 =
+      "attribute vec4 a_position;   \n"
+      "attribute vec2 a_texCoord;   \n"
+      "varying vec2 v_texCoord;     \n"
+      "void main()                  \n"
+      "{                            \n"
+      "   gl_Position = a_position; \n"
+      "   v_texCoord = a_texCoord;  \n"
+      "}                            \n";
+
+static const gchar *redisplay_fragment_shader_str_gles2 =
+      "precision mediump float;                            \n"
+      "varying vec2 v_texCoord;                            \n"
+      "uniform sampler2D s_texture;                        \n"
+      "void main()                                         \n"
+      "{                                                   \n"
+      "  gl_FragColor = texture2D( s_texture, v_texCoord );\n"
+      "}                                                   \n";
+/* *INDENT-ON* */
+#endif
+
+static GstStaticPadTemplate gst_glimage_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (GST_GL_UPLOAD_FORMATS) "; "
+        GST_VIDEO_CAPS_MAKE_WITH_FEATURES
+        (GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META,
+            GST_GL_UPLOAD_FORMATS))
+    );
+
+enum
+{
+  ARG_0,
+  ARG_DISPLAY,
+  PROP_CLIENT_RESHAPE_CALLBACK,
+  PROP_CLIENT_DRAW_CALLBACK,
+  PROP_CLIENT_DATA,
+  PROP_FORCE_ASPECT_RATIO,
+  PROP_PIXEL_ASPECT_RATIO,
+  PROP_OTHER_CONTEXT
+};
+
+#define gst_glimage_sink_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstGLImageSink, gst_glimage_sink,
+    GST_TYPE_VIDEO_SINK, G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_OVERLAY,
+        gst_glimage_sink_video_overlay_init);
+    GST_DEBUG_CATEGORY_INIT (gst_debug_glimage_sink, "glimagesink", 0,
+        "OpenGL Video Sink"));
+
+static void
+gst_glimage_sink_class_init (GstGLImageSinkClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstBaseSinkClass *gstbasesink_class;
+  GstElementClass *element_class;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstbasesink_class = (GstBaseSinkClass *) klass;
+  element_class = GST_ELEMENT_CLASS (klass);
+
+  gobject_class->set_property = gst_glimage_sink_set_property;
+  gobject_class->get_property = gst_glimage_sink_get_property;
+
+  g_object_class_install_property (gobject_class, ARG_DISPLAY,
+      g_param_spec_string ("display", "Display", "Display name",
+          NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_CLIENT_RESHAPE_CALLBACK,
+      g_param_spec_pointer ("client-reshape-callback",
+          "Client reshape callback",
+          "Define a custom reshape callback in a client code",
+          G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_CLIENT_DRAW_CALLBACK,
+      g_param_spec_pointer ("client-draw-callback", "Client draw callback",
+          "Define a custom draw callback in a client code",
+          G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_CLIENT_DATA,
+      g_param_spec_pointer ("client-data", "Client data",
+          "Pass data to the draw and reshape callbacks",
+          G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
+      g_param_spec_boolean ("force-aspect-ratio",
+          "Force aspect ratio",
+          "When enabled, scaling will respect original aspect ratio", FALSE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO,
+      gst_param_spec_fraction ("pixel-aspect-ratio", "Pixel Aspect Ratio",
+          "The pixel aspect ratio of the device", 0, 1, G_MAXINT, 1, 0, 1,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_metadata (element_class, "OpenGL video sink",
+      "Sink/Video", "A videosink based on OpenGL",
+      "Julien Isorce <julien.isorce@gmail.com>");
+
+  g_object_class_install_property (gobject_class, PROP_OTHER_CONTEXT,
+      g_param_spec_object ("other-context",
+          "External OpenGL context",
+          "Give an external OpenGL context with which to share textures",
+          GST_GL_TYPE_CONTEXT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&gst_glimage_sink_template));
+
+  gobject_class->finalize = gst_glimage_sink_finalize;
+
+  gstelement_class->change_state = gst_glimage_sink_change_state;
+  gstelement_class->set_context = gst_glimage_sink_set_context;
+  gstbasesink_class->query = GST_DEBUG_FUNCPTR (gst_glimage_sink_query);
+  gstbasesink_class->set_caps = gst_glimage_sink_set_caps;
+  gstbasesink_class->get_times = gst_glimage_sink_get_times;
+  gstbasesink_class->preroll = gst_glimage_sink_render;
+  gstbasesink_class->render = gst_glimage_sink_render;
+  gstbasesink_class->propose_allocation = gst_glimage_sink_propose_allocation;
+  gstbasesink_class->stop = gst_glimage_sink_stop;
+}
+
+static void
+gst_glimage_sink_init (GstGLImageSink * glimage_sink)
+{
+  glimage_sink->display_name = NULL;
+  glimage_sink->window_id = 0;
+  glimage_sink->new_window_id = 0;
+  glimage_sink->display = NULL;
+  glimage_sink->clientReshapeCallback = NULL;
+  glimage_sink->clientDrawCallback = NULL;
+  glimage_sink->client_data = NULL;
+  glimage_sink->keep_aspect_ratio = FALSE;
+  glimage_sink->par_n = 0;
+  glimage_sink->par_d = 1;
+  glimage_sink->pool = NULL;
+  glimage_sink->redisplay_texture = 0;
+
+  g_mutex_init (&glimage_sink->drawing_lock);
+}
+
+static void
+gst_glimage_sink_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstGLImageSink *glimage_sink;
+
+  g_return_if_fail (GST_IS_GLIMAGE_SINK (object));
+
+  glimage_sink = GST_GLIMAGE_SINK (object);
+
+  switch (prop_id) {
+    case ARG_DISPLAY:
+    {
+      g_free (glimage_sink->display_name);
+      glimage_sink->display_name = g_strdup (g_value_get_string (value));
+      break;
+    }
+    case PROP_CLIENT_RESHAPE_CALLBACK:
+    {
+      glimage_sink->clientReshapeCallback = g_value_get_pointer (value);
+      break;
+    }
+    case PROP_CLIENT_DRAW_CALLBACK:
+    {
+      glimage_sink->clientDrawCallback = g_value_get_pointer (value);
+      break;
+    }
+    case PROP_CLIENT_DATA:
+    {
+      glimage_sink->client_data = g_value_get_pointer (value);
+      break;
+    }
+    case PROP_FORCE_ASPECT_RATIO:
+    {
+      glimage_sink->keep_aspect_ratio = g_value_get_boolean (value);
+      break;
+    }
+    case PROP_PIXEL_ASPECT_RATIO:
+    {
+      glimage_sink->par_n = gst_value_get_fraction_numerator (value);
+      glimage_sink->par_d = gst_value_get_fraction_denominator (value);
+      break;
+    }
+    case PROP_OTHER_CONTEXT:
+    {
+      if (glimage_sink->other_context)
+        gst_object_unref (glimage_sink->other_context);
+      glimage_sink->other_context = g_value_dup_object (value);
+      break;
+    }
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_glimage_sink_finalize (GObject * object)
+{
+  GstGLImageSink *glimage_sink;
+
+  g_return_if_fail (GST_IS_GLIMAGE_SINK (object));
+
+  glimage_sink = GST_GLIMAGE_SINK (object);
+
+  g_mutex_clear (&glimage_sink->drawing_lock);
+
+  g_free (glimage_sink->display_name);
+
+  GST_DEBUG ("finalized");
+}
+
+static void
+gst_glimage_sink_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstGLImageSink *glimage_sink;
+
+  g_return_if_fail (GST_IS_GLIMAGE_SINK (object));
+
+  glimage_sink = GST_GLIMAGE_SINK (object);
+
+  switch (prop_id) {
+    case ARG_DISPLAY:
+      g_value_set_string (value, glimage_sink->display_name);
+      break;
+    case PROP_FORCE_ASPECT_RATIO:
+      g_value_set_boolean (value, glimage_sink->keep_aspect_ratio);
+      break;
+    case PROP_PIXEL_ASPECT_RATIO:
+      gst_value_set_fraction (value, glimage_sink->par_n, glimage_sink->par_d);
+      break;
+    case PROP_OTHER_CONTEXT:
+      g_value_set_object (value, glimage_sink->other_context);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+_ensure_gl_setup (GstGLImageSink * gl_sink)
+{
+  GError *error = NULL;
+
+  if (!gst_gl_ensure_display (gl_sink, &gl_sink->display))
+    return FALSE;
+
+  if (!gl_sink->context) {
+    gl_sink->context = gst_gl_context_new (gl_sink->display);
+    if (!gst_gl_context_create (gl_sink->context, gl_sink->other_context,
+            &error))
+      goto context_error;
+  }
+
+  if (!gl_sink->upload) {
+    gl_sink->upload = gst_gl_upload_new (gl_sink->context);
+    if (!gst_gl_upload_init_format (gl_sink->upload, gl_sink->info,
+            gl_sink->info))
+      goto upload_error;
+  }
+
+  return TRUE;
+
+upload_error:
+  {
+    GST_ELEMENT_ERROR (gl_sink, RESOURCE, NOT_FOUND, ("Failed to init upload"),
+        (NULL));
+    return FALSE;
+  }
+context_error:
+  {
+    GST_ELEMENT_ERROR (gl_sink, RESOURCE, NOT_FOUND, ("%s", error->message),
+        (NULL));
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_glimage_sink_query (GstBaseSink * bsink, GstQuery * query)
+{
+  GstGLImageSink *glimage_sink = GST_GLIMAGE_SINK (bsink);
+  gboolean res = FALSE;
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CONTEXT:
+    {
+      return gst_gl_handle_context_query ((GstElement *) glimage_sink, query,
+          &glimage_sink->display);
+      break;
+    }
+    default:
+      res = GST_BASE_SINK_CLASS (parent_class)->query (bsink, query);
+      break;
+  }
+
+  return res;
+}
+
+static void
+gst_glimage_sink_cleanup_glthread (GstGLImageSink * gl_sink)
+{
+#if GST_GL_HAVE_GLES2
+  if (gl_sink->redisplay_shader) {
+    gst_object_unref (gl_sink->redisplay_shader);
+    gl_sink->redisplay_shader = NULL;
+  }
+#endif
+}
+
+/*
+ * GstElement methods
+ */
+
+static gboolean
+gst_glimage_sink_stop (GstBaseSink * bsink)
+{
+  GstGLImageSink *glimage_sink = GST_GLIMAGE_SINK (bsink);
+
+  if (glimage_sink->pool) {
+    gst_object_unref (glimage_sink->pool);
+    glimage_sink->pool = NULL;
+  }
+
+  return TRUE;
+}
+
+static void
+gst_glimage_sink_set_context (GstElement * element, GstContext * context)
+{
+  GstGLImageSink *gl_sink = GST_GLIMAGE_SINK (element);
+
+  gst_gl_handle_set_context (element, context, &gl_sink->display);
+}
+
+static GstStateChangeReturn
+gst_glimage_sink_change_state (GstElement * element, GstStateChange transition)
+{
+  GstGLImageSink *glimage_sink;
+  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+
+  GST_DEBUG ("change state");
+
+  glimage_sink = GST_GLIMAGE_SINK (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      g_atomic_int_set (&glimage_sink->to_quit, 0);
+      if (!glimage_sink->display) {
+        GstGLWindow *window;
+        GError *error = NULL;
+
+        if (!gst_gl_ensure_display (glimage_sink, &glimage_sink->display))
+          return GST_STATE_CHANGE_FAILURE;
+
+        glimage_sink->context = gst_gl_context_new (glimage_sink->display);
+        window = gst_gl_context_get_window (glimage_sink->context);
+
+        if (!glimage_sink->window_id && !glimage_sink->new_window_id)
+          gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY
+              (glimage_sink));
+
+        if (glimage_sink->window_id != glimage_sink->new_window_id) {
+          glimage_sink->window_id = glimage_sink->new_window_id;
+          gst_gl_window_set_window_handle (window, glimage_sink->window_id);
+        }
+
+        if (!gst_gl_context_create (glimage_sink->context,
+                glimage_sink->other_context, &error)) {
+          GST_ELEMENT_ERROR (glimage_sink, RESOURCE, NOT_FOUND, ("%s",
+                  error->message), (NULL));
+
+          if (glimage_sink->display) {
+            gst_object_unref (glimage_sink->display);
+            glimage_sink->display = NULL;
+          }
+          gst_object_unref (glimage_sink->context);
+          gst_object_unref (window);
+
+          return GST_STATE_CHANGE_FAILURE;
+        }
+
+        /* setup callbacks */
+        gst_gl_window_set_resize_callback (window,
+            GST_GL_WINDOW_RESIZE_CB (gst_glimage_sink_on_resize),
+            gst_object_ref (glimage_sink), (GDestroyNotify) gst_object_unref);
+        gst_gl_window_set_draw_callback (window,
+            GST_GL_WINDOW_CB (gst_glimage_sink_on_draw),
+            gst_object_ref (glimage_sink), (GDestroyNotify) gst_object_unref);
+        gst_gl_window_set_close_callback (window,
+            GST_GL_WINDOW_CB (gst_glimage_sink_on_close),
+            gst_object_ref (glimage_sink), (GDestroyNotify) gst_object_unref);
+
+        gst_object_unref (window);
+      }
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+  if (ret == GST_STATE_CHANGE_FAILURE)
+    return ret;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+    {
+      /* mark the redisplay_texture as unavailable (=0)
+       * to avoid drawing
+       */
+      GST_GLIMAGE_SINK_LOCK (glimage_sink);
+      glimage_sink->redisplay_texture = 0;
+      GST_GLIMAGE_SINK_UNLOCK (glimage_sink);
+
+      if (glimage_sink->upload) {
+        gst_object_unref (glimage_sink->upload);
+        glimage_sink->upload = NULL;
+      }
+
+      glimage_sink->window_id = 0;
+      //but do not reset glimage_sink->new_window_id
+
+      if (glimage_sink->pool) {
+        gst_buffer_pool_set_active (glimage_sink->pool, FALSE);
+        gst_object_unref (glimage_sink->pool);
+        glimage_sink->pool = NULL;
+      }
+
+      GST_VIDEO_SINK_WIDTH (glimage_sink) = 1;
+      GST_VIDEO_SINK_HEIGHT (glimage_sink) = 1;
+      if (glimage_sink->context) {
+        GstGLWindow *window = gst_gl_context_get_window (glimage_sink->context);
+
+        gst_gl_window_send_message (window,
+            GST_GL_WINDOW_CB (gst_glimage_sink_cleanup_glthread), glimage_sink);
+
+        gst_gl_window_set_resize_callback (window, NULL, NULL, NULL);
+        gst_gl_window_set_draw_callback (window, NULL, NULL, NULL);
+        gst_gl_window_set_close_callback (window, NULL, NULL, NULL);
+
+        gst_object_unref (window);
+        gst_object_unref (glimage_sink->context);
+        glimage_sink->context = NULL;
+        gst_object_unref (glimage_sink->display);
+        glimage_sink->display = NULL;
+      }
+      break;
+    }
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static void
+gst_glimage_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
+    GstClockTime * start, GstClockTime * end)
+{
+  GstGLImageSink *glimagesink;
+
+  glimagesink = GST_GLIMAGE_SINK (bsink);
+
+  if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
+    *start = GST_BUFFER_TIMESTAMP (buf);
+    if (GST_BUFFER_DURATION_IS_VALID (buf))
+      *end = *start + GST_BUFFER_DURATION (buf);
+    else {
+      if (GST_VIDEO_INFO_FPS_N (&glimagesink->info) > 0) {
+        *end = *start +
+            gst_util_uint64_scale_int (GST_SECOND,
+            GST_VIDEO_INFO_FPS_D (&glimagesink->info),
+            GST_VIDEO_INFO_FPS_N (&glimagesink->info));
+      }
+    }
+  }
+}
+
+static gboolean
+gst_glimage_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
+{
+  GstGLImageSink *glimage_sink;
+  gint width;
+  gint height;
+  gboolean ok;
+  gint par_n, par_d;
+  gint display_par_n, display_par_d;
+  guint display_ratio_num, display_ratio_den;
+  GstVideoInfo vinfo;
+  GstStructure *structure;
+  GstBufferPool *newpool, *oldpool;
+
+  GST_DEBUG ("set caps with %" GST_PTR_FORMAT, caps);
+
+  glimage_sink = GST_GLIMAGE_SINK (bsink);
+
+  ok = gst_video_info_from_caps (&vinfo, caps);
+  if (!ok)
+    return FALSE;
+
+  width = GST_VIDEO_INFO_WIDTH (&vinfo);
+  height = GST_VIDEO_INFO_HEIGHT (&vinfo);
+
+  if (glimage_sink->tex_id)
+    gst_gl_context_del_texture (glimage_sink->context, &glimage_sink->tex_id);
+  //FIXME: this texture seems to be never deleted when going to STATE_NULL
+  gst_gl_context_gen_texture (glimage_sink->context, &glimage_sink->tex_id,
+      GST_VIDEO_INFO_FORMAT (&vinfo), width, height);
+
+  par_n = GST_VIDEO_INFO_PAR_N (&vinfo);
+  par_d = GST_VIDEO_INFO_PAR_D (&vinfo);
+
+  if (!par_n)
+    par_n = 1;
+
+  /* get display's PAR */
+  if (glimage_sink->par_n != 0 && glimage_sink->par_d != 0) {
+    display_par_n = glimage_sink->par_n;
+    display_par_d = glimage_sink->par_d;
+  } else {
+    display_par_n = 1;
+    display_par_d = 1;
+  }
+
+  ok = gst_video_calculate_display_ratio (&display_ratio_num,
+      &display_ratio_den, width, height, par_n, par_d, display_par_n,
+      display_par_d);
+
+  if (!ok)
+    return FALSE;
+
+  GST_TRACE ("PAR: %u/%u DAR:%u/%u", par_n, par_d, display_par_n,
+      display_par_d);
+
+  if (height % display_ratio_den == 0) {
+    GST_DEBUG ("keeping video height");
+    GST_VIDEO_SINK_WIDTH (glimage_sink) = (guint)
+        gst_util_uint64_scale_int (height, display_ratio_num,
+        display_ratio_den);
+    GST_VIDEO_SINK_HEIGHT (glimage_sink) = height;
+  } else if (width % display_ratio_num == 0) {
+    GST_DEBUG ("keeping video width");
+    GST_VIDEO_SINK_WIDTH (glimage_sink) = width;
+    GST_VIDEO_SINK_HEIGHT (glimage_sink) = (guint)
+        gst_util_uint64_scale_int (width, display_ratio_den, display_ratio_num);
+  } else {
+    GST_DEBUG ("approximating while keeping video height");
+    GST_VIDEO_SINK_WIDTH (glimage_sink) = (guint)
+        gst_util_uint64_scale_int (height, display_ratio_num,
+        display_ratio_den);
+    GST_VIDEO_SINK_HEIGHT (glimage_sink) = height;
+  }
+  GST_DEBUG ("scaling to %dx%d", GST_VIDEO_SINK_WIDTH (glimage_sink),
+      GST_VIDEO_SINK_HEIGHT (glimage_sink));
+
+  glimage_sink->info = vinfo;
+
+  newpool = gst_gl_buffer_pool_new (glimage_sink->context);
+  structure = gst_buffer_pool_get_config (newpool);
+  gst_buffer_pool_config_set_params (structure, caps, vinfo.size, 2, 0);
+  gst_buffer_pool_set_config (newpool, structure);
+
+  oldpool = glimage_sink->pool;
+  /* we don't activate the pool yet, this will be done by downstream after it
+   * has configured the pool. If downstream does not want our pool we will
+   * activate it when we render into it */
+  glimage_sink->pool = newpool;
+
+  /* unref the old sink */
+  if (oldpool) {
+    /* we don't deactivate, some elements might still be using it, it will
+     * be deactivated when the last ref is gone */
+    gst_object_unref (oldpool);
+  }
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_glimage_sink_render (GstBaseSink * bsink, GstBuffer * buf)
+{
+  GstGLImageSink *glimage_sink;
+  guint tex_id;
+
+  GST_TRACE ("rendering buffer:%p", buf);
+
+  glimage_sink = GST_GLIMAGE_SINK (bsink);
+
+  if (GST_VIDEO_SINK_WIDTH (glimage_sink) < 1 ||
+      GST_VIDEO_SINK_HEIGHT (glimage_sink) < 1) {
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
+
+  if (!_ensure_gl_setup (glimage_sink))
+    return GST_FLOW_NOT_NEGOTIATED;
+
+  if (!gst_gl_upload_perform_with_buffer (glimage_sink->upload, buf, &tex_id))
+    goto upload_failed;
+
+  if (glimage_sink->window_id != glimage_sink->new_window_id) {
+    GstGLWindow *window = gst_gl_context_get_window (glimage_sink->context);
+
+    glimage_sink->window_id = glimage_sink->new_window_id;
+    gst_gl_window_set_window_handle (window, glimage_sink->window_id);
+
+    gst_object_unref (window);
+  }
+
+  GST_TRACE ("redisplay texture:%u of size:%ux%u, window size:%ux%u", tex_id,
+      GST_VIDEO_INFO_WIDTH (&glimage_sink->info),
+      GST_VIDEO_INFO_HEIGHT (&glimage_sink->info),
+      GST_VIDEO_SINK_WIDTH (glimage_sink),
+      GST_VIDEO_SINK_HEIGHT (glimage_sink));
+
+  /* Avoid to release the texture while drawing */
+  GST_GLIMAGE_SINK_LOCK (glimage_sink);
+  glimage_sink->redisplay_texture = tex_id;
+  GST_GLIMAGE_SINK_UNLOCK (glimage_sink);
+
+  /* Ask the underlying window to redraw its content */
+  if (!gst_glimage_sink_redisplay (glimage_sink))
+    goto redisplay_failed;
+
+  GST_TRACE ("post redisplay");
+
+  if (g_atomic_int_get (&glimage_sink->to_quit) != 0) {
+    GST_ELEMENT_ERROR (glimage_sink, RESOURCE, NOT_FOUND,
+        ("%s", gst_gl_context_get_error ()), (NULL));
+    gst_gl_upload_release_buffer (glimage_sink->upload);
+    return GST_FLOW_ERROR;
+  }
+
+  gst_gl_upload_release_buffer (glimage_sink->upload);
+  return GST_FLOW_OK;
+
+/* ERRORS */
+redisplay_failed:
+  {
+    gst_gl_upload_release_buffer (glimage_sink->upload);
+    GST_ELEMENT_ERROR (glimage_sink, RESOURCE, NOT_FOUND,
+        ("%s", gst_gl_context_get_error ()), (NULL));
+    return GST_FLOW_ERROR;
+  }
+
+upload_failed:
+  {
+    GST_ELEMENT_ERROR (glimage_sink, RESOURCE, NOT_FOUND,
+        ("%s", "Failed to upload format"), (NULL));
+    return FALSE;
+  }
+}
+
+
+static void
+gst_glimage_sink_video_overlay_init (GstVideoOverlayInterface * iface)
+{
+  iface->set_window_handle = gst_glimage_sink_set_window_handle;
+  iface->expose = gst_glimage_sink_expose;
+}
+
+
+static void
+gst_glimage_sink_set_window_handle (GstVideoOverlay * overlay, guintptr id)
+{
+  GstGLImageSink *glimage_sink = GST_GLIMAGE_SINK (overlay);
+  guintptr window_id = (guintptr) id;
+
+  g_return_if_fail (GST_IS_GLIMAGE_SINK (overlay));
+
+  GST_DEBUG ("set_xwindow_id %" G_GUINT64_FORMAT, (guint64) window_id);
+
+  glimage_sink->new_window_id = window_id;
+}
+
+
+static void
+gst_glimage_sink_expose (GstVideoOverlay * overlay)
+{
+  GstGLImageSink *glimage_sink = GST_GLIMAGE_SINK (overlay);
+
+  /* redisplay opengl scene */
+  if (glimage_sink->display && glimage_sink->window_id) {
+
+    if (glimage_sink->window_id != glimage_sink->new_window_id) {
+      GstGLWindow *window = gst_gl_context_get_window (glimage_sink->context);
+
+      glimage_sink->window_id = glimage_sink->new_window_id;
+      gst_gl_window_set_window_handle (window, glimage_sink->window_id);
+
+      gst_object_unref (window);
+    }
+
+    gst_glimage_sink_redisplay (glimage_sink);
+  }
+}
+
+static gboolean
+gst_glimage_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
+{
+  GstGLImageSink *glimage_sink = GST_GLIMAGE_SINK (bsink);
+  GstBufferPool *pool;
+  GstStructure *config;
+  GstCaps *caps;
+  guint size;
+  gboolean need_pool;
+  GstStructure *gl_context;
+  gchar *platform, *gl_apis;
+  gpointer handle;
+
+  if (!_ensure_gl_setup (glimage_sink))
+    return FALSE;
+
+  gst_query_parse_allocation (query, &caps, &need_pool);
+
+  if (caps == NULL)
+    goto no_caps;
+
+  if ((pool = glimage_sink->pool))
+    gst_object_ref (pool);
+
+  if (pool != NULL) {
+    GstCaps *pcaps;
+
+    /* we had a pool, check caps */
+    GST_DEBUG_OBJECT (glimage_sink, "check existing pool caps");
+    config = gst_buffer_pool_get_config (pool);
+    gst_buffer_pool_config_get_params (config, &pcaps, &size, NULL, NULL);
+
+    if (!gst_caps_is_equal (caps, pcaps)) {
+      GST_DEBUG_OBJECT (glimage_sink, "pool has different caps");
+      /* different caps, we can't use this pool */
+      gst_object_unref (pool);
+      pool = NULL;
+    }
+    gst_structure_free (config);
+  }
+
+  if (pool == NULL && need_pool) {
+    GstVideoInfo info;
+
+    if (!gst_video_info_from_caps (&info, caps))
+      goto invalid_caps;
+
+    GST_DEBUG_OBJECT (glimage_sink, "create new pool");
+    pool = gst_gl_buffer_pool_new (glimage_sink->context);
+
+    /* the normal size of a frame */
+    size = info.size;
+
+    config = gst_buffer_pool_get_config (pool);
+    gst_buffer_pool_config_set_params (config, caps, size, 0, 0);
+    if (!gst_buffer_pool_set_config (pool, config))
+      goto config_failed;
+  }
+  /* we need at least 2 buffer because we hold on to the last one */
+  gst_query_add_allocation_pool (query, pool, size, 2, 0);
+
+  /* we also support various metadata */
+  gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, 0);
+
+  gst_object_unref (pool);
+
+  gl_apis =
+      gst_gl_api_to_string (gst_gl_context_get_gl_api (glimage_sink->context));
+  platform =
+      gst_gl_platform_to_string (gst_gl_context_get_gl_platform
+      (glimage_sink->context));
+  handle = (gpointer) gst_gl_context_get_gl_context (glimage_sink->context);
+
+  gl_context =
+      gst_structure_new ("GstVideoGLTextureUploadMeta", "gst.gl.GstGLContext",
+      GST_GL_TYPE_CONTEXT, glimage_sink->context, "gst.gl.context.handle",
+      G_TYPE_POINTER, handle, "gst.gl.context.type", G_TYPE_STRING, platform,
+      "gst.gl.context.apis", G_TYPE_STRING, gl_apis, NULL);
+  gst_query_add_allocation_meta (query,
+      GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, gl_context);
+
+  g_free (gl_apis);
+  g_free (platform);
+  gst_structure_free (gl_context);
+
+  return TRUE;
+
+  /* ERRORS */
+no_caps:
+  {
+    GST_DEBUG_OBJECT (bsink, "no caps specified");
+    return FALSE;
+  }
+invalid_caps:
+  {
+    GST_DEBUG_OBJECT (bsink, "invalid caps specified");
+    return FALSE;
+  }
+config_failed:
+  {
+    GST_DEBUG_OBJECT (bsink, "failed setting config");
+    return FALSE;
+  }
+}
+
+#if GST_GL_HAVE_GLES2
+/* Called in the gl thread */
+static void
+gst_glimage_sink_thread_init_redisplay (GstGLImageSink * gl_sink)
+{
+  GError *error = NULL;
+  gl_sink->redisplay_shader = gst_gl_shader_new (gl_sink->context);
+
+  gst_gl_shader_set_vertex_source (gl_sink->redisplay_shader,
+      redisplay_vertex_shader_str_gles2);
+  gst_gl_shader_set_fragment_source (gl_sink->redisplay_shader,
+      redisplay_fragment_shader_str_gles2);
+
+  gst_gl_shader_compile (gl_sink->redisplay_shader, &error);
+  if (error) {
+    gst_gl_context_set_error (gl_sink->context, "%s", error->message);
+    g_error_free (error);
+    error = NULL;
+    gst_gl_context_clear_shader (gl_sink->context);
+  } else {
+    gl_sink->redisplay_attr_position_loc =
+        gst_gl_shader_get_attribute_location (gl_sink->redisplay_shader,
+        "a_position");
+    gl_sink->redisplay_attr_texture_loc =
+        gst_gl_shader_get_attribute_location (gl_sink->redisplay_shader,
+        "a_texCoord");
+  }
+}
+#endif
+
+static void
+gst_glimage_sink_on_resize (const GstGLImageSink * gl_sink, gint width,
+    gint height)
+{
+  /* Here gl_sink members (ex:gl_sink->info) have a life time of set_caps.
+   * It means that they cannot not change between two set_caps
+   */
+  const GstGLFuncs *gl = gl_sink->context->gl_vtable;
+
+  GST_TRACE ("GL Window resized to %ux%u", width, height);
+
+  /* check if a client reshape callback is registered */
+  if (gl_sink->clientReshapeCallback)
+    gl_sink->clientReshapeCallback (width, height, gl_sink->client_data);
+
+  /* default reshape */
+  else {
+    if (gl_sink->keep_aspect_ratio) {
+      GstVideoRectangle src, dst, result;
+
+      src.x = 0;
+      src.y = 0;
+      src.w = GST_VIDEO_INFO_WIDTH (&gl_sink->info);
+      src.h = GST_VIDEO_INFO_HEIGHT (&gl_sink->info);
+
+      dst.x = 0;
+      dst.y = 0;
+      dst.w = width;
+      dst.h = height;
+
+      gst_video_sink_center_rect (src, dst, &result, TRUE);
+      gl->Viewport (result.x, result.y, result.w, result.h);
+    } else {
+      gl->Viewport (0, 0, width, height);
+    }
+#if GST_GL_HAVE_OPENGL
+    if (USING_OPENGL (gl_sink->context)) {
+      gl->MatrixMode (GL_PROJECTION);
+      gl->LoadIdentity ();
+      gluOrtho2D (0, width, 0, height);
+      gl->MatrixMode (GL_MODELVIEW);
+    }
+#endif
+  }
+}
+
+
+static void
+gst_glimage_sink_on_draw (const GstGLImageSink * gl_sink)
+{
+  /* Here gl_sink members (ex:gl_sink->info) have a life time of set_caps.
+   * It means that they cannot not change between two set_caps as well as
+   * for the redisplay_texture size.
+   * Whereas redisplay_texture id changes every sink_render
+   */
+
+  const GstGLFuncs *gl = NULL;
+  GstGLWindow *window = NULL;
+
+  g_return_if_fail (GST_IS_GLIMAGE_SINK (gl_sink));
+
+  gl = gl_sink->context->gl_vtable;
+
+  GST_GLIMAGE_SINK_LOCK (gl_sink);
+
+  /* check if texture is ready for being drawn */
+  if (!gl_sink->redisplay_texture) {
+    GST_GLIMAGE_SINK_UNLOCK (gl_sink);
+    return;
+  }
+
+  window = gst_gl_context_get_window (gl_sink->context);
+  window->is_drawing = TRUE;
+
+  /* opengl scene */
+  GST_TRACE ("redrawing texture:%u", gl_sink->redisplay_texture);
+
+  /* make sure that the environnement is clean */
+  gst_gl_context_clear_shader (gl_sink->context);
+
+#if GST_GL_HAVE_OPENGL
+  if (USING_OPENGL (gl_sink->context))
+    gl->Disable (GL_TEXTURE_2D);
+#endif
+
+  gl->BindTexture (GL_TEXTURE_2D, 0);
+
+  /* check if a client draw callback is registered */
+  if (gl_sink->clientDrawCallback) {
+
+    gboolean doRedisplay =
+        gl_sink->clientDrawCallback (gl_sink->redisplay_texture,
+        GST_VIDEO_INFO_WIDTH (&gl_sink->info),
+        GST_VIDEO_INFO_HEIGHT (&gl_sink->info),
+        gl_sink->client_data);
+
+    if (doRedisplay)
+      gst_gl_window_draw_unlocked (window,
+          GST_VIDEO_INFO_WIDTH (&gl_sink->info),
+          GST_VIDEO_INFO_HEIGHT (&gl_sink->info));
+  }
+  /* default opengl scene */
+  else {
+#if GST_GL_HAVE_OPENGL
+    if (USING_OPENGL (gl_sink->context)) {
+      GLfloat verts[8] = { 1.0f, 1.0f,
+        -1.0f, 1.0f,
+        -1.0f, -1.0f,
+        1.0f, -1.0f
+      };
+      GLfloat texcoords[8] = { 1.0f, 0.0f,
+        0.0f, 0.0f,
+        0.0f, 1.0f,
+        1.0f, 1.0f
+      };
+      gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+      gl->MatrixMode (GL_PROJECTION);
+      gl->LoadIdentity ();
+
+      gl->Enable (GL_TEXTURE_2D);
+      gl->BindTexture (GL_TEXTURE_2D, gl_sink->redisplay_texture);
+
+      gl->EnableClientState (GL_VERTEX_ARRAY);
+      gl->EnableClientState (GL_TEXTURE_COORD_ARRAY);
+      gl->VertexPointer (2, GL_FLOAT, 0, &verts);
+      gl->TexCoordPointer (2, GL_FLOAT, 0, &texcoords);
+
+      gl->DrawArrays (GL_TRIANGLE_FAN, 0, 4);
+
+      gl->DisableClientState (GL_VERTEX_ARRAY);
+      gl->DisableClientState (GL_TEXTURE_COORD_ARRAY);
+
+      gl->Disable (GL_TEXTURE_2D);
+    }
+#endif
+#if GST_GL_HAVE_GLES2
+    if (USING_GLES2 (gl_sink->context)) {
+      const GLfloat vVertices[] = { 1.0f, 1.0f, 0.0f,
+        1.0f, 0.0f,
+        -1.0f, 1.0f, 0.0f,
+        0.0f, 0.0f,
+        -1.0f, -1.0f, 0.0f,
+        0.0f, 1.0f,
+        1.0f, -1.0f, 0.0f,
+        1.0f, 1.0f
+      };
+
+      GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
+
+      gl->Clear (GL_COLOR_BUFFER_BIT);
+
+      gst_gl_shader_use (gl_sink->redisplay_shader);
+
+      /* Load the vertex position */
+      gl->VertexAttribPointer (gl_sink->redisplay_attr_position_loc, 3,
+          GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), vVertices);
+
+      /* Load the texture coordinate */
+      gl->VertexAttribPointer (gl_sink->redisplay_attr_texture_loc, 2,
+          GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), &vVertices[3]);
+
+      gl->EnableVertexAttribArray (gl_sink->redisplay_attr_position_loc);
+      gl->EnableVertexAttribArray (gl_sink->redisplay_attr_texture_loc);
+
+      gl->ActiveTexture (GL_TEXTURE0);
+      gl->BindTexture (GL_TEXTURE_2D, gl_sink->redisplay_texture);
+      gst_gl_shader_set_uniform_1i (gl_sink->redisplay_shader, "s_texture", 0);
+
+      gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
+    }
+#endif
+  }                             /* end default opengl scene */
+
+  window->is_drawing = FALSE;
+  gst_object_unref (window);
+
+  GST_GLIMAGE_SINK_UNLOCK (gl_sink);
+}
+
+static void
+gst_glimage_sink_on_close (GstGLImageSink * gl_sink)
+{
+  gst_gl_context_set_error (gl_sink->context, "Output window was closed");
+
+  g_atomic_int_set (&gl_sink->to_quit, 1);
+}
+
+static gboolean
+gst_glimage_sink_redisplay (GstGLImageSink * gl_sink)
+{
+  GstGLWindow *window;
+  gboolean alive;
+
+  window = gst_gl_context_get_window (gl_sink->context);
+
+  if (window && gst_gl_window_is_running (window)) {
+
+#if GST_GL_HAVE_GLES2
+    if (USING_GLES2 (gl_sink->context)) {
+      if (!gl_sink->redisplay_shader) {
+        gst_gl_window_send_message (window,
+            GST_GL_WINDOW_CB (gst_glimage_sink_thread_init_redisplay), gl_sink);
+      }
+    }
+#endif
+
+    /* Drawing is asynchrone: gst_gl_window_draw is not blocking
+     * It means that it does not wait for stuff being executed in other threads
+     */
+    gst_gl_window_draw (window, GST_VIDEO_SINK_WIDTH (gl_sink),
+        GST_VIDEO_SINK_HEIGHT (gl_sink));
+  }
+  alive = gst_gl_window_is_running (window);
+  gst_object_unref (window);
+
+  return alive;
+}
diff --git a/ext/gl/gstglimagesink.h b/ext/gl/gstglimagesink.h
new file mode 100644 (file)
index 0000000..ea158fe
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * GStreamer
+ * Copyright (C) 2003 Julien Moutte <julien@moutte.net>
+ * Copyright (C) 2005,2006,2007 David A. Schleef <ds@schleef.org>
+ * Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.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.
+ */
+
+#ifndef _GLIMAGESINK_H_
+#define _GLIMAGESINK_H_
+
+#include <gst/gst.h>
+#include <gst/video/gstvideosink.h>
+#include <gst/video/video.h>
+
+#include <gst/gl/gl.h>
+
+G_BEGIN_DECLS
+
+GST_DEBUG_CATEGORY_EXTERN (gst_debug_glimage_sink);
+
+#define GST_TYPE_GLIMAGE_SINK \
+    (gst_glimage_sink_get_type())
+#define GST_GLIMAGE_SINK(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GLIMAGE_SINK,GstGLImageSink))
+#define GST_GLIMAGE_SINK_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GLIMAGE_SINK,GstGLImageSinkClass))
+#define GST_IS_GLIMAGE_SINK(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GLIMAGE_SINK))
+#define GST_IS_GLIMAGE_SINK_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GLIMAGE_SINK))
+
+typedef struct _GstGLImageSink GstGLImageSink;
+typedef struct _GstGLImageSinkClass GstGLImageSinkClass;
+
+struct _GstGLImageSink
+{
+    GstVideoSink video_sink;
+
+    //properties
+    gchar *display_name;
+
+    guintptr window_id;
+    guintptr new_window_id;
+
+    //caps
+    GstVideoInfo info;
+
+    GstGLDisplay *display;
+    GstGLContext *context;
+    GstGLContext *other_context;
+
+    GstGLUpload *upload;
+    GLuint     tex_id;
+
+    CRCB clientReshapeCallback;
+    CDCB clientDrawCallback;
+    gpointer client_data;
+
+    volatile gint to_quit;
+    gboolean keep_aspect_ratio;
+    gint par_n, par_d;
+
+    GstBufferPool *pool;
+
+    /* avoid replacing the stored_buffer while drawing */
+    GMutex drawing_lock;
+    GLuint redisplay_texture;
+
+#if GST_GL_HAVE_GLES2
+  GstGLShader *redisplay_shader;
+  GLint redisplay_attr_position_loc;
+  GLint redisplay_attr_texture_loc;
+#endif
+
+};
+
+struct _GstGLImageSinkClass
+{
+    GstVideoSinkClass video_sink_class;
+};
+
+GType gst_glimage_sink_get_type(void);
+
+G_END_DECLS
+
+#endif
+
diff --git a/ext/gl/gstglmosaic.c b/ext/gl/gstglmosaic.c
new file mode 100644 (file)
index 0000000..040b88c
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ * GStreamer
+ * Copyright (C) 2009 Julien Isorce <julien.isorce@gmail.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.
+ */
+
+/**
+ * SECTION:element-glmosaic
+ *
+ * glmixer sub element. N gl sink pads to 1 source pad.
+ * N + 1 OpenGL contexts shared together.
+ * N <= 6 because the rendering is more a like a cube than a mosaic
+ * Each opengl input stream is rendered on a cube face
+ *
+ * <refsect2>
+ * <title>Examples</title>
+ * |[
+ * gst-launch-0.10 videotestsrc ! "video/x-raw-yuv, format=(fourcc)YUY2" ! glupload ! queue ! glmosaic name=m ! glimagesink videotestsrc pattern=12 ! "video/x-raw-yuv, format=(fourcc)I420, framerate=(fraction)5/1, width=100, height=200" ! glupload ! queue ! m. videotestsrc ! "video/x-raw-rgb, framerate=(fraction)15/1, width=1500, height=1500" ! glupload ! gleffects effect=3 ! queue ! m. videotestsrc ! glupload ! gleffects effect=2 ! queue ! m.  videotestsrc ! glupload ! glfiltercube ! queue ! m. videotestsrc ! glupload ! gleffects effect=6 ! queue ! m.
+ * ]|
+ * FBO (Frame Buffer Object) is required.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstglmosaic.h"
+
+#define GST_CAT_DEFAULT gst_gl_mosaic_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+enum
+{
+  PROP_0,
+};
+
+#define DEBUG_INIT \
+    GST_DEBUG_CATEGORY_INIT (gst_gl_mosaic_debug, "glmosaic", 0, "glmosaic element");
+
+G_DEFINE_TYPE_WITH_CODE (GstGLMosaic, gst_gl_mosaic, GST_TYPE_GL_MIXER,
+    DEBUG_INIT);
+
+static void gst_gl_mosaic_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_gl_mosaic_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static void gst_gl_mosaic_reset (GstGLMixer * mixer);
+static gboolean gst_gl_mosaic_init_shader (GstGLMixer * mixer,
+    GstCaps * outcaps);
+
+static gboolean gst_gl_mosaic_process_textures (GstGLMixer * mixer,
+    GPtrArray * frames, guint out_tex);
+static void gst_gl_mosaic_callback (gpointer stuff);
+
+//vertex source
+static const gchar *mosaic_v_src =
+    "uniform mat4 u_matrix;                                       \n"
+    "uniform float xrot_degree, yrot_degree, zrot_degree;         \n"
+    "attribute vec4 a_position;                                   \n"
+    "attribute vec2 a_texCoord;                                   \n"
+    "varying vec2 v_texCoord;                                     \n"
+    "void main()                                                  \n"
+    "{                                                            \n"
+    "   float PI = 3.14159265;                                    \n"
+    "   float xrot = xrot_degree*2.0*PI/360.0;                    \n"
+    "   float yrot = yrot_degree*2.0*PI/360.0;                    \n"
+    "   float zrot = zrot_degree*2.0*PI/360.0;                    \n"
+    "   mat4 matX = mat4 (                                        \n"
+    "            1.0,        0.0,        0.0, 0.0,                \n"
+    "            0.0,  cos(xrot),  sin(xrot), 0.0,                \n"
+    "            0.0, -sin(xrot),  cos(xrot), 0.0,                \n"
+    "            0.0,        0.0,        0.0, 1.0 );              \n"
+    "   mat4 matY = mat4 (                                        \n"
+    "      cos(yrot),        0.0, -sin(yrot), 0.0,                \n"
+    "            0.0,        1.0,        0.0, 0.0,                \n"
+    "      sin(yrot),        0.0,  cos(yrot), 0.0,                \n"
+    "            0.0,        0.0,       0.0,  1.0 );              \n"
+    "   mat4 matZ = mat4 (                                        \n"
+    "      cos(zrot),  sin(zrot),        0.0, 0.0,                \n"
+    "     -sin(zrot),  cos(zrot),        0.0, 0.0,                \n"
+    "            0.0,        0.0,        1.0, 0.0,                \n"
+    "            0.0,        0.0,        0.0, 1.0 );              \n"
+    "   gl_Position = u_matrix * matZ * matY * matX * a_position; \n"
+    "   v_texCoord = a_texCoord;                                  \n"
+    "}                                                            \n";
+
+//fragment source
+static const gchar *mosaic_f_src =
+    "uniform sampler2D s_texture;                    \n"
+    "varying vec2 v_texCoord;                            \n"
+    "void main()                                         \n"
+    "{                                                   \n"
+    //"  gl_FragColor = vec4( 1.0, 0.5, 1.0, 1.0 );\n"
+    "  gl_FragColor = texture2D( s_texture, v_texCoord );\n"
+    "}                                                   \n";
+
+static void
+gst_gl_mosaic_class_init (GstGLMosaicClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *element_class;
+
+  gobject_class = (GObjectClass *) klass;
+  element_class = GST_ELEMENT_CLASS (klass);
+
+  gobject_class->set_property = gst_gl_mosaic_set_property;
+  gobject_class->get_property = gst_gl_mosaic_get_property;
+
+  gst_element_class_set_metadata (element_class, "OpenGL mosaic",
+      "Filter/Effect/Video", "OpenGL mosaic",
+      "Julien Isorce <julien.isorce@gmail.com>");
+
+  GST_GL_MIXER_CLASS (klass)->set_caps = gst_gl_mosaic_init_shader;
+  GST_GL_MIXER_CLASS (klass)->reset = gst_gl_mosaic_reset;
+  GST_GL_MIXER_CLASS (klass)->process_textures = gst_gl_mosaic_process_textures;
+}
+
+static void
+gst_gl_mosaic_init (GstGLMosaic * mosaic)
+{
+  mosaic->shader = NULL;
+  mosaic->input_frames = NULL;
+}
+
+static void
+gst_gl_mosaic_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  //GstGLMosaic *mixer = GST_GL_MOSAIC (object);
+
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_gl_mosaic_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  //GstGLMosaic* mixer = GST_GL_MOSAIC (object);
+
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_gl_mosaic_reset (GstGLMixer * mixer)
+{
+  GstGLMosaic *mosaic = GST_GL_MOSAIC (mixer);
+
+  mosaic->input_frames = NULL;
+
+  //blocking call, wait the opengl thread has destroyed the shader
+  if (mosaic->shader)
+    gst_gl_context_del_shader (mixer->context, mosaic->shader);
+  mosaic->shader = NULL;
+}
+
+static gboolean
+gst_gl_mosaic_init_shader (GstGLMixer * mixer, GstCaps * outcaps)
+{
+  GstGLMosaic *mosaic = GST_GL_MOSAIC (mixer);
+
+  //blocking call, wait the opengl thread has compiled the shader
+  return gst_gl_context_gen_shader (mixer->context, mosaic_v_src, mosaic_f_src,
+      &mosaic->shader);
+}
+
+static gboolean
+gst_gl_mosaic_process_textures (GstGLMixer * mix, GPtrArray * frames,
+    guint out_tex)
+{
+  GstGLMosaic *mosaic = GST_GL_MOSAIC (mix);
+
+  mosaic->input_frames = frames;
+
+  //blocking call, use a FBO
+  gst_gl_context_use_fbo_v2 (mix->context,
+      GST_VIDEO_INFO_WIDTH (&mix->out_info),
+      GST_VIDEO_INFO_HEIGHT (&mix->out_info), mix->fbo, mix->depthbuffer,
+      out_tex, gst_gl_mosaic_callback, (gpointer) mosaic);
+
+  return TRUE;
+}
+
+/* opengl scene, params: input texture (not the output mixer->texture) */
+static void
+gst_gl_mosaic_callback (gpointer stuff)
+{
+  GstGLMosaic *mosaic = GST_GL_MOSAIC (stuff);
+  GstGLMixer *mixer = GST_GL_MIXER (mosaic);
+  GstGLFuncs *gl = mixer->context->gl_vtable;
+
+  static GLfloat xrot = 0;
+  static GLfloat yrot = 0;
+  static GLfloat zrot = 0;
+
+  GLint attr_position_loc = 0;
+  GLint attr_texture_loc = 0;
+
+  const GLfloat matrix[] = {
+    0.5f, 0.0f, 0.0f, 0.0f,
+    0.0f, 0.5f, 0.0f, 0.0f,
+    0.0f, 0.0f, 0.5f, 0.0f,
+    0.0f, 0.0f, 0.0f, 1.0f
+  };
+  const GLushort indices[] = {
+    0, 1, 2,
+    0, 2, 3
+  };
+
+  guint count = 0;
+
+  gst_gl_context_clear_shader (mixer->context);
+  gl->BindTexture (GL_TEXTURE_2D, 0);
+  gl->Disable (GL_TEXTURE_2D);
+
+  gl->Enable (GL_DEPTH_TEST);
+
+  gl->ClearColor (0.0, 0.0, 0.0, 0.0);
+  gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+  gst_gl_shader_use (mosaic->shader);
+
+  attr_position_loc =
+      gst_gl_shader_get_attribute_location (mosaic->shader, "a_position");
+  attr_texture_loc =
+      gst_gl_shader_get_attribute_location (mosaic->shader, "a_texCoord");
+
+  while (count < mosaic->input_frames->len && count < 6) {
+    GstGLMixerFrameData *frame;
+    GLfloat *v_vertices;
+    guint in_tex;
+    guint width, height;
+
+    frame = g_ptr_array_index (mosaic->input_frames, count);
+    in_tex = frame->texture;
+    width = GST_VIDEO_INFO_WIDTH (&frame->pad->in_info);
+    height = GST_VIDEO_INFO_HEIGHT (&frame->pad->in_info);
+
+    if (!frame || !in_tex || width <= 0 || height <= 0) {
+      GST_DEBUG ("skipping texture:%u frame:%p width:%u height %u",
+          in_tex, frame, width, height);
+      count++;
+      continue;
+    }
+
+    GST_TRACE ("processing texture:%u dimensions:%ux%u", in_tex, width, height);
+
+    /* *INDENT-OFF* */
+    v_vertices = (GLfloat[]) {
+      /* front face */
+      1.0f, 1.0f, -1.0f,
+      1.0f, 0.0f,
+      1.0f, -1.0f, -1.0f,
+      1.0f, 1.0f,
+      -1.0f, -1.0f, -1.0f,
+      0.0f, 1.0f,
+      -1.0f, 1.0f, -1.0f,
+      0.0f, 0.0f,
+      /* right face */
+      1.0f, 1.0f, 1.0f,
+      1.0f, 0.0f,
+      1.0f, -1.0f, 1.0f,
+      0.0f, 0.0f,
+      1.0f, -1.0f, -1.0f,
+      0.0f, 1.0f,
+      1.0f, 1.0f, -1.0f,
+      1.0f, 1.0f,
+      /* left face */
+      -1.0f, 1.0f, 1.0f,
+      1.0f, 0.0f,
+      -1.0f, 1.0f, -1.0f,
+      1.0f, 1.0f,
+      -1.0f, -1.0f, -1.0f,
+      0.0f, 1.0f,
+      -1.0f, -1.0f, 1.0f,
+      0.0f, 0.0f,
+      /* top face */
+      1.0f, -1.0f, 1.0f,
+      1.0f, 0.0f,
+      -1.0f, -1.0f, 1.0f,
+      0.0f, 0.0f,
+      -1.0f, -1.0f, -1.0f,
+      0.0f, 1.0f,
+      1.0f, -1.0f, -1.0f,
+      1.0f, 1.0f,
+      /* bottom face */
+      1.0f, 1.0f, 1.0f,
+      1.0f, 0.0f,
+      1.0f, 1.0f, -1.0f,
+      1.0f, 1.0f,
+      -1.0f, 1.0f, -1.0f,
+      0.0f, 1.0f,
+      -1.0f, 1.0f, 1.0f,
+      0.0f, 0.0f,
+      /* back face */
+      1.0f, 1.0f, 1.0f,
+      1.0f, 0.0f,
+      -1.0f, 1.0f, 1.0f,
+      0.0f, 0.0f,
+      -1.0f, -1.0f, 1.0f,
+      0.0f, 1.0f,
+      1.0f, -1.0f, 1.0f,
+      1.0f, 1.0f
+    };
+    /* *INDENT-ON* */
+
+    gl->VertexAttribPointer (attr_position_loc, 3, GL_FLOAT,
+        GL_FALSE, 5 * sizeof (GLfloat), &v_vertices[5 * 4 * count]);
+
+    gl->VertexAttribPointer (attr_texture_loc, 2, GL_FLOAT,
+        GL_FALSE, 5 * sizeof (GLfloat), &v_vertices[5 * 4 * count + 3]);
+
+    gl->EnableVertexAttribArray (attr_position_loc);
+    gl->EnableVertexAttribArray (attr_texture_loc);
+
+    gl->ActiveTexture (GL_TEXTURE0);
+    gl->BindTexture (GL_TEXTURE_2D, in_tex);
+    gst_gl_shader_set_uniform_1i (mosaic->shader, "s_texture", 0);
+    gst_gl_shader_set_uniform_1f (mosaic->shader, "xrot_degree", xrot);
+    gst_gl_shader_set_uniform_1f (mosaic->shader, "yrot_degree", yrot);
+    gst_gl_shader_set_uniform_1f (mosaic->shader, "zrot_degree", zrot);
+    gst_gl_shader_set_uniform_matrix_4fv (mosaic->shader, "u_matrix", 1,
+        GL_FALSE, matrix);
+
+    gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
+
+    ++count;
+  }
+
+  gl->DisableVertexAttribArray (attr_position_loc);
+  gl->DisableVertexAttribArray (attr_texture_loc);
+
+  gl->BindTexture (GL_TEXTURE_2D, 0);
+
+  gl->Disable (GL_DEPTH_TEST);
+
+  gst_gl_context_clear_shader (mixer->context);
+
+  xrot += 0.6f;
+  yrot += 0.4f;
+  zrot += 0.8f;
+}
diff --git a/ext/gl/gstglmosaic.h b/ext/gl/gstglmosaic.h
new file mode 100644 (file)
index 0000000..1da9dbe
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * GStreamer
+ * Copyright (C) 2009 Julien Isorce <julien.isorce@gmail.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.
+ */
+
+#ifndef _GST_GL_MOSAIC_H_
+#define _GST_GL_MOSAIC_H_
+
+#include <gst/gl/gstglmixer.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_GL_MOSAIC            (gst_gl_mosaic_get_type())
+#define GST_GL_MOSAIC(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_MOSAIC,GstGLMosaic))
+#define GST_IS_GL_MOSAIC(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_MOSAIC))
+#define GST_GL_MOSAIC_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_MOSAIC,GstGLMosaicClass))
+#define GST_IS_GL_MOSAIC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_MOSAIC))
+#define GST_GL_MOSAIC_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_MOSAIC,GstGLMosaicClass))
+
+typedef struct _GstGLMosaic GstGLMosaic;
+typedef struct _GstGLMosaicClass GstGLMosaicClass;
+
+struct _GstGLMosaic
+{
+    GstGLMixer mixer;
+
+    GstGLShader *shader;
+    GPtrArray *input_frames;
+};
+
+struct _GstGLMosaicClass
+{
+    GstGLMixerClass mixer_class;
+};
+
+GType gst_gl_mosaic_get_type (void);
+
+G_END_DECLS
+
+#endif /* _GST_GLFILTERCUBE_H_ */
diff --git a/ext/gl/gstgloverlay.c b/ext/gl/gstgloverlay.c
new file mode 100644 (file)
index 0000000..ba108a9
--- /dev/null
@@ -0,0 +1,809 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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.
+ */
+
+/**
+ * SECTION:element-gloverlay
+ *
+ * Overlay GL video texture with a PNG image
+ *
+ * <refsect2>
+ * <title>Examples</title>
+ * |[
+ * gst-launch  videotestsrc ! "video/x-raw-rgb" ! glupload ! gloverlay location=imagefile ! glimagesink
+ * ]|
+ * FBO (Frame Buffer Object) is required.
+ * </refsect2>
+ */
+
+/* FIXME: Redo this */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gl/gstglconfig.h>
+
+#include "gstgloverlay.h"
+#include "effects/gstgleffectssources.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <jpeglib.h>
+#include <png.h>
+
+#if PNG_LIBPNG_VER >= 10400
+#define int_p_NULL         NULL
+#define png_infopp_NULL    NULL
+#endif
+
+#define GST_CAT_DEFAULT gst_gl_overlay_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+#define DEBUG_INIT \
+  GST_DEBUG_CATEGORY_INIT (gst_gl_overlay_debug, "gloverlay", 0, "gloverlay element");
+
+G_DEFINE_TYPE_WITH_CODE (GstGLOverlay, gst_gl_overlay, GST_TYPE_GL_FILTER,
+    DEBUG_INIT);
+
+static gboolean gst_gl_overlay_set_caps (GstGLFilter * filter,
+    GstCaps * incaps, GstCaps * outcaps);
+
+static void gst_gl_overlay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_gl_overlay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static void gst_gl_overlay_init_resources (GstGLFilter * filter);
+static void gst_gl_overlay_reset_resources (GstGLFilter * filter);
+
+static gboolean gst_gl_overlay_filter_texture (GstGLFilter * filter,
+    guint in_tex, guint out_tex);
+
+static gint gst_gl_overlay_load_png (GstGLFilter * filter);
+static gint gst_gl_overlay_load_jpeg (GstGLFilter * filter);
+
+enum
+{
+  PROP_0,
+  PROP_LOCATION,
+  PROP_XPOS_PNG,
+  PROP_YPOS_PNG,
+  PROP_SIZE_PNG,
+  PROP_XPOS_VIDEO,
+  PROP_YPOS_VIDEO,
+  PROP_SIZE_VIDEO,
+  PROP_VIDEOTOP,
+  PROP_ROTATE_PNG,
+  PROP_ROTATE_VIDEO,
+  PROP_ANGLE_PNG,
+  PROP_ANGLE_VIDEO,
+  PROP_RATIO_VIDEO
+};
+
+
+/* init resources that need a gl context */
+static void
+gst_gl_overlay_init_gl_resources (GstGLFilter * filter)
+{
+//  GstGLOverlay *overlay = GST_GL_OVERLAY (filter);
+}
+
+/* free resources that need a gl context */
+static void
+gst_gl_overlay_reset_gl_resources (GstGLFilter * filter)
+{
+  GstGLOverlay *overlay = GST_GL_OVERLAY (filter);
+  const GstGLFuncs *gl = filter->context->gl_vtable;
+
+  gl->DeleteTextures (1, &overlay->pbuftexture);
+}
+
+static void
+gst_gl_overlay_class_init (GstGLOverlayClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *element_class;
+
+  gobject_class = (GObjectClass *) klass;
+  element_class = GST_ELEMENT_CLASS (klass);
+
+  gobject_class->set_property = gst_gl_overlay_set_property;
+  gobject_class->get_property = gst_gl_overlay_get_property;
+
+  GST_GL_FILTER_CLASS (klass)->set_caps = gst_gl_overlay_set_caps;
+  GST_GL_FILTER_CLASS (klass)->filter_texture = gst_gl_overlay_filter_texture;
+  GST_GL_FILTER_CLASS (klass)->display_init_cb =
+      gst_gl_overlay_init_gl_resources;
+  GST_GL_FILTER_CLASS (klass)->display_reset_cb =
+      gst_gl_overlay_reset_gl_resources;
+  GST_GL_FILTER_CLASS (klass)->onStart = gst_gl_overlay_init_resources;
+  GST_GL_FILTER_CLASS (klass)->onStop = gst_gl_overlay_reset_resources;
+
+  g_object_class_install_property (gobject_class,
+      PROP_LOCATION,
+      g_param_spec_string ("location",
+          "Location of the image",
+          "Location of the image", NULL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_XPOS_PNG,
+      g_param_spec_int ("xpos-png",
+          "X position of overlay image in percents",
+          "X position of overlay image in percents",
+          0, 100, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_YPOS_PNG,
+      g_param_spec_int ("ypos-png",
+          "Y position of overlay image in percents",
+          "Y position of overlay image in percents",
+          0, 100, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_SIZE_PNG,
+      g_param_spec_int ("proportion-png",
+          "Relative size of overlay image, in percents",
+          "Relative size of iverlay image, in percents",
+          0, 100, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_XPOS_VIDEO,
+      g_param_spec_int ("xpos-video",
+          "X position of overlay video in percents",
+          "X position of overlay video in percents",
+          0, 100, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_YPOS_VIDEO,
+      g_param_spec_int ("ypos-video",
+          "Y position of overlay video in percents",
+          "Y position of overlay video in percents",
+          0, 100, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_SIZE_VIDEO,
+      g_param_spec_int ("proportion-video",
+          "Relative size of overlay video, in percents",
+          "Relative size of iverlay video, in percents",
+          0, 100, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_VIDEOTOP,
+      g_param_spec_boolean ("video-top",
+          "Video-top", "Video is over png image", FALSE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_ROTATE_PNG,
+      g_param_spec_int ("rotate-png",
+          "choose rotation axis for the moment only Y axis is implemented",
+          "choose rotation axis for the moment only Y axis is implemented",
+          0, 3, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_ROTATE_VIDEO,
+      g_param_spec_int ("rotate-video",
+          "choose rotation axis for the moment only Y axis is implemented",
+          "choose rotation axis for the moment only Y axis is implemented",
+          0, 3, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_ANGLE_PNG,
+      g_param_spec_int ("angle-png",
+          "choose angle in axis to choosen between -90 and 90",
+          "choose angle in axis to choosen between -90 and 90",
+          -90, 90, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_ANGLE_VIDEO,
+      g_param_spec_int ("angle-video",
+          "choose angle in axis to choosen between -90 and 90",
+          "choose angle in axis to choosen between -90 and 90",
+          -90, 90, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_RATIO_VIDEO,
+      g_param_spec_int ("ratio-video",
+          "choose ratio video between 0 and 3\n \t\t\t0 : Default ratio\n\t\t\t1 : 4 / 3\n\t\t\t2 : 16 / 9\n\t\t\t3 : 16 / 10",
+          "choose ratio video between 0 and 3\n \t\t\t0 : Default ratio\n\t\t\t1 : 4 / 3\n\t\t\t2 : 16 / 9\n\t\t\t3 : 16 / 10",
+          0, 3, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_metadata (element_class,
+      "Gstreamer OpenGL Overlay", "Filter/Effect/Video",
+      "Overlay GL video texture with a PNG image",
+      "Filippo Argiolas <filippo.argiolas@gmail.com>");
+
+  /*
+     g_object_class_install_property (gobject_class,
+     PROP_STRETCH,
+     g_param_spec_boolean ("stretch",
+     "Stretch the image to texture size",
+     "Stretch the image to fit video texture size",
+     TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+   */
+}
+
+static void
+gst_gl_overlay_calc_ratio_video (GstGLOverlay * o, gfloat * video_ratio_w,
+    gfloat * video_ratio_h)
+{
+  if (o->ratio_video == 0) {
+    o->ratio_texture = (gfloat) o->ratio_window;
+    *video_ratio_w = (gfloat) o->width_window;
+    *video_ratio_h = (gfloat) o->height_window;
+  } else if (o->ratio_video == 1) {
+    o->ratio_texture = (gfloat) 1.33;
+    *video_ratio_w = 4.0;
+    *video_ratio_h = 3.0;
+  } else if (o->ratio_video == 2) {
+    o->ratio_texture = (gfloat) 1.77;
+    *video_ratio_w = 16.0;
+    *video_ratio_h = 9.0;
+  } else {
+    o->ratio_texture = (gfloat) 1.6;
+    *video_ratio_w = 16.0;
+    *video_ratio_h = 10.0;
+  }
+}
+
+static void
+gst_gl_overlay_init_texture (GstGLOverlay * o, GLuint tex, int flag)
+{
+  GstGLFilter *filter = GST_GL_FILTER (o);
+  const GstGLFuncs *gl = filter->context->gl_vtable;
+
+  if (flag == 0 && o->type_file == 2) {
+    gl->Enable (GL_TEXTURE_2D);
+    gl->BindTexture (GL_TEXTURE_2D, tex);
+  } else {
+    gl->Enable (GL_TEXTURE_2D);
+    gl->BindTexture (GL_TEXTURE_2D, tex);
+  }
+}
+
+static void
+gst_gl_overlay_draw (GstGLOverlay * o, int flag)
+{
+  GstGLFilter *filter = GST_GL_FILTER (o);
+  const GstGLFuncs *gl = filter->context->gl_vtable;
+
+  float y = 0.0f;
+  float width = 0.0f;
+  float height = 0.0f;
+
+/* *INDENT-OFF* */
+  float v_vertices[] = {
+ /*|            Vertex             | TexCoord  |*/
+    -o->ratio_x + o->posx, y, 0.0f, 0.0f,  0.0f,
+     o->ratio_x + o->posx, y, 0.0f, width, 0.0f,
+     o->ratio_x + o->posx, y, 0.0f, width, height,
+    -o->ratio_x + o->posx, y, 0.0f, 0.0,   height,
+  };
+
+  GLushort indices[] = {
+    0, 1, 2,
+    0, 2, 3,
+  };
+/* *INDENT-ON* */
+
+  if (flag == 1) {
+    width = 1.0f;
+    height = 1.0f;
+  } else if (flag == 0 && o->type_file == 1) {
+    width = (gfloat) o->width;
+    height = (gfloat) o->height;
+  } else if (flag == 0 && o->type_file == 2) {
+    width = 1.0f;
+    height = 1.0f;
+  }
+
+  v_vertices[8] = width;
+  v_vertices[13] = width;
+  v_vertices[14] = height;
+  v_vertices[19] = height;
+
+  y = (o->type_file == 2 && flag == 0 ? o->ratio_y : -o->ratio_y) + o->posy;
+  v_vertices[1] = y;
+  v_vertices[6] = y;
+  y = (o->type_file == 2 && flag == 0 ? -o->ratio_y : o->ratio_y) + o->posy;
+  v_vertices[11] = y;
+  v_vertices[16] = y;
+
+  gst_gl_context_clear_shader (filter->context);
+
+  gl->ClientActiveTexture (GL_TEXTURE0);
+  gl->EnableClientState (GL_TEXTURE_COORD_ARRAY);
+  gl->EnableClientState (GL_VERTEX_ARRAY);
+
+  gl->VertexPointer (3, GL_FLOAT, 5 * sizeof (float), v_vertices);
+  gl->TexCoordPointer (2, GL_FLOAT, 5 * sizeof (float), &v_vertices[3]);
+
+  gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
+
+  gl->DisableClientState (GL_TEXTURE_COORD_ARRAY);
+  gl->DisableClientState (GL_VERTEX_ARRAY);
+}
+
+static void
+gst_gl_overlay_calc_proportion (GstGLOverlay * o, int flag, float size_texture,
+    float width, float height)
+{
+  if ((1.59f < o->ratio_window && o->ratio_window < 1.61f
+          && 1.77f < o->ratio_texture && o->ratio_texture < 1.78f)
+      || (1.3f < o->ratio_window && o->ratio_window < 1.34f
+          && ((1.7f < o->ratio_texture && o->ratio_texture < 1.78f)
+              || (1.59f < o->ratio_texture && o->ratio_texture < 1.61f)))) {
+    o->ratio_x = o->ratio_window * (gfloat) size_texture / 100.0f;
+    o->ratio_y =
+        (o->ratio_window / width) * height * (gfloat) size_texture / 100.0f;
+  } else {
+    o->ratio_x = o->ratio_texture * (gfloat) size_texture / 100.0f;
+    o->ratio_y = 1.0f * size_texture / 100.0f;
+  }
+  o->posx =
+      ((o->ratio_window - o->ratio_x) * ((flag ==
+              1 ? o->pos_x_video : o->pos_x_png) - 50.0f) / 50.0f);
+  o->posy =
+      (1.0f - o->ratio_y) * (((flag ==
+              1 ? o->pos_y_video : o->pos_y_png) - 50.0f) / 50.0f);
+}
+
+static void
+gst_gl_overlay_load_texture (GstGLOverlay * o, GLuint tex, int flag)
+{
+  GstGLFilter *filter = GST_GL_FILTER (o);
+  const GstGLFuncs *gl = filter->context->gl_vtable;
+
+  gfloat video_ratio_w;
+  gfloat video_ratio_h;
+
+  o->ratio_window = (gfloat) o->width_window / (gfloat) o->height_window;
+
+  gl->MatrixMode (GL_MODELVIEW);
+  gl->ActiveTexture (GL_TEXTURE0);
+
+  gst_gl_overlay_init_texture (o, tex, flag);
+
+  gl->BlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+  gl->Enable (GL_BLEND);
+  gl->Translatef (0.0f, 0.0f, -1.43f);
+
+  if (flag == 1) {
+    if (o->rotate_video)
+      gl->Rotatef (o->angle_video, 0, 1, 0);
+    gst_gl_overlay_calc_ratio_video (o, &video_ratio_w, &video_ratio_h);
+    gst_gl_overlay_calc_proportion (o, flag, o->size_video, video_ratio_w,
+        video_ratio_h);
+  } else {
+    o->ratio_texture = (gfloat) o->width / (gfloat) o->height;
+    if (o->rotate_png == 2)
+      gl->Rotatef (o->angle_png, 0, 1, 0);
+    gst_gl_overlay_calc_proportion (o, flag, o->size_png, (gfloat) o->width,
+        (gfloat) o->height);
+  }
+
+  gst_gl_overlay_draw (o, flag);
+  if (flag == 1)
+    gl->Disable (GL_TEXTURE_2D);
+}
+
+static void
+gst_gl_overlay_init (GstGLOverlay * overlay)
+{
+  overlay->location = NULL;
+  overlay->pixbuf = NULL;
+  overlay->pbuftexture = 0;
+  overlay->pbuftexture = 0;
+  overlay->width = 0;
+  overlay->height = 0;
+  overlay->pos_x_png = 0;
+  overlay->pos_y_png = 0;
+  overlay->size_png = 100;
+  overlay->pos_x_video = 0;
+  overlay->pos_y_video = 0;
+  overlay->size_video = 100;
+  overlay->video_top = FALSE;
+  overlay->rotate_png = 0;
+  overlay->rotate_video = 0;
+  overlay->angle_png = 0;
+  overlay->angle_video = 0;
+  overlay->ratio_video = 0;
+  //  overlay->stretch = TRUE;
+  overlay->pbuf_has_changed = FALSE;
+}
+
+static void
+gst_gl_overlay_reset_resources (GstGLFilter * filter)
+{
+  // GstGLOverlay* overlay = GST_GL_OVERLAY(filter);
+}
+
+static void
+gst_gl_overlay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstGLOverlay *overlay = GST_GL_OVERLAY (object);
+
+  switch (prop_id) {
+    case PROP_LOCATION:
+      if (overlay->location != NULL)
+        g_free (overlay->location);
+      overlay->pbuf_has_changed = TRUE;
+      overlay->location = g_value_dup_string (value);
+      break;
+    case PROP_XPOS_PNG:
+      overlay->pos_x_png = g_value_get_int (value);
+      break;
+    case PROP_YPOS_PNG:
+      overlay->pos_y_png = g_value_get_int (value);
+      break;
+    case PROP_SIZE_PNG:
+      overlay->size_png = g_value_get_int (value);
+      break;
+    case PROP_XPOS_VIDEO:
+      overlay->pos_x_video = g_value_get_int (value);
+      break;
+    case PROP_YPOS_VIDEO:
+      overlay->pos_y_video = g_value_get_int (value);
+      break;
+    case PROP_SIZE_VIDEO:
+      overlay->size_video = g_value_get_int (value);
+      break;
+    case PROP_VIDEOTOP:
+      overlay->video_top = g_value_get_boolean (value);
+      break;
+    case PROP_ROTATE_PNG:
+      overlay->rotate_png = g_value_get_int (value);
+      break;
+    case PROP_ROTATE_VIDEO:
+      overlay->rotate_video = g_value_get_int (value);
+      break;
+    case PROP_ANGLE_PNG:
+      overlay->angle_png = g_value_get_int (value);
+      break;
+    case PROP_ANGLE_VIDEO:
+      overlay->angle_video = g_value_get_int (value);
+      break;
+    case PROP_RATIO_VIDEO:
+      overlay->ratio_video = (gfloat) g_value_get_int (value);
+      break;
+      /*  case PROP_STRETCH:
+         overlay->stretch = g_value_get_boolean (value);
+         break;
+       */
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_gl_overlay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstGLOverlay *overlay = GST_GL_OVERLAY (object);
+
+  switch (prop_id) {
+    case PROP_LOCATION:
+      g_value_set_string (value, overlay->location);
+      break;
+    case PROP_XPOS_PNG:
+      g_value_set_int (value, overlay->pos_x_png);
+      break;
+    case PROP_YPOS_PNG:
+      g_value_set_int (value, overlay->pos_y_png);
+      break;
+    case PROP_SIZE_PNG:
+      g_value_set_int (value, overlay->size_png);
+      break;
+    case PROP_XPOS_VIDEO:
+      g_value_set_int (value, overlay->pos_x_video);
+      break;
+    case PROP_YPOS_VIDEO:
+      g_value_set_int (value, overlay->pos_y_video);
+      break;
+    case PROP_SIZE_VIDEO:
+      g_value_set_int (value, overlay->size_video);
+      break;
+    case PROP_VIDEOTOP:
+      g_value_set_boolean (value, overlay->video_top);
+      break;
+    case PROP_ROTATE_PNG:
+      g_value_set_int (value, overlay->rotate_png);
+      break;
+    case PROP_ROTATE_VIDEO:
+      g_value_set_int (value, overlay->rotate_video);
+      break;
+    case PROP_ANGLE_PNG:
+      g_value_set_int (value, overlay->angle_png);
+      break;
+    case PROP_ANGLE_VIDEO:
+      g_value_set_int (value, overlay->angle_video);
+      break;
+    case PROP_RATIO_VIDEO:
+      g_value_set_int (value, (gint) overlay->ratio_video);
+      break;
+      /*  case PROP_STRETCH:
+         g_value_set_boolean (value, overlay->stretch);
+         break;
+       */
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_gl_overlay_set_caps (GstGLFilter * filter, GstCaps * incaps,
+    GstCaps * outcaps)
+{
+  GstGLOverlay *overlay = GST_GL_OVERLAY (filter);
+  GstStructure *s = gst_caps_get_structure (incaps, 0);
+  gint width = 0;
+  gint height = 0;
+
+  gst_structure_get_int (s, "width", &width);
+  gst_structure_get_int (s, "height", &height);
+
+  overlay->width_window = (gfloat) width;
+  overlay->height_window = (gfloat) height;
+
+  return TRUE;
+}
+
+static void
+gst_gl_overlay_init_resources (GstGLFilter * filter)
+{
+//  GstGLOverlay *overlay = GST_GL_OVERLAY (filter);
+}
+
+static void
+gst_gl_overlay_callback (gint width, gint height, guint texture, gpointer stuff)
+{
+  GstGLOverlay *overlay = GST_GL_OVERLAY (stuff);
+  GstGLFilter *filter = GST_GL_FILTER (overlay);
+  const GstGLFuncs *gl = filter->context->gl_vtable;
+
+  gl->MatrixMode (GL_PROJECTION);
+  gl->LoadIdentity ();
+  gluPerspective (70.0f,
+      (GLfloat) overlay->width_window / (GLfloat) overlay->height_window, 1.0f,
+      1000.0f);
+  gl->Enable (GL_DEPTH_TEST);
+  gluLookAt (0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
+  if (!overlay->video_top) {
+    if (overlay->pbuftexture != 0)
+      gst_gl_overlay_load_texture (overlay, overlay->pbuftexture, 0);
+    // if (overlay->stretch) {
+    //   width = (gfloat) overlay->width;
+    //   height = (gfloat) overlay->height;
+    // }
+    gl->LoadIdentity ();
+    gst_gl_overlay_load_texture (overlay, texture, 1);
+  } else {
+    gst_gl_overlay_load_texture (overlay, texture, 1);
+    if (overlay->pbuftexture == 0)
+      return;
+    // if (overlay->stretch) {
+    //   width = (gfloat) overlay->width;
+    //   height = (gfloat) overlay->height;
+    // }
+    gl->LoadIdentity ();
+    gst_gl_overlay_load_texture (overlay, overlay->pbuftexture, 0);
+  }
+}
+
+static void
+init_pixbuf_texture (GstGLContext * context, gpointer data)
+{
+  GstGLOverlay *overlay = GST_GL_OVERLAY (data);
+  GstGLFilter *filter = GST_GL_FILTER (overlay);
+  const GstGLFuncs *gl = filter->context->gl_vtable;
+
+  if (overlay->pixbuf) {
+    gl->DeleteTextures (1, &overlay->pbuftexture);
+    gl->GenTextures (1, &overlay->pbuftexture);
+    if (overlay->type_file == 1) {
+      gl->BindTexture (GL_TEXTURE_2D, overlay->pbuftexture);
+      gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGBA,
+          (gint) overlay->width, (gint) overlay->height, 0,
+          GL_RGBA, GL_UNSIGNED_BYTE, overlay->pixbuf);
+    } else if (overlay->type_file == 2) {
+      gl->BindTexture (GL_TEXTURE_2D, overlay->pbuftexture);
+      gl->TexImage2D (GL_TEXTURE_2D, 0, overlay->internalFormat,
+          overlay->width, overlay->height, 0, overlay->format,
+          GL_UNSIGNED_BYTE, overlay->pixbuf);
+      gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+      gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    }
+  }
+}
+
+static gboolean
+gst_gl_overlay_filter_texture (GstGLFilter * filter, guint in_tex,
+    guint out_tex)
+{
+  GstGLOverlay *overlay = GST_GL_OVERLAY (filter);
+
+  if (overlay->pbuf_has_changed && (overlay->location != NULL)) {
+    if ((overlay->type_file = gst_gl_overlay_load_png (filter)) == 0)
+      if ((overlay->type_file = gst_gl_overlay_load_jpeg (filter)) == 0)
+        overlay->pixbuf = NULL;
+    /* if loader failed then context is turned off */
+    gst_gl_context_thread_add (filter->context, init_pixbuf_texture, overlay);
+    if (overlay->pixbuf) {
+      free (overlay->pixbuf);
+      overlay->pixbuf = NULL;
+    }
+
+    overlay->pbuf_has_changed = FALSE;
+  }
+
+  gst_gl_filter_render_to_target (filter, TRUE, in_tex, out_tex,
+      gst_gl_overlay_callback, overlay);
+
+  return TRUE;
+}
+
+static void
+user_warning_fn (png_structp png_ptr, png_const_charp warning_msg)
+{
+  g_warning ("%s\n", warning_msg);
+}
+
+#define LOAD_ERROR(msg) { GST_WARNING ("unable to load %s: %s", overlay->location, msg); return FALSE; }
+
+static gint
+gst_gl_overlay_load_jpeg (GstGLFilter * filter)
+{
+  GstGLOverlay *overlay = GST_GL_OVERLAY (filter);
+  FILE *fp = NULL;
+  struct jpeg_decompress_struct cinfo;
+  struct jpeg_error_mgr jerr;
+  JSAMPROW j;
+  int i;
+
+  fp = fopen (overlay->location, "rb");
+  if (!fp) {
+    g_error ("error: couldn't open file!\n");
+    return 0;
+  }
+  jpeg_create_decompress (&cinfo);
+  cinfo.err = jpeg_std_error (&jerr);
+  jpeg_stdio_src (&cinfo, fp);
+  jpeg_read_header (&cinfo, TRUE);
+  jpeg_start_decompress (&cinfo);
+  overlay->width = cinfo.image_width;
+  overlay->height = cinfo.image_height;
+  overlay->internalFormat = cinfo.num_components;
+  if (cinfo.num_components == 1)
+    overlay->format = GL_LUMINANCE;
+  else
+    overlay->format = GL_RGB;
+  overlay->pixbuf = (GLubyte *) malloc (sizeof (GLubyte) * overlay->width
+      * overlay->height * overlay->internalFormat);
+  for (i = 0; i < overlay->height; ++i) {
+    j = (overlay->pixbuf +
+        (((int) overlay->height - (i +
+                    1)) * (int) overlay->width * overlay->internalFormat));
+    jpeg_read_scanlines (&cinfo, &j, 1);
+  }
+  jpeg_finish_decompress (&cinfo);
+  jpeg_destroy_decompress (&cinfo);
+  fclose (fp);
+  return 2;
+}
+
+static gint
+gst_gl_overlay_load_png (GstGLFilter * filter)
+{
+  GstGLOverlay *overlay = GST_GL_OVERLAY (filter);
+
+  png_structp png_ptr;
+  png_infop info_ptr;
+  png_uint_32 width = 0;
+  png_uint_32 height = 0;
+  gint bit_depth = 0;
+  gint color_type = 0;
+  gint interlace_type = 0;
+  png_FILE_p fp = NULL;
+  guint y = 0;
+  guchar **rows = NULL;
+  gint filler;
+  png_byte magic[8];
+  gint n_read;
+
+  if (!filter->context)
+    return 1;
+
+  if ((fp = fopen (overlay->location, "rb")) == NULL)
+    LOAD_ERROR ("file not found");
+
+  /* Read magic number */
+  n_read = fread (magic, 1, sizeof (magic), fp);
+  if (n_read != sizeof (magic)) {
+    fclose (fp);
+    LOAD_ERROR ("can't read PNG magic number");
+  }
+
+  /* Check for valid magic number */
+  if (png_sig_cmp (magic, 0, sizeof (magic))) {
+    fclose (fp);
+    LOAD_ERROR ("not a valid PNG image");
+  }
+
+  png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+
+  if (png_ptr == NULL) {
+    fclose (fp);
+    LOAD_ERROR ("failed to initialize the png_struct");
+  }
+
+  png_set_error_fn (png_ptr, NULL, NULL, user_warning_fn);
+
+  info_ptr = png_create_info_struct (png_ptr);
+  if (info_ptr == NULL) {
+    fclose (fp);
+    png_destroy_read_struct (&png_ptr, png_infopp_NULL, png_infopp_NULL);
+    LOAD_ERROR ("failed to initialize the memory for image information");
+  }
+
+  png_init_io (png_ptr, fp);
+
+  png_set_sig_bytes (png_ptr, sizeof (magic));
+
+  png_read_info (png_ptr, info_ptr);
+
+  png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
+      &interlace_type, int_p_NULL, int_p_NULL);
+
+  if (color_type == PNG_COLOR_TYPE_RGB) {
+    filler = 0xff;
+    png_set_filler (png_ptr, filler, PNG_FILLER_AFTER);
+    color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+  }
+
+  if (color_type != PNG_COLOR_TYPE_RGB_ALPHA) {
+    fclose (fp);
+    png_destroy_read_struct (&png_ptr, png_infopp_NULL, png_infopp_NULL);
+    LOAD_ERROR ("color type is not rgb");
+  }
+
+  overlay->width = width;
+  overlay->height = height;
+
+  overlay->pixbuf = (guchar *) malloc (sizeof (guchar) * width * height * 4);
+
+  rows = (guchar **) malloc (sizeof (guchar *) * height);
+
+  for (y = 0; y < height; ++y)
+    rows[y] = (guchar *) (overlay->pixbuf + y * width * 4);
+
+  png_read_image (png_ptr, rows);
+
+  free (rows);
+
+  png_read_end (png_ptr, info_ptr);
+  png_destroy_read_struct (&png_ptr, &info_ptr, png_infopp_NULL);
+  fclose (fp);
+
+  return 1;
+}
diff --git a/ext/gl/gstgloverlay.h b/ext/gl/gstgloverlay.h
new file mode 100644 (file)
index 0000000..6497ec3
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * GStreamer
+ * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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.
+ */
+
+#ifndef _GST_GL_OVERLAY_H_
+#define _GST_GL_OVERLAY_H_
+
+#include <gst/gl/gstglfilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_GL_OVERLAY            (gst_gl_overlay_get_type())
+#define GST_GL_OVERLAY(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_GL_OVERLAY,GstGLOverlay))
+#define GST_IS_GL_OVERLAY(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_GL_OVERLAY))
+#define GST_GL_OVERLAY_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) , GST_TYPE_GL_OVERLAY,GstGLOverlayClass))
+#define GST_IS_GL_OVERLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) , GST_TYPE_GL_OVERLAY))
+#define GST_GL_OVERLAY_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) , GST_TYPE_GL_OVERLAY,GstGLOverlayClass))
+
+typedef struct _GstGLOverlay GstGLOverlay;
+typedef struct _GstGLOverlayClass GstGLOverlayClass;
+
+struct _GstGLOverlay
+{
+  GstGLFilter filter;
+  gchar *location;
+  gboolean pbuf_has_changed;
+  gint8 pos_x_png;
+  gint8 pos_y_png;
+  guint8 size_png;
+  gint8 pos_x_video;
+  gint8 pos_y_video;
+  guint8 size_video;
+  gboolean video_top;
+  guint8 rotate_png;
+  guint8 rotate_video;
+  gint8 angle_png;
+  gint8 angle_video;
+  guchar *pixbuf;
+  gint width, height;
+  GLuint pbuftexture;
+  GLint internalFormat;
+  GLenum format;
+  gint type_file;               // 0 = No; 1 = PNG and 2 = JPEG
+  gfloat width_window;
+  gfloat height_window;
+  gfloat posx;
+  gfloat posy;
+  gfloat ratio_window;
+  gfloat ratio_texture;
+  gfloat ratio_x;
+  gfloat ratio_y;
+  gfloat ratio_video;
+
+/*  gboolean stretch; */
+};
+
+struct _GstGLOverlayClass
+{
+  GstGLFilterClass filter_class;
+};
+
+G_END_DECLS
+
+#endif /* _GST_GL_OVERLAY_H_ */
diff --git a/ext/gl/gstgltestsrc.c b/ext/gl/gstgltestsrc.c
new file mode 100644 (file)
index 0000000..b788dcd
--- /dev/null
@@ -0,0 +1,708 @@
+/*
+ * GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) 2002,2007 David A. Schleef <ds@schleef.org>
+ * Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.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.
+ */
+
+/**
+ * SECTION:element-gltestsrc
+ *
+ * <refsect2>
+ * <para>
+ * The gltestsrc element is used to produce test video texture.
+ * The video test produced can be controlled with the "pattern"
+ * property.
+ * </para>
+ * <title>Example launch line</title>
+ * <para>
+ * <programlisting>
+ * gst-launch -v gltestsrc pattern=smpte ! glimagesink
+ * </programlisting>
+ * Shows original SMPTE color bars in a window.
+ * </para>
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstgltestsrc.h"
+#include "gltestsrc.h"
+#include <gst/gst-i18n-plugin.h>
+
+#define USE_PEER_BUFFERALLOC
+
+GST_DEBUG_CATEGORY_STATIC (gl_test_src_debug);
+#define GST_CAT_DEFAULT gl_test_src_debug
+
+enum
+{
+  PROP_0,
+  PROP_PATTERN,
+  PROP_TIMESTAMP_OFFSET,
+  PROP_IS_LIVE
+      /* FILL ME */
+};
+
+#define gst_gl_test_src_parent_class parent_class
+G_DEFINE_TYPE (GstGLTestSrc, gst_gl_test_src, GST_TYPE_PUSH_SRC);
+
+static void gst_gl_test_src_set_pattern (GstGLTestSrc * gltestsrc,
+    int pattern_type);
+static void gst_gl_test_src_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_gl_test_src_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static gboolean gst_gl_test_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps);
+static GstCaps *gst_gl_test_src_fixate (GstBaseSrc * bsrc, GstCaps * caps);
+
+static gboolean gst_gl_test_src_is_seekable (GstBaseSrc * psrc);
+static gboolean gst_gl_test_src_do_seek (GstBaseSrc * bsrc,
+    GstSegment * segment);
+static gboolean gst_gl_test_src_query (GstBaseSrc * bsrc, GstQuery * query);
+static void gst_gl_test_src_set_context (GstElement * element,
+    GstContext * context);
+
+static void gst_gl_test_src_get_times (GstBaseSrc * basesrc,
+    GstBuffer * buffer, GstClockTime * start, GstClockTime * end);
+static GstFlowReturn gst_gl_test_src_fill (GstPushSrc * psrc,
+    GstBuffer * buffer);
+static gboolean gst_gl_test_src_start (GstBaseSrc * basesrc);
+static gboolean gst_gl_test_src_stop (GstBaseSrc * basesrc);
+static gboolean gst_gl_test_src_decide_allocation (GstBaseSrc * basesrc,
+    GstQuery * query);
+
+static void gst_gl_test_src_callback (gpointer stuff);
+
+#define GST_TYPE_GL_TEST_SRC_PATTERN (gst_gl_test_src_pattern_get_type ())
+static GType
+gst_gl_test_src_pattern_get_type (void)
+{
+  static GType gl_test_src_pattern_type = 0;
+  static const GEnumValue pattern_types[] = {
+    {GST_GL_TEST_SRC_SMPTE, "SMPTE 100% color bars", "smpte"},
+    {GST_GL_TEST_SRC_SNOW, "Random (television snow)", "snow"},
+    {GST_GL_TEST_SRC_BLACK, "100% Black", "black"},
+    {GST_GL_TEST_SRC_WHITE, "100% White", "white"},
+    {GST_GL_TEST_SRC_RED, "Red", "red"},
+    {GST_GL_TEST_SRC_GREEN, "Green", "green"},
+    {GST_GL_TEST_SRC_BLUE, "Blue", "blue"},
+    {GST_GL_TEST_SRC_CHECKERS1, "Checkers 1px", "checkers-1"},
+    {GST_GL_TEST_SRC_CHECKERS2, "Checkers 2px", "checkers-2"},
+    {GST_GL_TEST_SRC_CHECKERS4, "Checkers 4px", "checkers-4"},
+    {GST_GL_TEST_SRC_CHECKERS8, "Checkers 8px", "checkers-8"},
+    {GST_GL_TEST_SRC_CIRCULAR, "Circular", "circular"},
+    {GST_GL_TEST_SRC_BLINK, "Blink", "blink"},
+    {0, NULL, NULL}
+  };
+
+  if (!gl_test_src_pattern_type) {
+    gl_test_src_pattern_type =
+        g_enum_register_static ("GstGLTestSrcPattern", pattern_types);
+  }
+  return gl_test_src_pattern_type;
+}
+
+static void
+gst_gl_test_src_class_init (GstGLTestSrcClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstBaseSrcClass *gstbasesrc_class;
+  GstPushSrcClass *gstpushsrc_class;
+  GstElementClass *element_class;
+
+  GST_DEBUG_CATEGORY_INIT (gl_test_src_debug, "gltestsrc", 0,
+      "Video Test Source");
+
+  gobject_class = (GObjectClass *) klass;
+  gstbasesrc_class = (GstBaseSrcClass *) klass;
+  gstpushsrc_class = (GstPushSrcClass *) klass;
+  element_class = GST_ELEMENT_CLASS (klass);
+
+  gobject_class->set_property = gst_gl_test_src_set_property;
+  gobject_class->get_property = gst_gl_test_src_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_PATTERN,
+      g_param_spec_enum ("pattern", "Pattern",
+          "Type of test pattern to generate", GST_TYPE_GL_TEST_SRC_PATTERN,
+          GST_GL_TEST_SRC_SMPTE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class,
+      PROP_TIMESTAMP_OFFSET, g_param_spec_int64 ("timestamp-offset",
+          "Timestamp offset",
+          "An offset added to timestamps set on buffers (in ns)", G_MININT64,
+          G_MAXINT64, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_IS_LIVE,
+      g_param_spec_boolean ("is-live", "Is Live",
+          "Whether to act as a live source", FALSE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_element_class_set_metadata (element_class, "Video test source",
+      "Source/Video", "Creates a test video stream",
+      "David A. Schleef <ds@schleef.org>");
+
+  gst_element_class_add_pad_template (element_class,
+      gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
+          gst_caps_from_string (GST_GL_DOWNLOAD_VIDEO_CAPS)));
+
+  element_class->set_context = gst_gl_test_src_set_context;
+
+  gstbasesrc_class->set_caps = gst_gl_test_src_setcaps;
+  gstbasesrc_class->is_seekable = gst_gl_test_src_is_seekable;
+  gstbasesrc_class->do_seek = gst_gl_test_src_do_seek;
+  gstbasesrc_class->query = gst_gl_test_src_query;
+  gstbasesrc_class->get_times = gst_gl_test_src_get_times;
+  gstbasesrc_class->start = gst_gl_test_src_start;
+  gstbasesrc_class->stop = gst_gl_test_src_stop;
+  gstbasesrc_class->fixate = gst_gl_test_src_fixate;
+  gstbasesrc_class->decide_allocation = gst_gl_test_src_decide_allocation;
+
+  gstpushsrc_class->fill = gst_gl_test_src_fill;
+}
+
+static void
+gst_gl_test_src_init (GstGLTestSrc * src)
+{
+  gst_gl_test_src_set_pattern (src, GST_GL_TEST_SRC_SMPTE);
+
+  src->timestamp_offset = 0;
+
+  /* we operate in time */
+  gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME);
+  gst_base_src_set_live (GST_BASE_SRC (src), FALSE);
+}
+
+static GstCaps *
+gst_gl_test_src_fixate (GstBaseSrc * bsrc, GstCaps * caps)
+{
+  GstStructure *structure;
+
+  GST_DEBUG ("fixate");
+
+  caps = gst_caps_make_writable (caps);
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  gst_structure_fixate_field_nearest_int (structure, "width", 320);
+  gst_structure_fixate_field_nearest_int (structure, "height", 240);
+  gst_structure_fixate_field_nearest_fraction (structure, "framerate", 30, 1);
+
+  caps = GST_BASE_SRC_CLASS (parent_class)->fixate (bsrc, caps);
+
+  return caps;
+}
+
+static void
+gst_gl_test_src_set_pattern (GstGLTestSrc * gltestsrc, gint pattern_type)
+{
+  gltestsrc->pattern_type = pattern_type;
+
+  GST_DEBUG_OBJECT (gltestsrc, "setting pattern to %d", pattern_type);
+
+  switch (pattern_type) {
+    case GST_GL_TEST_SRC_SMPTE:
+      gltestsrc->make_image = gst_gl_test_src_smpte;
+      break;
+    case GST_GL_TEST_SRC_SNOW:
+      gltestsrc->make_image = gst_gl_test_src_snow;
+      break;
+    case GST_GL_TEST_SRC_BLACK:
+      gltestsrc->make_image = gst_gl_test_src_black;
+      break;
+    case GST_GL_TEST_SRC_WHITE:
+      gltestsrc->make_image = gst_gl_test_src_white;
+      break;
+    case GST_GL_TEST_SRC_RED:
+      gltestsrc->make_image = gst_gl_test_src_red;
+      break;
+    case GST_GL_TEST_SRC_GREEN:
+      gltestsrc->make_image = gst_gl_test_src_green;
+      break;
+    case GST_GL_TEST_SRC_BLUE:
+      gltestsrc->make_image = gst_gl_test_src_blue;
+      break;
+    case GST_GL_TEST_SRC_CHECKERS1:
+      gltestsrc->make_image = gst_gl_test_src_checkers1;
+      break;
+    case GST_GL_TEST_SRC_CHECKERS2:
+      gltestsrc->make_image = gst_gl_test_src_checkers2;
+      break;
+    case GST_GL_TEST_SRC_CHECKERS4:
+      gltestsrc->make_image = gst_gl_test_src_checkers4;
+      break;
+    case GST_GL_TEST_SRC_CHECKERS8:
+      gltestsrc->make_image = gst_gl_test_src_checkers8;
+      break;
+    case GST_GL_TEST_SRC_CIRCULAR:
+      gltestsrc->make_image = gst_gl_test_src_circular;
+      break;
+    case GST_GL_TEST_SRC_BLINK:
+      gltestsrc->make_image = gst_gl_test_src_black;
+      break;
+    default:
+      g_assert_not_reached ();
+  }
+}
+
+static void
+gst_gl_test_src_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstGLTestSrc *src = GST_GL_TEST_SRC (object);
+
+  switch (prop_id) {
+    case PROP_PATTERN:
+      gst_gl_test_src_set_pattern (src, g_value_get_enum (value));
+      break;
+    case PROP_TIMESTAMP_OFFSET:
+      src->timestamp_offset = g_value_get_int64 (value);
+      break;
+    case PROP_IS_LIVE:
+      gst_base_src_set_live (GST_BASE_SRC (src), g_value_get_boolean (value));
+      break;
+    default:
+      break;
+  }
+}
+
+static void
+gst_gl_test_src_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstGLTestSrc *src = GST_GL_TEST_SRC (object);
+
+  switch (prop_id) {
+    case PROP_PATTERN:
+      g_value_set_enum (value, src->pattern_type);
+      break;
+    case PROP_TIMESTAMP_OFFSET:
+      g_value_set_int64 (value, src->timestamp_offset);
+      break;
+    case PROP_IS_LIVE:
+      g_value_set_boolean (value, gst_base_src_is_live (GST_BASE_SRC (src)));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_gl_test_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps)
+{
+  GstGLTestSrc *gltestsrc = GST_GL_TEST_SRC (bsrc);
+
+  GST_DEBUG ("setcaps");
+
+  if (!gst_video_info_from_caps (&gltestsrc->out_info, caps))
+    goto wrong_caps;
+
+  gltestsrc->negotiated = TRUE;
+
+  return TRUE;
+
+/* ERRORS */
+wrong_caps:
+  {
+    GST_WARNING ("wrong caps");
+    return FALSE;
+  }
+}
+
+static void
+gst_gl_test_src_set_context (GstElement * element, GstContext * context)
+{
+  GstGLTestSrc *src = GST_GL_TEST_SRC (element);
+
+  gst_gl_handle_set_context (element, context, &src->display);
+}
+
+static gboolean
+gst_gl_test_src_query (GstBaseSrc * bsrc, GstQuery * query)
+{
+  gboolean res = FALSE;
+  GstGLTestSrc *src;
+
+  src = GST_GL_TEST_SRC (bsrc);
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CONTEXT:
+    {
+      res = gst_gl_handle_context_query ((GstElement *) src, query,
+          &src->display);
+      break;
+    }
+    case GST_QUERY_CONVERT:
+    {
+      GstFormat src_fmt, dest_fmt;
+      gint64 src_val, dest_val;
+
+      gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
+      res =
+          gst_video_info_convert (&src->out_info, src_fmt, src_val, dest_fmt,
+          &dest_val);
+      gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
+      break;
+    }
+    default:
+      res = GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query);
+  }
+
+  return res;
+}
+
+static void
+gst_gl_test_src_get_times (GstBaseSrc * basesrc, GstBuffer * buffer,
+    GstClockTime * start, GstClockTime * end)
+{
+  /* for live sources, sync on the timestamp of the buffer */
+  if (gst_base_src_is_live (basesrc)) {
+    GstClockTime timestamp = GST_BUFFER_TIMESTAMP (buffer);
+
+    if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
+      /* get duration to calculate end time */
+      GstClockTime duration = GST_BUFFER_DURATION (buffer);
+
+      if (GST_CLOCK_TIME_IS_VALID (duration))
+        *end = timestamp + duration;
+      *start = timestamp;
+    }
+  } else {
+    *start = -1;
+    *end = -1;
+  }
+}
+
+static gboolean
+gst_gl_test_src_do_seek (GstBaseSrc * bsrc, GstSegment * segment)
+{
+  GstClockTime time;
+  GstGLTestSrc *src;
+
+  src = GST_GL_TEST_SRC (bsrc);
+
+  segment->time = segment->start;
+  time = segment->position;
+
+  /* now move to the time indicated */
+  if (src->out_info.fps_n) {
+    src->n_frames = gst_util_uint64_scale (time,
+        src->out_info.fps_n, src->out_info.fps_d * GST_SECOND);
+  } else
+    src->n_frames = 0;
+
+  if (src->out_info.fps_n) {
+    src->running_time = gst_util_uint64_scale (src->n_frames,
+        src->out_info.fps_d * GST_SECOND, src->out_info.fps_n);
+  } else {
+    /* FIXME : Not sure what to set here */
+    src->running_time = 0;
+  }
+
+  g_return_val_if_fail (src->running_time <= time, FALSE);
+
+  return TRUE;
+}
+
+static gboolean
+gst_gl_test_src_is_seekable (GstBaseSrc * psrc)
+{
+  /* we're seekable... */
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_gl_test_src_fill (GstPushSrc * psrc, GstBuffer * buffer)
+{
+  GstGLTestSrc *src;
+  GstClockTime next_time;
+  gint width, height;
+  GstVideoFrame out_frame;
+  gboolean out_gl_wrapped = FALSE;
+  guint out_tex;
+
+  src = GST_GL_TEST_SRC (psrc);
+
+  if (G_UNLIKELY (!src->negotiated))
+    goto not_negotiated;
+
+  width = GST_VIDEO_INFO_WIDTH (&src->out_info);
+  height = GST_VIDEO_INFO_HEIGHT (&src->out_info);
+
+  /* 0 framerate and we are at the second frame, eos */
+  if (G_UNLIKELY (GST_VIDEO_INFO_FPS_N (&src->out_info) == 0
+          && src->n_frames == 1))
+    goto eos;
+
+  if (src->pattern_type == GST_GL_TEST_SRC_BLINK) {
+    if (src->n_frames & 0x1)
+      src->make_image = gst_gl_test_src_white;
+    else
+      src->make_image = gst_gl_test_src_black;
+  }
+
+  if (!gst_video_frame_map (&out_frame, &src->out_info, buffer,
+          GST_MAP_WRITE | GST_MAP_GL)) {
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
+
+  if (gst_is_gl_memory (out_frame.map[0].memory)) {
+    out_tex = *(guint *) out_frame.data[0];
+  } else {
+    GST_INFO ("Output Buffer does not contain correct meta, "
+        "attempting to wrap for download");
+
+    if (!src->out_tex_id) {
+      gst_gl_context_gen_texture (src->context, &src->out_tex_id,
+          GST_VIDEO_FORMAT_RGBA, GST_VIDEO_FRAME_WIDTH (&out_frame),
+          GST_VIDEO_FRAME_HEIGHT (&out_frame));
+    }
+    out_tex = src->out_tex_id;
+
+    if (!src->download) {
+      src->download = gst_gl_download_new (src->context);
+
+      if (!gst_gl_download_init_format (src->download,
+              GST_VIDEO_FRAME_FORMAT (&out_frame),
+              GST_VIDEO_FRAME_WIDTH (&out_frame),
+              GST_VIDEO_FRAME_HEIGHT (&out_frame))) {
+        GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
+            ("%s", "Failed to init download format"), (NULL));
+        return FALSE;
+      }
+    }
+
+    out_gl_wrapped = TRUE;
+  }
+
+  gst_buffer_replace (&src->buffer, buffer);
+
+  //blocking call, generate a FBO
+  if (!gst_gl_context_use_fbo_v2 (src->context, width, height, src->fbo,
+          src->depthbuffer, out_tex, gst_gl_test_src_callback,
+          (gpointer) src)) {
+    goto not_negotiated;
+  }
+
+  if (out_gl_wrapped) {
+    if (!gst_gl_download_perform_with_data (src->download, out_tex,
+            out_frame.data)) {
+      GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, ("%s",
+              "Failed to init upload format"), (NULL));
+      return FALSE;
+    }
+  }
+  gst_video_frame_unmap (&out_frame);
+
+  GST_BUFFER_TIMESTAMP (buffer) = src->timestamp_offset + src->running_time;
+  GST_BUFFER_OFFSET (buffer) = src->n_frames;
+  src->n_frames++;
+  GST_BUFFER_OFFSET_END (buffer) = src->n_frames;
+  if (src->out_info.fps_n) {
+    next_time = gst_util_uint64_scale_int (src->n_frames * GST_SECOND,
+        src->out_info.fps_d, src->out_info.fps_n);
+    GST_BUFFER_DURATION (buffer) = next_time - src->running_time;
+  } else {
+    next_time = src->timestamp_offset;
+    /* NONE means forever */
+    GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
+  }
+
+  src->running_time = next_time;
+
+  return GST_FLOW_OK;
+
+not_negotiated:
+  {
+    GST_ELEMENT_ERROR (src, CORE, NEGOTIATION, (NULL),
+        (_("format wasn't negotiated before get function")));
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
+eos:
+  {
+    GST_DEBUG_OBJECT (src, "eos: 0 framerate, frame %d", (gint) src->n_frames);
+    return GST_FLOW_EOS;
+  }
+}
+
+static gboolean
+gst_gl_test_src_start (GstBaseSrc * basesrc)
+{
+  GstGLTestSrc *src = GST_GL_TEST_SRC (basesrc);
+
+  if (!gst_gl_ensure_display (src, &src->display))
+    return FALSE;
+
+  src->running_time = 0;
+  src->n_frames = 0;
+  src->negotiated = FALSE;
+
+  return TRUE;
+}
+
+static gboolean
+gst_gl_test_src_stop (GstBaseSrc * basesrc)
+{
+  GstGLTestSrc *src = GST_GL_TEST_SRC (basesrc);
+
+  if (src->context) {
+    if (src->out_tex_id) {
+      gst_gl_context_del_texture (src->context, &src->out_tex_id);
+    }
+
+    if (src->download) {
+      gst_object_unref (src->download);
+      src->download = NULL;
+    }
+    //blocking call, delete the FBO
+    gst_gl_context_del_fbo (src->context, src->fbo, src->depthbuffer);
+    gst_object_unref (src->context);
+    src->context = NULL;
+  }
+
+  if (src->display) {
+    gst_object_unref (src->display);
+    src->display = NULL;
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_gl_test_src_decide_allocation (GstBaseSrc * basesrc, GstQuery * query)
+{
+  GstGLTestSrc *src = GST_GL_TEST_SRC (basesrc);
+  GstBufferPool *pool = NULL;
+  GstStructure *config;
+  GstCaps *caps;
+  guint min, max, size;
+  gboolean update_pool;
+  GError *error = NULL;
+  guint idx;
+  guint out_width, out_height;
+  GstGLContext *other_context = NULL;
+
+  gst_query_parse_allocation (query, &caps, NULL);
+
+  if (gst_query_get_n_allocation_pools (query) > 0) {
+    gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
+
+    update_pool = TRUE;
+  } else {
+    GstVideoInfo vinfo;
+
+    gst_video_info_init (&vinfo);
+    gst_video_info_from_caps (&vinfo, caps);
+    size = vinfo.size;
+    min = max = 0;
+    update_pool = FALSE;
+  }
+
+  if (!gst_gl_ensure_display (src, &src->display))
+    return FALSE;
+
+  if (gst_query_find_allocation_meta (query,
+          GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, &idx)) {
+    GstGLContext *context;
+    const GstStructure *upload_meta_params;
+    gpointer handle;
+    gchar *type;
+    gchar *apis;
+
+    gst_query_parse_nth_allocation_meta (query, idx, &upload_meta_params);
+    if (gst_structure_get (upload_meta_params, "gst.gl.GstGLContext",
+            GST_GL_TYPE_CONTEXT, &context, NULL) && context) {
+      GstGLContext *old = src->context;
+
+      src->context = context;
+      if (old)
+        gst_object_unref (old);
+    } else if (gst_structure_get (upload_meta_params, "gst.gl.context.handle",
+            G_TYPE_POINTER, &handle, "gst.gl.context.type", G_TYPE_STRING,
+            &type, "gst.gl.context.apis", G_TYPE_STRING, &apis, NULL)
+        && handle) {
+      GstGLPlatform platform = GST_GL_PLATFORM_NONE;
+      GstGLAPI gl_apis;
+
+      GST_DEBUG ("got GL context handle 0x%p with type %s and apis %s", handle,
+          type, apis);
+
+      if (g_strcmp0 (type, "glx") == 0)
+        platform = GST_GL_PLATFORM_GLX;
+
+      gl_apis = gst_gl_api_from_string (apis);
+
+      if (gl_apis && platform)
+        other_context =
+            gst_gl_context_new_wrapped (src->display, (guintptr) handle,
+            platform, gl_apis);
+    }
+  }
+
+  if (!src->context) {
+    src->context = gst_gl_context_new (src->display);
+    if (!gst_gl_context_create (src->context, other_context, &error))
+      goto context_error;
+  }
+
+  out_width = GST_VIDEO_INFO_WIDTH (&src->out_info);
+  out_height = GST_VIDEO_INFO_HEIGHT (&src->out_info);
+
+  if (!gst_gl_context_gen_fbo (src->context, out_width, out_height,
+          &src->fbo, &src->depthbuffer))
+    goto context_error;
+
+  if (!pool)
+    pool = gst_gl_buffer_pool_new (src->context);
+
+  config = gst_buffer_pool_get_config (pool);
+  gst_buffer_pool_config_set_params (config, caps, size, min, max);
+  gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
+  gst_buffer_pool_set_config (pool, config);
+
+  if (update_pool)
+    gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
+  else
+    gst_query_add_allocation_pool (query, pool, size, min, max);
+
+  gst_object_unref (pool);
+
+  return TRUE;
+
+context_error:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, ("%s", error->message),
+        (NULL));
+    return FALSE;
+  }
+}
+
+//opengl scene
+static void
+gst_gl_test_src_callback (gpointer stuff)
+{
+  GstGLTestSrc *src = GST_GL_TEST_SRC (stuff);
+
+  src->make_image (src, src->buffer, GST_VIDEO_INFO_WIDTH (&src->out_info),
+      GST_VIDEO_INFO_HEIGHT (&src->out_info));
+
+  gst_buffer_unref (src->buffer);
+  src->buffer = NULL;
+}
diff --git a/ext/gl/gstgltestsrc.h b/ext/gl/gstgltestsrc.h
new file mode 100644 (file)
index 0000000..48e4d86
--- /dev/null
@@ -0,0 +1,125 @@
+/* 
+ * GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) 2002,2007 David A. Schleef <ds@schleef.org>
+ * Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.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.
+ */
+
+#ifndef __GST_GL_TEST_SRC_H__
+#define __GST_GL_TEST_SRC_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstpushsrc.h>
+
+#include <gst/gl/gl.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_GL_TEST_SRC \
+    (gst_gl_test_src_get_type())
+#define GST_GL_TEST_SRC(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_TEST_SRC,GstGLTestSrc))
+#define GST_GL_TEST_SRC_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GL_TEST_SRC,GstGLTestSrcClass))
+#define GST_IS_GL_TEST_SRC(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_TEST_SRC))
+#define GST_IS_GL_TEST_SRC_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GL_TEST_SRC))
+
+/**
+ * GstGLTestSrcPattern:
+ * @GST_GL_TEST_SRC_SMPTE: A standard SMPTE test pattern
+ * @GST_GL_TEST_SRC_SNOW: Random noise
+ * @GST_GL_TEST_SRC_BLACK: A black image
+ * @GST_GL_TEST_SRC_WHITE: A white image
+ * @GST_GL_TEST_SRC_RED: A red image
+ * @GST_GL_TEST_SRC_GREEN: A green image
+ * @GST_GL_TEST_SRC_BLUE: A blue image
+ * @GST_GL_TEST_SRC_CHECKERS1: Checkers pattern (1px)
+ * @GST_GL_TEST_SRC_CHECKERS2: Checkers pattern (2px)
+ * @GST_GL_TEST_SRC_CHECKERS4: Checkers pattern (4px)
+ * @GST_GL_TEST_SRC_CHECKERS8: Checkers pattern (8px)
+ * @GST_GL_TEST_SRC_CIRCULAR: Circular pattern
+ * @GST_GL_TEST_SRC_BLINK: Alternate between black and white
+ *
+ * The test pattern to produce.
+ */
+typedef enum {
+    GST_GL_TEST_SRC_SMPTE,
+    GST_GL_TEST_SRC_SNOW,
+    GST_GL_TEST_SRC_BLACK,
+    GST_GL_TEST_SRC_WHITE,
+    GST_GL_TEST_SRC_RED,
+    GST_GL_TEST_SRC_GREEN,
+    GST_GL_TEST_SRC_BLUE,
+    GST_GL_TEST_SRC_CHECKERS1,
+    GST_GL_TEST_SRC_CHECKERS2,
+    GST_GL_TEST_SRC_CHECKERS4,
+    GST_GL_TEST_SRC_CHECKERS8,
+    GST_GL_TEST_SRC_CIRCULAR,
+    GST_GL_TEST_SRC_BLINK
+} GstGLTestSrcPattern;
+
+typedef struct _GstGLTestSrc GstGLTestSrc;
+typedef struct _GstGLTestSrcClass GstGLTestSrcClass;
+
+/**
+ * GstGLTestSrc:
+ *
+ * Opaque data structure.
+ */
+struct _GstGLTestSrc {
+    GstPushSrc element;
+
+    /*< private >*/
+
+    /* type of output */
+    GstGLTestSrcPattern pattern_type;
+
+    /* video state */
+    char *format_name;
+    GstVideoInfo out_info;
+
+    GLuint fbo;
+    GLuint depthbuffer;
+
+    GstBuffer* buffer;
+    GstBufferPool *pool;
+
+    guint out_tex_id;
+    GstGLDownload *download;
+
+    GstGLDisplay *display;
+    GstGLContext *context;
+    gint64 timestamp_offset;              /* base offset */
+    GstClockTime running_time;            /* total running time */
+    gint64 n_frames;                      /* total frames sent */
+    gboolean negotiated;
+
+    void (*make_image) (GstGLTestSrc* v, GstBuffer* buffer, gint w, gint h);
+};
+
+struct _GstGLTestSrcClass {
+    GstPushSrcClass parent_class;
+};
+
+GType gst_gl_test_src_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_GL_TEST_SRC_H__ */
diff --git a/ext/gl/gstglvideomixer.c b/ext/gl/gstglvideomixer.c
new file mode 100644 (file)
index 0000000..d72f83b
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * GStreamer
+ * Copyright (C) 2009 Julien Isorce <julien.isorce@gmail.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.
+ */
+
+/**
+ * SECTION:element-glvideomixer
+ *
+ * glmixer sub element. N gl sink pads to 1 source pad.
+ * N + 1 OpenGL contexts shared together.
+ * N <= 6 because the rendering is more a like a cube than a video_mixer
+ * Each opengl input stream is rendered on a cube face
+ *
+ * <refsect2>
+ * <title>Examples</title>
+ * |[
+ * gst-launch-0.10 videotestsrc ! "video/x-raw-yuv, format=(fourcc)YUY2" ! glupload ! queue ! glvideomixer name=m ! glimagesink videotestsrc pattern=12 ! "video/x-raw-yuv, format=(fourcc)I420, framerate=(fraction)5/1, width=100, height=200" ! glupload ! queue ! m. videotestsrc ! "video/x-raw-rgb, framerate=(fraction)15/1, width=1500, height=1500" ! glupload ! gleffects effect=3 ! queue ! m. videotestsrc ! glupload ! gleffects effect=2 ! queue ! m.  videotestsrc ! glupload ! glfiltercube ! queue ! m. videotestsrc ! glupload ! gleffects effect=6 ! queue ! m.
+ * ]|
+ * FBO (Frame Buffer Object) is required.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstglvideomixer.h"
+
+#define GST_CAT_DEFAULT gst_gl_video_mixer_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+enum
+{
+  PROP_0,
+};
+
+#define DEBUG_INIT \
+    GST_DEBUG_CATEGORY_INIT (gst_gl_video_mixer_debug, "glvideomixer", 0, "glvideomixer element");
+
+G_DEFINE_TYPE_WITH_CODE (GstGLVideoMixer, gst_gl_video_mixer, GST_TYPE_GL_MIXER,
+    DEBUG_INIT);
+
+static void gst_gl_video_mixer_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_gl_video_mixer_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static void gst_gl_video_mixer_reset (GstGLMixer * mixer);
+static gboolean gst_gl_video_mixer_init_shader (GstGLMixer * mixer,
+    GstCaps * outcaps);
+
+static gboolean gst_gl_video_mixer_process_textures (GstGLMixer * mixer,
+    GPtrArray * in_frames, guint out_tex);
+static void gst_gl_video_mixer_callback (gpointer stuff);
+
+/* vertex source */
+static const gchar *video_mixer_v_src =
+    "attribute vec4 a_position;                                   \n"
+    "attribute vec2 a_texCoord;                                   \n"
+    "uniform float x_scale;                                       \n"
+    "uniform float y_scale;                                       \n"
+    "varying vec2 v_texCoord;                                     \n"
+    "void main()                                                  \n"
+    "{                                                            \n"
+    "   gl_Position = a_position * vec4(x_scale, y_scale, 1.0, 1.0);\n"
+    "   v_texCoord = a_texCoord;                                  \n" "}";
+
+/* fragment source */
+static const gchar *video_mixer_f_src =
+    "uniform sampler2D texture;                     \n"
+    "varying vec2 v_texCoord;                            \n"
+    "void main()                                         \n"
+    "{                                                   \n"
+    "  vec4 rgba = texture2D( texture, v_texCoord );\n"
+    "  gl_FragColor = vec4(rgba.rgb, 1.0);\n"
+    "}                                                   \n";
+
+static void
+gst_gl_video_mixer_class_init (GstGLVideoMixerClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *element_class;
+
+  gobject_class = (GObjectClass *) klass;
+  element_class = GST_ELEMENT_CLASS (klass);
+
+  gobject_class->set_property = gst_gl_video_mixer_set_property;
+  gobject_class->get_property = gst_gl_video_mixer_get_property;
+
+  gst_element_class_set_metadata (element_class, "OpenGL video_mixer",
+      "Filter/Effect/Video", "OpenGL video_mixer",
+      "Julien Isorce <julien.isorce@gmail.com>");
+
+  GST_GL_MIXER_CLASS (klass)->set_caps = gst_gl_video_mixer_init_shader;
+  GST_GL_MIXER_CLASS (klass)->reset = gst_gl_video_mixer_reset;
+  GST_GL_MIXER_CLASS (klass)->process_textures =
+      gst_gl_video_mixer_process_textures;
+}
+
+static void
+gst_gl_video_mixer_init (GstGLVideoMixer * video_mixer)
+{
+  video_mixer->shader = NULL;
+  video_mixer->input_frames = NULL;
+}
+
+static void
+gst_gl_video_mixer_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_gl_video_mixer_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_gl_video_mixer_reset (GstGLMixer * mixer)
+{
+  GstGLVideoMixer *video_mixer = GST_GL_VIDEO_MIXER (mixer);
+
+  video_mixer->input_frames = NULL;
+
+  if (video_mixer->shader)
+    gst_gl_context_del_shader (mixer->context, video_mixer->shader);
+  video_mixer->shader = NULL;
+}
+
+static gboolean
+gst_gl_video_mixer_init_shader (GstGLMixer * mixer, GstCaps * outcaps)
+{
+  GstGLVideoMixer *video_mixer = GST_GL_VIDEO_MIXER (mixer);
+
+  return gst_gl_context_gen_shader (mixer->context, video_mixer_v_src,
+      video_mixer_f_src, &video_mixer->shader);
+}
+
+static gboolean
+gst_gl_video_mixer_process_textures (GstGLMixer * mix, GPtrArray * frames,
+    guint out_tex)
+{
+  GstGLVideoMixer *video_mixer = GST_GL_VIDEO_MIXER (mix);
+
+  video_mixer->input_frames = frames;
+
+  gst_gl_context_use_fbo_v2 (mix->context,
+      GST_VIDEO_INFO_WIDTH (&mix->out_info),
+      GST_VIDEO_INFO_HEIGHT (&mix->out_info), mix->fbo, mix->depthbuffer,
+      out_tex, gst_gl_video_mixer_callback, (gpointer) video_mixer);
+
+  return TRUE;
+}
+
+/* opengl scene, params: input texture (not the output mixer->texture) */
+static void
+gst_gl_video_mixer_callback (gpointer stuff)
+{
+  GstGLVideoMixer *video_mixer = GST_GL_VIDEO_MIXER (stuff);
+  GstGLMixer *mixer = GST_GL_MIXER (video_mixer);
+  GstGLFuncs *gl = mixer->context->gl_vtable;
+
+  GLint attr_position_loc = 0;
+  GLint attr_texture_loc = 0;
+  guint out_width, out_height;
+
+  const GLushort indices[] = {
+    0, 1, 2,
+    0, 2, 3
+  };
+
+  guint count = 0;
+
+  out_width = GST_VIDEO_INFO_WIDTH (&mixer->out_info);
+  out_height = GST_VIDEO_INFO_HEIGHT (&mixer->out_info);
+
+  gst_gl_context_clear_shader (mixer->context);
+  gl->BindTexture (GL_TEXTURE_2D, 0);
+  gl->Disable (GL_TEXTURE_2D);
+
+  gl->Disable (GL_DEPTH_TEST);
+  gl->Disable (GL_CULL_FACE);
+
+  gl->ClearColor (0.0, 0.0, 0.0, 0.0);
+  gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+  gst_gl_shader_use (video_mixer->shader);
+
+  attr_position_loc =
+      gst_gl_shader_get_attribute_location (video_mixer->shader, "a_position");
+  attr_texture_loc =
+      gst_gl_shader_get_attribute_location (video_mixer->shader, "a_texCoord");
+
+  gl->Enable (GL_BLEND);
+
+  while (count < video_mixer->input_frames->len) {
+    GstGLMixerFrameData *frame;
+    GLfloat *v_vertices;
+    guint in_tex;
+    guint in_width, in_height;
+    gfloat w, h;
+
+    frame = g_ptr_array_index (video_mixer->input_frames, count);
+    in_tex = frame->texture;
+    in_width = GST_VIDEO_INFO_WIDTH (&frame->pad->in_info);
+    in_height = GST_VIDEO_INFO_HEIGHT (&frame->pad->in_info);
+
+    if (!frame || !in_tex || in_width <= 0 || in_height <= 0) {
+      GST_DEBUG ("skipping texture:%u frame:%p width:%u height %u",
+          in_tex, frame, in_width, in_height);
+      count++;
+      continue;
+    }
+
+    GST_TRACE ("processing texture:%u dimensions:%ux%u", in_tex, in_width,
+        in_height);
+
+    w = ((gfloat) in_width / (gfloat) out_width);
+    h = ((gfloat) in_height / (gfloat) out_height);
+    GST_TRACE ("processing texture:%u dimensions:%ux%u, %fx%f", in_tex,
+        in_width, in_height, w, h);
+
+    /* *INDENT-OFF* */
+    v_vertices = (GLfloat[]) {
+      /* front face */
+      -1.0, -1.0, -1.0f,
+      0.0f, 0.0f,
+      1.0, -1.0, -1.0f,
+      1.0f, 0.0f,
+      1.0, 1.0, -1.0f,
+      1.0f, 1.0f,
+      -1.0, 1.0, -1.0f,
+      0.0f, 1.0f,
+    };
+    /* *INDENT-ON* */
+
+    gl->VertexAttribPointer (attr_position_loc, 3, GL_FLOAT,
+        GL_FALSE, 5 * sizeof (GLfloat), &v_vertices[0]);
+
+    gl->VertexAttribPointer (attr_texture_loc, 2, GL_FLOAT,
+        GL_FALSE, 5 * sizeof (GLfloat), &v_vertices[3]);
+
+    gl->EnableVertexAttribArray (attr_position_loc);
+    gl->EnableVertexAttribArray (attr_texture_loc);
+
+    gl->BlendFunc (GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR);
+    gl->BlendEquation (GL_FUNC_ADD);
+
+    gl->ActiveTexture (GL_TEXTURE0);
+    gl->BindTexture (GL_TEXTURE_2D, in_tex);
+    gst_gl_shader_set_uniform_1i (video_mixer->shader, "texture", 0);
+    gst_gl_shader_set_uniform_1f (video_mixer->shader, "x_scale", w);
+    gst_gl_shader_set_uniform_1f (video_mixer->shader, "y_scale", h);
+
+    gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
+
+    ++count;
+  }
+
+  gl->DisableVertexAttribArray (attr_position_loc);
+  gl->DisableVertexAttribArray (attr_texture_loc);
+
+  gl->BindTexture (GL_TEXTURE_2D, 0);
+
+  gl->Disable (GL_BLEND);
+
+  gst_gl_context_clear_shader (mixer->context);
+}
diff --git a/ext/gl/gstglvideomixer.h b/ext/gl/gstglvideomixer.h
new file mode 100644 (file)
index 0000000..716c60a
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * GStreamer
+ * Copyright (C) 2009 Julien Isorce <julien.isorce@gmail.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.
+ */
+
+#ifndef _GST_GL_VIDEO_MIXER_H_
+#define _GST_GL_VIDEO_MIXER_H_
+
+#include <gst/gl/gstglmixer.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_GL_VIDEO_MIXER            (gst_gl_video_mixer_get_type())
+#define GST_GL_VIDEO_MIXER(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_VIDEO_MIXER,GstGLVideoMixer))
+#define GST_IS_GL_VIDEO_MIXER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_VIDEO_MIXER))
+#define GST_GL_VIDEO_MIXER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_VIDEO_MIXER,GstGLVideoMixerClass))
+#define GST_IS_GL_VIDEO_MIXER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_VIDEO_MIXER))
+#define GST_GL_VIDEO_MIXER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_VIDEO_MIXER,GstGLVideoMixerClass))
+
+typedef struct _GstGLVideoMixer GstGLVideoMixer;
+typedef struct _GstGLVideoMixerClass GstGLVideoMixerClass;
+
+struct _GstGLVideoMixer
+{
+    GstGLMixer mixer;
+
+    GstGLShader *shader;
+    GPtrArray *input_frames;
+};
+
+struct _GstGLVideoMixerClass
+{
+    GstGLMixerClass mixer_class;
+};
+
+GType gst_gl_video_mixer_get_type (void);
+
+G_END_DECLS
+
+#endif /* _GST_GLFILTERCUBE_H_ */
diff --git a/ext/gl/gstopengl.c b/ext/gl/gstopengl.c
new file mode 100644 (file)
index 0000000..b439859
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * GStreamer
+ * Copyright (C) 2003 Julien Moutte <julien@moutte.net>
+ * Copyright (C) 2005,2006,2007 David A. Schleef <ds@schleef.org>
+ * Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.com>
+ * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.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.
+ */
+
+/**
+ * SECTION:plugin-opengl
+ *
+ * Cross-platform OpenGL plugin.
+ * <refsect2>
+ * <title>Debugging</title>
+ * </refsect2>
+ * <refsect2>
+ * <title>Examples</title>
+ * |[
+ * gst-launch-0.10 --gst-debug=gldisplay:3 videotestsrc ! glimagesink
+ * ]| A debugging pipeline.
+  |[
+ * GST_GL_SHADER_DEBUG=1 gst-launch-0.10 videotestsrc ! glimagesink
+ * ]| A debugging pipelines related to shaders.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef USE_EGL_RPI
+#include <bcm_host.h>
+#endif
+
+#include <gst/gl/gstglconfig.h>
+
+#include "gstglimagesink.h"
+
+#include "gstglfiltercube.h"
+#include "gstgleffects.h"
+#include "gstglcolorscale.h"
+
+GType gst_gl_filter_cube_get_type (void);
+GType gst_gl_effects_get_type (void);
+
+#if GST_GL_HAVE_OPENGL
+#include "gstgltestsrc.h"
+#include "gstglfilterlaplacian.h"
+#include "gstglfilterglass.h"
+#include "gstglfilterapp.h"
+#include "gstglfilterreflectedscreen.h"
+#include "gstglfiltershader.h"
+#include "gstgldeinterlace.h"
+#include "gstglmosaic.h"
+#include "gstglvideomixer.h"
+
+GType gst_gl_deinterlace_get_type (void);
+GType gst_gl_filter_app_get_type (void);
+GType gst_gl_filter_reflected_screen_get_type (void);
+GType gst_gl_filterblur_get_type (void);
+GType gst_gl_filtershader_get_type (void);
+GType gst_gl_filtersobel_get_type (void);
+GType gst_gl_filter_laplacian_get_type (void);
+GType gst_gl_filter_glass_get_type (void);
+GType gst_gl_mosaic_get_type (void);
+
+#if HAVE_PNG
+#include "gstgldifferencematte.h"
+#include "gstglbumper.h"
+
+GType gst_gl_differencematte_get_type (void);
+GType gst_gl_bumper_get_type (void);
+
+#if HAVE_JPEG
+#include "gstgloverlay.h"
+
+GType gst_gl_overlay_get_type (void);
+
+#endif /* HAVE_JPEG */
+#endif /* HAVE_PNG */
+#endif /* GST_GL_HAVE_OPENGL */
+
+#define GST_CAT_DEFAULT gst_gl_gstgl_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+/* Register filters that make up the gstgl plugin */
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (gst_gl_gstgl_debug, "gstopengl", 0, "gstopengl");
+
+#ifdef USE_EGL_RPI
+  GST_DEBUG ("Initialize BCM host");
+  bcm_host_init ();
+#endif
+
+  if (!gst_element_register (plugin, "glimagesink",
+          GST_RANK_MARGINAL, GST_TYPE_GLIMAGE_SINK)) {
+    return FALSE;
+  }
+
+  if (!gst_element_register (plugin, "glfiltercube",
+          GST_RANK_NONE, GST_TYPE_GL_FILTER_CUBE)) {
+    return FALSE;
+  }
+
+  if (!gst_element_register (plugin, "gleffects",
+          GST_RANK_NONE, gst_gl_effects_get_type ())) {
+    return FALSE;
+  }
+
+  if (!gst_element_register (plugin, "glcolorscale",
+          GST_RANK_NONE, GST_TYPE_GL_COLORSCALE)) {
+    return FALSE;
+  }
+#if GST_GL_HAVE_OPENGL
+  if (!gst_element_register (plugin, "gltestsrc",
+          GST_RANK_NONE, GST_TYPE_GL_TEST_SRC)) {
+    return FALSE;
+  }
+
+  if (!gst_element_register (plugin, "glfilterblur",
+          GST_RANK_NONE, gst_gl_filterblur_get_type ())) {
+    return FALSE;
+  }
+
+  if (!gst_element_register (plugin, "glshader",
+          GST_RANK_NONE, gst_gl_filtershader_get_type ())) {
+    return FALSE;
+  }
+
+  if (!gst_element_register (plugin, "glfiltersobel",
+          GST_RANK_NONE, gst_gl_filtersobel_get_type ())) {
+    return FALSE;
+  }
+
+  if (!gst_element_register (plugin, "glfilterlaplacian",
+          GST_RANK_NONE, GST_TYPE_GL_FILTER_LAPLACIAN)) {
+    return FALSE;
+  }
+
+  if (!gst_element_register (plugin, "glfilterglass",
+          GST_RANK_NONE, GST_TYPE_GL_FILTER_GLASS)) {
+    return FALSE;
+  }
+
+  if (!gst_element_register (plugin, "glfilterapp",
+          GST_RANK_NONE, GST_TYPE_GL_FILTER_APP)) {
+    return FALSE;
+  }
+
+  if (!gst_element_register (plugin, "glfilterreflectedscreen",
+          GST_RANK_NONE, GST_TYPE_GL_FILTER_REFLECTED_SCREEN)) {
+    return FALSE;
+  }
+
+  if (!gst_element_register (plugin, "gldeinterlace",
+          GST_RANK_NONE, GST_TYPE_GL_DEINTERLACE)) {
+    return FALSE;
+  }
+
+  if (!gst_element_register (plugin, "glmosaic",
+          GST_RANK_NONE, GST_TYPE_GL_MOSAIC)) {
+    return FALSE;
+  }
+
+  if (!gst_element_register (plugin, "glvideomixer",
+          GST_RANK_NONE, GST_TYPE_GL_VIDEO_MIXER)) {
+    return FALSE;
+  }
+#if HAVE_PNG
+  if (!gst_element_register (plugin, "gldifferencematte",
+          GST_RANK_NONE, gst_gl_differencematte_get_type ())) {
+    return FALSE;
+  }
+
+  if (!gst_element_register (plugin, "glbumper",
+          GST_RANK_NONE, gst_gl_bumper_get_type ())) {
+    return FALSE;
+  }
+#if HAVE_JPEG
+  if (!gst_element_register (plugin, "gloverlay",
+          GST_RANK_NONE, gst_gl_overlay_get_type ())) {
+    return FALSE;
+  }
+#endif /* HAVE_JPEG */
+#endif /* HAVE_PNG */
+#endif /* GST_GL_HAVE_OPENGL */
+
+  return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    opengl,
+    "OpenGL plugin",
+    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)