--- /dev/null
+
+known issues:
+
--- /dev/null
+
+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)
+
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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* */
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/* 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 = π
+ 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 = π
+ 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 = π
+ 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 = π
+ 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 = π
+ 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
+}
--- /dev/null
+/* 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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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_ */
+
--- /dev/null
+/*
+ * 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);
+
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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)