move gl elements to ext subdirectory

This commit is contained in:
Matthew Waters 2014-03-16 11:23:16 +01:00 committed by Tim-Philipp Müller
parent 4a18aa4b70
commit a884d6feee
59 changed files with 12789 additions and 0 deletions

3
ext/gl/BUGS Normal file
View file

@ -0,0 +1,3 @@
known issues:

96
ext/gl/Makefile.am Normal file
View file

@ -0,0 +1,96 @@
plugin_LTLIBRARIES = libgstopengl.la
AM_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
AM_LIBS = $(GST_BASE_LIBS) $(GST_PLUGINS_BASE_LIBS)
# full opengl required
if USE_OPENGL
OPENGL_SOURCES = \
gstglfiltershader.c \
gstglfiltershader.h \
gstglfilterblur.c \
gstglfilterblur.h \
gstglfiltersobel.c \
gstglfiltersobel.h \
gstglfilterlaplacian.c \
gstglfilterlaplacian.h \
gstglfilterglass.c \
gstglfilterglass.h \
gstglfilterapp.c \
gstglfilterapp.h \
gstglfilterreflectedscreen.c \
gstglfilterreflectedscreen.h \
gstgldeinterlace.c \
gstgldeinterlace.h \
gltestsrc.c \
gltestsrc.h \
gstgltestsrc.c \
gstgltestsrc.h \
gstglmosaic.c \
gstglmosaic.h \
gstglvideomixer.c \
gstglvideomixer.h \
effects/gstgleffectscurves.h \
effects/gstgleffectstretch.c \
effects/gstgleffecttunnel.c \
effects/gstgleffectfisheye.c \
effects/gstgleffecttwirl.c \
effects/gstgleffectbulge.c \
effects/gstgleffectsquare.c \
effects/gstgleffectlumatocurve.c \
effects/gstgleffectlumatocurve.h \
effects/gstgleffectrgbtocurve.c \
effects/gstgleffectsin.c \
effects/gstgleffectglow.c \
effects/gstgleffectxray.c
if HAVE_PNG
OPENGL_SOURCES += \
gstglbumper.c \
gstglbumper.h \
gstgldifferencematte.c \
gstgldifferencematte.h
if HAVE_JPEG
OPENGL_SOURCES += \
gstgloverlay.c \
gstgloverlay.h
endif
endif
endif
libgstopengl_la_SOURCES = \
gstopengl.c \
gstglimagesink.c \
gstglimagesink.h \
gstglfiltercube.c \
gstglfiltercube.h \
gstgleffects.c \
gstgleffects.h \
effects/gstgleffectssources.c \
effects/gstgleffectssources.h \
effects/gstgleffectidentity.c \
effects/gstgleffectmirror.c \
effects/gstgleffectsqueeze.c \
gstglcolorscale.c \
gstglcolorscale.h \
$(OPENGL_SOURCES)
# check order of CFLAGS and LIBS, shouldn't the order be the other way around
# (like in AM_CFLAGS)?
libgstopengl_la_CFLAGS = -I$(top_srcdir)/gst-libs $(GST_CFLAGS) $(GST_BASE_CFLAGS) \
$(GST_PLUGINS_BASE_CFLAGS) $(GL_CFLAGS) $(LIBPNG_CFLAGS)
libgstopengl_la_LIBADD = \
$(top_builddir)/gst-libs/gst/gl/libgstgl-$(GST_API_VERSION).la \
$(GST_BASE_LIBS) \
$(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_API_VERSION) \
-lgstpbutils-$(GST_API_VERSION) \
$(GL_LIBS) \
$(LIBPNG_LIBS) \
$(JPEG_LIBS) \
$(LIBM)
libgstopengl_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstopengl_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)

View file

@ -0,0 +1,75 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstgleffects.h"
static void
gst_gl_effects_bulge_callback (gint width, gint height, guint texture,
gpointer data)
{
GstGLShader *shader;
GstGLEffects *effects = GST_GL_EFFECTS (data);
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLContext *context = filter->context;
GstGLFuncs *gl = context->gl_vtable;
shader = g_hash_table_lookup (effects->shaderstable, "bulge0");
if (!shader) {
shader = gst_gl_shader_new (context);
g_hash_table_insert (effects->shaderstable, "bulge0", shader);
}
if (!gst_gl_shader_compile_and_check (shader,
bulge_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
gst_gl_context_set_error (context, "Failed to initialize bulge shader");
GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
("%s", gst_gl_context_get_error ()), (NULL));
return;
}
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gst_gl_shader_use (shader);
gl->ActiveTexture (GL_TEXTURE0);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gst_gl_shader_set_uniform_1i (shader, "tex", 0);
gst_gl_shader_set_uniform_1f (shader, "width", (gfloat) width / 2.0f);
gst_gl_shader_set_uniform_1f (shader, "height", (gfloat) height / 2.0f);
gst_gl_filter_draw_texture (filter, texture, width, height);
}
void
gst_gl_effects_bulge (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
effects->outtexture, gst_gl_effects_bulge_callback, effects);
}

View file

@ -0,0 +1,75 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstgleffects.h"
static void
gst_gl_effects_fisheye_callback (gint width, gint height, guint texture,
gpointer data)
{
GstGLShader *shader;
GstGLEffects *effects = GST_GL_EFFECTS (data);
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLContext *context = filter->context;
GstGLFuncs *gl = context->gl_vtable;
shader = g_hash_table_lookup (effects->shaderstable, "fisheye0");
if (!shader) {
shader = gst_gl_shader_new (context);
g_hash_table_insert (effects->shaderstable, "fisheye0", shader);
}
if (!gst_gl_shader_compile_and_check (shader,
fisheye_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
gst_gl_context_set_error (context, "Failed to initialize fisheye shader");
GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
("%s", gst_gl_context_get_error ()), (NULL));
return;
}
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gst_gl_shader_use (shader);
gl->ActiveTexture (GL_TEXTURE0);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gst_gl_shader_set_uniform_1i (shader, "tex", 0);
gst_gl_shader_set_uniform_1f (shader, "width", (gfloat) width / 2.0f);
gst_gl_shader_set_uniform_1f (shader, "height", (gfloat) height / 2.0f);
gst_gl_filter_draw_texture (filter, texture, width, height);
}
void
gst_gl_effects_fisheye (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
effects->outtexture, gst_gl_effects_fisheye_callback, effects);
}

View file

@ -0,0 +1,223 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstgleffects.h"
static gboolean kernel_ready = FALSE;
static float gauss_kernel[7];
static void
gst_gl_effects_glow_step_one (gint width, gint height, guint texture,
gpointer data)
{
GstGLShader *shader;
GstGLEffects *effects = GST_GL_EFFECTS (data);
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLContext *context = filter->context;
GstGLFuncs *gl = context->gl_vtable;
shader = g_hash_table_lookup (effects->shaderstable, "glow0");
if (!shader) {
shader = gst_gl_shader_new (context);
g_hash_table_insert (effects->shaderstable, "glow0", shader);
}
if (!gst_gl_shader_compile_and_check (shader,
luma_threshold_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
gst_gl_context_set_error (context,
"Failed to initialize luma threshold shader");
GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
("%s", gst_gl_context_get_error ()), (NULL));
return;
}
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gst_gl_shader_use (shader);
gl->ActiveTexture (GL_TEXTURE0);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gst_gl_shader_set_uniform_1i (shader, "tex", 0);
gst_gl_filter_draw_texture (filter, texture, width, height);
}
static void
gst_gl_effects_glow_step_two (gint width, gint height, guint texture,
gpointer data)
{
GstGLShader *shader;
GstGLEffects *effects = GST_GL_EFFECTS (data);
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLContext *context = filter->context;
GstGLFuncs *gl = context->gl_vtable;
shader = g_hash_table_lookup (effects->shaderstable, "glow1");
if (!shader) {
shader = gst_gl_shader_new (context);
g_hash_table_insert (effects->shaderstable, "glow1", shader);
}
if (!kernel_ready) {
fill_gaussian_kernel (gauss_kernel, 7, 10.0);
kernel_ready = TRUE;
}
if (!gst_gl_shader_compile_and_check (shader,
hconv7_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
gst_gl_context_set_error (context, "Failed to initialize hconv7 shader");
GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
("%s", gst_gl_context_get_error ()), (NULL));
return;
}
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gst_gl_shader_use (shader);
gl->ActiveTexture (GL_TEXTURE1);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gl->Disable (GL_TEXTURE_2D);
gst_gl_shader_set_uniform_1i (shader, "tex", 1);
gst_gl_shader_set_uniform_1fv (shader, "kernel", 7, gauss_kernel);
gst_gl_shader_set_uniform_1f (shader, "height", height);
gst_gl_filter_draw_texture (filter, texture, width, height);
}
void
gst_gl_effects_glow_step_three (gint width, gint height, guint texture,
gpointer data)
{
GstGLShader *shader;
GstGLEffects *effects = GST_GL_EFFECTS (data);
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLContext *context = filter->context;
GstGLFuncs *gl = context->gl_vtable;
shader = g_hash_table_lookup (effects->shaderstable, "glow2");
if (!shader) {
shader = gst_gl_shader_new (context);
g_hash_table_insert (effects->shaderstable, "glow2", shader);
}
if (!gst_gl_shader_compile_and_check (shader,
vconv7_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
gst_gl_context_set_error (context, "Failed to initialize vcon7 shader");
GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
("%s", gst_gl_context_get_error ()), (NULL));
return;
}
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gst_gl_shader_use (shader);
gl->ActiveTexture (GL_TEXTURE1);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gl->Disable (GL_TEXTURE_2D);
gst_gl_shader_set_uniform_1i (shader, "tex", 1);
gst_gl_shader_set_uniform_1fv (shader, "kernel", 7, gauss_kernel);
gst_gl_shader_set_uniform_1f (shader, "width", width);
gst_gl_filter_draw_texture (filter, texture, width, height);
}
void
gst_gl_effects_glow_step_four (gint width, gint height, guint texture,
gpointer data)
{
GstGLShader *shader;
GstGLEffects *effects = GST_GL_EFFECTS (data);
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLContext *context = filter->context;
GstGLFuncs *gl = context->gl_vtable;
shader = g_hash_table_lookup (effects->shaderstable, "glow3");
if (!shader) {
shader = gst_gl_shader_new (context);
g_hash_table_insert (effects->shaderstable, "glow3", shader);
}
if (!gst_gl_shader_compile_and_check (shader,
sum_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
gst_gl_context_set_error (context, "Failed to initialize sum shader");
GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
("%s", gst_gl_context_get_error ()), (NULL));
return;
}
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gst_gl_shader_use (shader);
gl->ActiveTexture (GL_TEXTURE2);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, effects->intexture);
gl->Disable (GL_TEXTURE_2D);
gst_gl_shader_set_uniform_1f (shader, "alpha", 1.0);
gst_gl_shader_set_uniform_1i (shader, "base", 2);
gl->ActiveTexture (GL_TEXTURE1);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gl->Disable (GL_TEXTURE_2D);
gst_gl_shader_set_uniform_1f (shader, "beta", (gfloat) 1 / 3.5f);
gst_gl_shader_set_uniform_1i (shader, "blend", 1);
gst_gl_filter_draw_texture (filter, texture, width, height);
}
void
gst_gl_effects_glow (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
/* threshold */
gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
effects->midtexture[0], gst_gl_effects_glow_step_one, effects);
/* blur */
gst_gl_filter_render_to_target (filter, FALSE, effects->midtexture[0],
effects->midtexture[1], gst_gl_effects_glow_step_two, effects);
gst_gl_filter_render_to_target (filter, FALSE, effects->midtexture[1],
effects->midtexture[2], gst_gl_effects_glow_step_three, effects);
/* add blurred luma to intexture */
gst_gl_filter_render_to_target (filter, FALSE, effects->midtexture[2],
effects->outtexture, gst_gl_effects_glow_step_four, effects);
}

View file

@ -0,0 +1,95 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstgleffects.h"
#define USING_OPENGL(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_OPENGL)
#define USING_OPENGL3(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_OPENGL3)
#define USING_GLES(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES)
#define USING_GLES2(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES2)
#define USING_GLES3(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES3)
static void
gst_gl_effects_identity_callback (gint width, gint height, guint texture,
gpointer data)
{
GstGLEffects *effects = GST_GL_EFFECTS (data);
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLContext *context = filter->context;
GstGLFuncs *gl = context->gl_vtable;
#if GST_GL_HAVE_OPENGL
if (USING_OPENGL (context)) {
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
}
#endif
#if GST_GL_HAVE_GLES2
if (USING_GLES2 (context)) {
GstGLShader *shader =
g_hash_table_lookup (effects->shaderstable, "identity0");
if (!shader) {
shader = gst_gl_shader_new (context);
g_hash_table_insert (effects->shaderstable, "identity0", shader);
if (shader) {
GError *error = NULL;
gst_gl_shader_set_vertex_source (shader, vertex_shader_source);
gst_gl_shader_set_fragment_source (shader, identity_fragment_source);
gst_gl_shader_compile (shader, &error);
if (error) {
GST_ERROR ("%s", error->message);
g_error_free (error);
error = NULL;
gst_gl_shader_use (NULL);
} else {
filter->draw_attr_position_loc =
gst_gl_shader_get_attribute_location (shader, "a_position");
filter->draw_attr_texture_loc =
gst_gl_shader_get_attribute_location (shader, "a_texCoord");
}
}
}
gst_gl_shader_use (shader);
gl->ActiveTexture (GL_TEXTURE0);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gst_gl_shader_set_uniform_1i (shader, "tex", 0);
}
#endif
gst_gl_filter_draw_texture (filter, texture, width, height);
}
void
gst_gl_effects_identity (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
effects->outtexture, gst_gl_effects_identity_callback, effects);
}

View file

@ -0,0 +1,148 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstgleffects.h"
#include "gstgleffectlumatocurve.h"
void
gst_gl_effects_luma_to_curve (GstGLEffects * effects,
GstGLEffectsCurve curve,
gint curve_index, gint width, gint height, GLuint texture)
{
GstGLShader *shader;
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLContext *context = filter->context;
GstGLFuncs *gl = context->gl_vtable;
shader = g_hash_table_lookup (effects->shaderstable, "lumamap0");
if (!shader) {
shader = gst_gl_shader_new (context);
g_hash_table_insert (effects->shaderstable, "lumamap0", shader);
}
if (!gst_gl_shader_compile_and_check (shader,
luma_to_curve_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
gst_gl_context_set_error (context,
"Failed to initialize luma to curve shader");
GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
("%s", gst_gl_context_get_error ()), (NULL));
return;
}
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gst_gl_shader_use (shader);
if (effects->curve[curve_index] == 0) {
/* this parameters are needed to have a right, predictable, mapping */
gl->GenTextures (1, &effects->curve[curve_index]);
gl->Enable (GL_TEXTURE_1D);
gl->BindTexture (GL_TEXTURE_1D, effects->curve[curve_index]);
gl->TexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
gl->TexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
gl->TexParameteri (GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
gl->TexParameteri (GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP);
gl->TexImage1D (GL_TEXTURE_1D, 0, curve.bytes_per_pixel,
curve.width, 0, GL_RGB, GL_UNSIGNED_BYTE, curve.pixel_data);
gl->Disable (GL_TEXTURE_1D);
}
gl->ActiveTexture (GL_TEXTURE2);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gst_gl_shader_set_uniform_1i (shader, "tex", 2);
gl->Disable (GL_TEXTURE_2D);
gl->ActiveTexture (GL_TEXTURE1);
gl->Enable (GL_TEXTURE_1D);
gl->BindTexture (GL_TEXTURE_1D, effects->curve[curve_index]);
gst_gl_shader_set_uniform_1i (shader, "curve", 1);
gl->Disable (GL_TEXTURE_1D);
gst_gl_filter_draw_texture (filter, texture, width, height);
}
static void
gst_gl_effects_heat_callback (gint width, gint height, guint texture,
gpointer data)
{
GstGLEffects *effects = GST_GL_EFFECTS (data);
gst_gl_effects_luma_to_curve (effects, heat_curve, GST_GL_EFFECTS_CURVE_HEAT,
width, height, texture);
}
void
gst_gl_effects_heat (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
effects->outtexture, gst_gl_effects_heat_callback, effects);
}
static void
gst_gl_effects_sepia_callback (gint width, gint height, guint texture,
gpointer data)
{
GstGLEffects *effects = GST_GL_EFFECTS (data);
gst_gl_effects_luma_to_curve (effects, sepia_curve,
GST_GL_EFFECTS_CURVE_SEPIA, width, height, texture);
}
void
gst_gl_effects_sepia (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
effects->outtexture, gst_gl_effects_sepia_callback, effects);
}
static void
gst_gl_effects_luma_xpro_callback (gint width, gint height, guint texture,
gpointer data)
{
GstGLEffects *effects = GST_GL_EFFECTS (data);
gst_gl_effects_luma_to_curve (effects, luma_xpro_curve,
GST_GL_EFFECTS_CURVE_LUMA_XPRO, width, height, texture);
}
void
gst_gl_effects_luma_xpro (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
effects->outtexture, gst_gl_effects_luma_xpro_callback, effects);
}

View file

@ -0,0 +1,35 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_GL_LUMA_TO_CURVE_H__
#define __GST_GL_LUMA_TO_CURVE_H__
#include "gstgleffectscurves.h"
G_BEGIN_DECLS
void gst_gl_effects_luma_to_curve (GstGLEffects *effects,
GstGLEffectsCurve curve,
gint curve_index,
gint width, gint height,
GLuint texture);
G_END_DECLS
#endif /* __GST_GL_LUMA_TO_CURVE_H__ */

View file

@ -0,0 +1,120 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstgleffects.h"
#define USING_OPENGL(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_OPENGL)
#define USING_OPENGL3(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_OPENGL3)
#define USING_GLES(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES)
#define USING_GLES2(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES2)
#define USING_GLES3(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES3)
static void
gst_gl_effects_mirror_callback (gint width, gint height, guint texture,
gpointer data)
{
GstGLShader *shader;
GstGLFilter *filter = GST_GL_FILTER (data);
GstGLEffects *effects = GST_GL_EFFECTS (filter);
GstGLContext *context = filter->context;
GstGLFuncs *gl = context->gl_vtable;
shader = g_hash_table_lookup (effects->shaderstable, "mirror0");
if (!shader) {
shader = gst_gl_shader_new (context);
g_hash_table_insert (effects->shaderstable, "mirror0", shader);
#if GST_GL_HAVE_GLES2
if (USING_GLES2 (context)) {
if (shader) {
GError *error = NULL;
gst_gl_shader_set_vertex_source (shader, vertex_shader_source);
gst_gl_shader_set_fragment_source (shader,
mirror_fragment_source_gles2);
gst_gl_shader_compile (shader, &error);
if (error) {
gst_gl_context_set_error (context,
"Failed to initialize mirror shader, %s", error->message);
g_error_free (error);
error = NULL;
gst_gl_shader_use (NULL);
GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
("%s", gst_gl_context_get_error ()), (NULL));
} else {
filter->draw_attr_position_loc =
gst_gl_shader_get_attribute_location (shader, "a_position");
filter->draw_attr_texture_loc =
gst_gl_shader_get_attribute_location (shader, "a_texCoord");
}
}
}
#endif
#if GST_GL_HAVE_OPENGL
if (USING_OPENGL (context)) {
if (!gst_gl_shader_compile_and_check (shader,
mirror_fragment_source_opengl, GST_GL_SHADER_FRAGMENT_SOURCE)) {
gst_gl_context_set_error (context,
"Failed to initialize mirror shader");
GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
("%s", gst_gl_context_get_error ()), (NULL));
return;
}
}
#endif
}
#if GST_GL_HAVE_OPENGL
if (USING_OPENGL (context)) {
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
}
#endif
gst_gl_shader_use (shader);
gl->ActiveTexture (GL_TEXTURE0);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gst_gl_shader_set_uniform_1i (shader, "tex", 0);
#if GST_GL_HAVE_OPENGL
if (USING_OPENGL (filter->context)) {
gst_gl_shader_set_uniform_1f (shader, "width", (gfloat) width / 2.0f);
gst_gl_shader_set_uniform_1f (shader, "height", (gfloat) height / 2.0f);
}
#endif
gst_gl_filter_draw_texture (filter, texture, width, height);
}
void
gst_gl_effects_mirror (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
effects->outtexture, gst_gl_effects_mirror_callback, effects);
}

View file

@ -0,0 +1,110 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstgleffects.h"
#include "gstgleffectscurves.h"
static void
gst_gl_effects_rgb_to_curve (GstGLEffects * effects,
GstGLEffectsCurve curve,
gint curve_index, gint width, gint height, GLuint texture)
{
GstGLShader *shader;
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLContext *context = filter->context;
GstGLFuncs *gl = context->gl_vtable;
shader = g_hash_table_lookup (effects->shaderstable, "rgbmap0");
if (!shader) {
shader = gst_gl_shader_new (context);
g_hash_table_insert (effects->shaderstable, "rgbmap0", shader);
}
if (!gst_gl_shader_compile_and_check (shader,
rgb_to_curve_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
gst_gl_context_set_error (context,
"Failed to initialize rgb to curve shader");
GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
("%s", gst_gl_context_get_error ()), (NULL));
return;
}
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gst_gl_shader_use (shader);
if (effects->curve[curve_index] == 0) {
/* this parameters are needed to have a right, predictable, mapping */
gl->GenTextures (1, &effects->curve[curve_index]);
gl->Enable (GL_TEXTURE_1D);
gl->BindTexture (GL_TEXTURE_1D, effects->curve[curve_index]);
gl->TexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
gl->TexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
gl->TexParameteri (GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
gl->TexParameteri (GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP);
gl->TexImage1D (GL_TEXTURE_1D, 0, curve.bytes_per_pixel,
curve.width, 0, GL_RGB, GL_UNSIGNED_BYTE, curve.pixel_data);
gl->Disable (GL_TEXTURE_1D);
}
gl->ActiveTexture (GL_TEXTURE0);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gst_gl_shader_set_uniform_1i (shader, "tex", 0);
gl->Disable (GL_TEXTURE_2D);
gl->ActiveTexture (GL_TEXTURE1);
gl->Enable (GL_TEXTURE_1D);
gl->BindTexture (GL_TEXTURE_1D, effects->curve[curve_index]);
gst_gl_shader_set_uniform_1i (shader, "curve", 1);
gl->Disable (GL_TEXTURE_1D);
gst_gl_filter_draw_texture (filter, texture, width, height);
}
static void
gst_gl_effects_xpro_callback (gint width, gint height, guint texture,
gpointer data)
{
GstGLEffects *effects = GST_GL_EFFECTS (data);
gst_gl_effects_rgb_to_curve (effects, xpro_curve, GST_GL_EFFECTS_CURVE_XPRO,
width, height, texture);
}
void
gst_gl_effects_xpro (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
effects->outtexture, gst_gl_effects_xpro_callback, effects);
}

View file

@ -0,0 +1,212 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_GL_EFFECTS_TEXTURES_H__
#define __GST_GL_EFFECTS_TEXTURES_H__
struct _GstGLEffectsCurve {
guint width;
guint height;
guint bytes_per_pixel; /* 3:RGB */
guint8 pixel_data[256 * 1 * 3 + 1];
};
typedef struct _GstGLEffectsCurve GstGLEffectsCurve;
/* CURVE for the heat signature effect */
static const GstGLEffectsCurve xpro_curve = {
256, 1, 3,
"\0\0\37\0\0\37\0\1\40\0\2!\0\2\"\0\3\"\1\4%\1\4%\1\5%\1\5'\1\7'\1\7(\1\7"
"(\1\10*\1\11+\1\11,\1\12,\1\13/\1\14/\1\14""1\2\15""1\2\15""1\2\16""4\2\17"
"""4\3\17""5\3\22""7\3\22""7\3\23""8\3\24""9\3\25;\3\26;\3\27<\3\27=\4\31"
"=\4\33?\4\34@\5\34B\5\35C\5\36D\5\40D\5\40G\5!G\6\"H\6$H\7&J\7&K\7*M\7*M"
"\10+N\10-P\11-P\11/R\11""3R\11""3T\12""4U\12""5U\13""7W\14""8Y\14""9Y\14"
"<Y\16=[\16@^\16@^\17C^\17D`\20F`\20Jb\22Jb\22Kc\23Me\24Nf\25Qg\26Rg\27Ti"
"\27Wj\30Xl\31Yl\33\\m\34^p\35`p\40bp\40fq!fr$gt$lt%lu'mv(px*qy-ty/uz/x|0"
"y}3|}4}~5\177\2018\203\2019\203\201;\204\202=\207\203?\210\204@\214\204C"
"\214\206D\216\207G\217\210H\223\211K\223\211M\225\212P\226\214Q\231\215T"
"\232\215U\234\216X\235\217Y\240\220\\\241\220^\243\221`\244\223b\246\224"
"e\250\224f\252\225i\253\226l\255\227m\256\231p\261\231q\262\232t\264\233"
"v\265\234x\267\234z\270\235|\271\236~\274\240\201\275\240\202\277\241\204"
"\300\242\207\302\243\210\303\243\212\305\244\214\306\245\216\307\246\220"
"\311\250\221\313\250\224\315\251\226\316\252\227\317\253\232\321\253\234"
"\322\254\235\323\255\240\325\256\242\326\256\242\330\256\245\331\261\250"
"\331\262\251\332\262\253\334\263\255\335\264\256\336\265\261\340\266\263"
"\341\266\264\342\267\266\343\270\270\344\271\271\344\271\271\346\273\276"
"\347\274\277\350\275\277\351\275\302\352\276\304\353\277\306\353\300\307"
"\355\300\311\356\301\314\356\302\315\357\303\317\360\304\320\360\304\322"
"\361\305\323\362\306\325\362\307\327\363\307\330\363\310\330\364\311\333"
"\364\313\334\365\313\336\365\314\340\365\314\342\366\316\342\366\316\346"
"\367\317\347\367\320\351\367\320\353\370\322\354\370\322\356\370\323\356"
"\370\324\360\371\325\360\371\325\363\371\326\363\371\327\363\372\330\365"
"\372\330\366\372\331\366\372\331\370\372\332\371\373\332\371\373\333\372"
"\373\334\373\373\335\373\373\336\374\373\336\374\374\337\374\374\340\375"
"\374\341\375\374\341\376\374\342\376\374\343\376\374\344\376\374\344\377"
"\374\345\377\374\346\377\375\346\377\375\346\377\375\347\377\375\350\377"
"\375\351\377\375\352\377\375\352\377\375\352\377\375\353\377\375\353\377"
"\376\354\377\376\354\377\376\356\377\376\356\377\376\356\377\376\357\377"
"\376\360\377\376\360\377\376\360\377\376\360\377\376\362\377\376\362\377"
"\376\363\377\376\363\377\376\363\377\376\363\377\376\364\377\376\364\377"
"\376\365\377\377\365\377\377\366\377\377\366\377\377\366\377\377\367\377"
"\377\367\377\377\367\377\377\370",
};
static const GstGLEffectsCurve luma_xpro_curve = {
256, 1, 3,
"\0\0\1\0\1\1\0\1\2\0\1\2\0\1\2\0\1\2\0\1\3\0\2\3\0\2\4\0\2\4\0\2\5\0\2\6"
"\0\3\6\0\3\6\0\3\7\0\3\10\0\4\10\0\4\11\0\4\12\0\4\12\1\4\13\1\5\14\1\5\15"
"\1\5\15\1\5\16\1\5\17\1\6\17\1\6\20\1\7\21\1\7\23\2\10\23\2\10\24\2\10\24"
"\2\11\26\2\11\27\2\11\30\3\11\31\3\12\31\3\13\32\3\13\33\4\13\34\4\14\35"
"\4\14\36\4\15\37\5\15\40\5\15\"\6\16#\6\17#\6\20$\7\20%\7\20%\10\21&\10\22"
"'\10\22)\11\24*\11\24*\12\24+\12\26.\13\26.\14\27.\14\30/\15\31""1\15\31"
"""2\16\32""3\16\33""3\20\33""5\20\35""6\20\36""7\22\37""7\23\"9\23#9\24$"
":\25$<\27&<\27'=\31'?\31)?\32*@\35+B\35-C\36.C\37""1E\"2F#3H$5H&6I'7I)7K"
"+:M-<N-<N1@N1BQ2BQ6CQ6EU7HU<IU=IV@NX@NXBQZCS[FU[HU]IV_MZ_N[_Q]`S_bU`dXbe"
"Zbe]gg]ig`ji`jjdljenlgpljqnpwppwpqxqszqw|sx}u|\201u}\203w\177\204x\177\206"
"x\204\210x\204\212z\212\213|\212\217}\217\221}\221\222}\222\224\177\226\224"
"\201\226\226\203\230\233\203\235\235\204\236\235\204\236\236\210\244\242"
"\210\244\242\210\245\244\212\251\245\213\252\251\213\254\252\215\257\254"
"\215\261\256\217\261\257\221\266\261\221\267\261\222\273\264\224\273\267"
"\224\274\267\224\276\273\230\301\273\230\302\274\231\304\276\231\307\302"
"\233\312\302\235\312\304\235\314\306\236\316\307\240\320\311\240\321\314"
"\242\324\315\242\325\316\244\327\320\245\332\321\245\333\321\245\334\323"
"\251\335\325\251\335\330\252\341\332\254\341\332\256\344\334\256\346\334"
"\256\347\337\257\347\340\261\350\340\263\351\342\263\352\344\264\354\345"
"\266\355\346\266\356\347\267\357\350\271\360\351\273\361\352\273\362\352"
"\274\362\355\276\364\356\277\364\357\277\365\360\277\365\360\302\366\361"
"\302\367\361\304\370\363\304\370\363\307\370\364\307\371\364\311\371\366"
"\312\372\367\312\372\367\314\372\367\316\373\370\316\373\370\320\373\371"
"\320\374\371\321\374\372\323\374\372\324\375\372\325\375\372\325\375\373"
"\327\375\373\330\375\374\332\375\374\333\375\375\334\376\375\334\376\375"
"\335\376\375\337\376\375\337\376\375\340\376\376\342\376\376\344\376\376"
"\344\376\376\345\376\376\346\376\376\347\376\376\350\377\376\351\377\377"
"\353\377\377\354\377\377\356\377\377\357\377\377\361\377\377\361\377\377"
"\361\377\377\364\377\377\365\377\377\366\377\377\367\377\377\367\377\377"
"\371\377\377\371\377\377\372\377\377\373\377\377\373\377\377\374\377\377"
"\375\377\377\375\377\377\375\377\377\376",
};
/* CURVE for the heat signature effect */
static const GstGLEffectsCurve heat_curve = {
256, 1, 3,
"\0\0\0\0\0\0\0\1\0\0\1\0\0\1\1\0\2\1\0\2\1\1\2\1\1\2\2\1\2\2\1\3\2\1\3\3"
"\1\3\3\1\4\3\1\4\4\1\5\4\1\5\5\2\5\6\2\6\6\2\6\7\2\6\7\2\7\7\2\7\11\2\10"
"\11\2\10\12\3\11\13\3\11\13\3\11\14\3\12\15\3\12\17\3\13\17\3\14\20\3\14"
"\22\4\15\23\4\16\24\4\16\26\4\16\27\4\17\31\4\20\34\4\21\34\5\21\40\5\22"
"\40\5\22$\5\23$\5\25&\6\25(\6\26-\6\26-\6\27""0\6\31""2\7\31""5\7\32;\7\34"
";\7\34?\10\35C\10\36G\10\37L\10\40V\11!V\11\"[\11$a\11&l\12&l\12'r\12(~\13"
"*~\13,\204\14,\213\14.\221\14/\227\14""1\236\15""2\244\15""4\252\15""5\260"
"\16""7\267\16""8\275\17:\302\17;\310\17=\323\20?\323\21@\330\21D\335\21D"
"\342\22E\346\22I\353\23I\356\23K\362\24M\365\24N\370\25P\372\26R\374\26T"
"\376\26V\377\27X\377\27Z\377\30\\\376\31`\376\31`\375\32b\373\32d\371\33"
"f\366\34j\363\34j\360\35l\354\36n\350\36r\344\37r\337\40t\333\40w\326!y\321"
"\"|\314#~\307$\201\301$\204\267%\207\267&\212\261'\214\254(\217\247(\222"
"\241)\226\234*\231\227+\234\222,\237\216-\242\211.\245\205/\251\2010\254"
"}1\257z2\262w3\266t4\271p5\274m6\277j7\302f8\305c9\310`:\314\\;\317Y<\321"
"V>\324S?\327P@\332LA\335IB\337FC\342CE\344@F\347=G\351;I\3538I\3558M\357"
"3P\3610S\363.V\365+Y\366)\\\370'`\371%d\372#g\373\"l\374\40p\374\37t\374"
"\35t\375\34}\376\33\202\376\32\202\375\31\213\375\30\220\375\27\225\375\27"
"\232\373\26\237\372\25\244\371\24\251\370\23\256\367\23\262\367\22\267\364"
"\21\274\362\20\300\361\20\305\357\17\311\355\16\311\353\16\322\351\15\326"
"\346\15\332\346\14\336\344\14\341\337\13\341\335\13\350\332\12\353\330\11"
"\356\330\11\360\322\10\362\320\10\364\320\10\364\312\7\366\307\7\366\304"
"\7\367\302\6\367\277\6\370\274\5\367\271\5\367\271\5\367\263\4\365\260\4"
"\364\255\4\363\253\3\362\250\3\361\245\3\360\242\3\357\240\3\357\235\2\355"
"\232\2\355\227\2\354\225\2\353\221\1\353\216\1\353\216\1\353\213\1\353\204"
"\1\353\201\1\354}\1\354y\0\354v\0\355r\0\355n\0\355j\0\356f\0\356b\0\357"
"_\0\357[\0\357W\0\357S\0\360O\0\360O\0\361K\0\361C\0\362@\0\363<\0\3638\0"
"\3648\0\3641\0\365.\0\366+\0\366'\0\367'\0\370!\0\370\36\0\370\33\0\371\30"
"\0\371\26\0\373\26\0\373\23\0\374\15\0\374\13\0\375\10\0\375\5\0\376\3\0",
};
static const GstGLEffectsCurve sepia_curve = {
256, 1, 3,
"\0\0\0\0\0\0\0\0\0\0\1\0\1\1\0\1\1\0\1\1\1\2\1\1\2\2\1\3\2\1\3\2\1\3\2\1"
"\4\3\2\4\3\2\4\3\2\6\4\2\6\4\2\6\4\2\7\5\2\7\5\3\11\6\3\11\6\3\12\7\3\13"
"\10\3\15\10\4\16\11\4\17\11\4\21\12\4\22\13\4\22\13\5\23\14\5\24\15\5\26"
"\16\6\31\20\6\31\21\6\32\22\7\34\22\7\35\23\7\40\24\10\40\26\10!\26\11#\30"
"\11&\31\12&\32\12'\34\13)\34\13*\37\13,\37\13-\40\14.\"\15""0\"\15""2#\17"
"""3&\17""4&\17""5'\20""8(\21""9)\21:*\23<,\23=-\23A.\24A0\25B0\25C2\26D3"
"\30H4\30H7\31K7\32K8\32L9\33M:\34P<\34Q=\35S>\37T?\37UA\40VB!XC!ZD#\\F#^"
"G#^J$`J&bK'bM'eM(fO)gP)iQ*kS,mT-mU-nV.oX/rY0sZ2u]2v]3w^3x`4za5{c7|c8~e8\177"
"f9\200i:\203i<\204j<\206k=\207m>\210n?\211o?\213qA\214rC\215sC\217uD\220"
"vD\221wF\223xG\224zH\225{J\227|K\230~K\231\177L\232\200M\234\202O\235\203"
"P\236\204Q\240\206Q\241\207S\242\210T\243\211U\245\213V\246\214X\247\215"
"Y\250\217Y\252\220Z\253\221\\\254\223]\254\224^\255\225`\257\227a\260\230"
"b\261\231c\262\232e\264\234e\265\235f\266\236g\267\240i\267\241i\272\242"
"k\273\243m\274\245n\274\246o\276\247q\277\250r\300\252s\301\253u\302\254"
"v\304\255w\305\257x\306\257z\306\261{\307\262|\310\264~\310\265\177\313\266"
"\200\314\267\202\315\267\203\316\272\204\317\273\206\317\274\207\320\276"
"\210\322\277\211\323\277\213\324\301\214\325\302\215\326\304\217\326\305"
"\220\327\306\221\327\307\223\331\310\224\333\311\225\334\311\227\334\313"
"\227\335\315\231\335\316\231\337\317\234\340\320\235\341\320\235\341\323"
"\240\342\324\241\343\324\242\343\326\243\345\327\245\345\330\245\346\331"
"\250\346\333\252\347\334\253\351\335\254\351\335\255\351\337\257\352\340"
"\260\353\341\260\354\342\262\355\343\264\355\344\265\355\345\266\356\346"
"\266\356\347\272\357\350\273\360\351\274\360\351\276\361\352\277\361\353"
"\300\362\353\301\362\354\302\362\355\304\362\356\305\364\357\305\364\357"
"\310\364\360\311\365\361\313\365\361\314\366\362\315\366\362\316\366\363"
"\316\367\364\320\367\364\320\367\365\324\367\365\324\370\366\326\370\366"
"\327\371\366\330\371\367\331\371\367\333\371\370\333\372\370\336\372\370"
"\336\372\371\340\373\371\341\373\372\342\373\372\343\374\372\344\374\373"
"\344\374\373\347\374\374\350\375\374\351\375\374\351\375\374\352\375\375"
"\352\376\375\353\376\376\355\376\376\356\376\376\357\377\377\357",
};
static const GstGLEffectsCurve xray_curve = {
256, 1, 3,
"\377\377\377\377\377\377\376\376\376\375\375\376\374\375\375\373\374\375"
"\372\374\374\371\374\374\370\373\373\366\373\372\366\372\372\365\372\371"
"\363\371\371\363\371\370\362\370\370\360\370\367\360\367\366\357\367\365"
"\356\366\365\355\366\364\353\365\363\353\365\363\352\364\362\351\363\362"
"\347\363\361\346\362\361\345\362\361\344\362\360\343\361\357\343\361\356"
"\342\360\356\341\360\356\340\357\355\336\356\354\336\356\354\335\355\353"
"\334\355\353\333\355\352\331\354\351\331\353\351\330\353\350\327\353\350"
"\325\352\347\325\351\347\324\350\346\323\350\345\322\347\344\321\347\344"
"\320\347\344\317\346\343\316\346\342\315\345\341\314\344\341\313\344\340"
"\312\344\340\311\343\337\310\342\337\307\342\335\306\341\335\305\341\335"
"\303\340\334\303\337\333\302\337\333\301\337\332\300\336\331\276\335\331"
"\276\334\330\274\334\330\274\334\327\273\333\327\272\333\326\271\332\325"
"\270\332\325\267\331\324\266\330\323\265\330\323\264\327\322\263\327\321"
"\262\326\320\261\325\320\257\325\317\257\324\317\256\324\316\254\323\315"
"\254\322\315\253\322\314\252\321\313\251\321\313\250\320\312\246\317\311"
"\245\317\311\245\316\310\244\316\307\243\315\307\242\314\306\241\314\305"
"\240\312\305\237\312\304\236\312\303\235\311\303\234\311\302\233\307\301"
"\232\307\300\231\307\300\230\306\277\227\305\276\226\305\276\225\304\275"
"\224\303\274\223\303\273\222\302\273\221\301\272\220\301\271\217\300\270"
"\216\277\270\215\277\267\214\276\266\213\275\265\212\275\265\211\274\264"
"\210\273\263\207\273\262\206\272\262\205\271\261\204\270\260\203\270\257"
"\202\267\257\201\266\256\200\266\255\177\265\254~\264\253}\263\253|\263\252"
"{\262\251z\261\250y\260\247x\260\247w\257\246v\256\245u\255\244t\255\243"
"s\254\243r\253\242q\252\241p\252\240o\251\237n\250\236m\247\235l\246\235"
"l\246\235j\245\233i\244\232h\243\231g\242\230f\242\227e\241\226d\240\226"
"c\237\225b\236\224a\235\223`\234\222_\234\221_\233\220]\232\217\\\231\216"
"\\\230\215Z\227\214Y\226\214X\226\213W\225\212V\224\211U\223\210T\222\207"
"S\221\206R\221\205Q\217\204P\216\203O\215\202N\215\201M\214\200M\213\177"
"K\212~J\211}I\211|H\210|G\206zG\205zE\204xD\203vC\203vB\201tA\200s@\200q"
"@~p>}o>|o<{l<yk;xi9wh8wg8te6sd5qd4pa3n_2m]1k\\0j\\0hY.fW-dU,cT+aR*_P)_O("
"]M'YK'XI%VI$TF$RD\"OB!M@\40K?\37I=\37G=\35E9\34C9\34A5\33>5\31<2\31<0\27"
":.\27""5,\26""3*\24""1*\23.&\22.&\22*\"\21'\40\17%\36\16\"\34\15\"\32\14"
"\36\32\13\33\26\13\31\24\11\26\22\11\24\20\7\24\16\6\21\16\5\14\14\4\12\10"
"\3\7\6\3\5\4\1\2\2",
};
#endif

View file

@ -0,0 +1,72 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstgleffects.h"
static void
gst_gl_effects_sin_callback (gint width, gint height, guint texture,
gpointer data)
{
GstGLShader *shader;
GstGLEffects *effects = GST_GL_EFFECTS (data);
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLContext *context = filter->context;
GstGLFuncs *gl = context->gl_vtable;
shader = g_hash_table_lookup (effects->shaderstable, "sin0");
if (!shader) {
shader = gst_gl_shader_new (context);
g_hash_table_insert (effects->shaderstable, "sin0", shader);
}
if (!gst_gl_shader_compile_and_check (shader,
sin_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
gst_gl_context_set_error (context, "Failed to initialize sin shader");
GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
("%s", gst_gl_context_get_error ()), (NULL));
return;
}
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gst_gl_shader_use (shader);
gl->ActiveTexture (GL_TEXTURE0);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gst_gl_shader_set_uniform_1i (shader, "tex", 0);
gst_gl_filter_draw_texture (filter, texture, width, height);
}
void
gst_gl_effects_sin (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
effects->outtexture, gst_gl_effects_sin_callback, effects);
}

View file

@ -0,0 +1,75 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstgleffects.h"
static void
gst_gl_effects_square_callback (gint width, gint height, guint texture,
gpointer data)
{
GstGLShader *shader;
GstGLEffects *effects = GST_GL_EFFECTS (data);
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLContext *context = filter->context;
GstGLFuncs *gl = context->gl_vtable;
shader = g_hash_table_lookup (effects->shaderstable, "square0");
if (!shader) {
shader = gst_gl_shader_new (context);
g_hash_table_insert (effects->shaderstable, "square0", shader);
}
if (!gst_gl_shader_compile_and_check (shader,
square_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
gst_gl_context_set_error (context, "Failed to initialize square shader");
GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
("%s", gst_gl_context_get_error ()), (NULL));
return;
}
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gst_gl_shader_use (shader);
gl->ActiveTexture (GL_TEXTURE0);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gst_gl_shader_set_uniform_1i (shader, "tex", 0);
gst_gl_shader_set_uniform_1f (shader, "width", (gfloat) width / 2.0f);
gst_gl_shader_set_uniform_1f (shader, "height", (gfloat) height / 2.0f);
gst_gl_filter_draw_texture (filter, texture, width, height);
}
void
gst_gl_effects_square (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
effects->outtexture, gst_gl_effects_square_callback, effects);
}

View file

@ -0,0 +1,119 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstgleffects.h"
#define USING_OPENGL(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_OPENGL)
#define USING_OPENGL3(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_OPENGL3)
#define USING_GLES(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES)
#define USING_GLES2(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES2)
#define USING_GLES3(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES3)
static void
gst_gl_effects_squeeze_callback (gint width, gint height, guint texture,
gpointer data)
{
GstGLShader *shader;
GstGLFilter *filter = GST_GL_FILTER (data);
GstGLEffects *effects = GST_GL_EFFECTS (data);
GstGLContext *context = filter->context;
GstGLFuncs *gl = context->gl_vtable;
shader = g_hash_table_lookup (effects->shaderstable, "squeeze0");
if (!shader) {
shader = gst_gl_shader_new (context);
g_hash_table_insert (effects->shaderstable, "squeeze0", shader);
#if GST_GL_HAVE_GLES2
if (USING_GLES2 (context)) {
if (shader) {
GError *error = NULL;
gst_gl_shader_set_vertex_source (shader, vertex_shader_source);
gst_gl_shader_set_fragment_source (shader,
squeeze_fragment_source_gles2);
gst_gl_shader_compile (shader, &error);
if (error) {
gst_gl_context_set_error (context,
"Failed to initialize squeeze shader, %s", error->message);
g_error_free (error);
error = NULL;
gst_gl_shader_use (NULL);
GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
("%s", gst_gl_context_get_error ()), (NULL));
} else {
filter->draw_attr_position_loc =
gst_gl_shader_get_attribute_location (shader, "a_position");
filter->draw_attr_texture_loc =
gst_gl_shader_get_attribute_location (shader, "a_texCoord");
}
}
}
#endif
#if GST_GL_HAVE_OPENGL
if (USING_OPENGL (context)) {
if (!gst_gl_shader_compile_and_check (shader,
squeeze_fragment_source_opengl, GST_GL_SHADER_FRAGMENT_SOURCE)) {
gst_gl_context_set_error (context,
"Failed to initialize squeeze shader");
GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
("%s", gst_gl_context_get_error ()), (NULL));
return;
}
}
#endif
}
#if GST_GL_HAVE_OPENGL
if (USING_OPENGL (context)) {
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
}
#endif
gst_gl_shader_use (shader);
gl->ActiveTexture (GL_TEXTURE0);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gst_gl_shader_set_uniform_1i (shader, "tex", 0);
#if GST_GL_HAVE_OPENGL
if (USING_OPENGL (filter->context)) {
gst_gl_shader_set_uniform_1f (shader, "width", (gfloat) width / 2.0f);
gst_gl_shader_set_uniform_1f (shader, "height", (gfloat) height / 2.0f);
}
#endif
gst_gl_filter_draw_texture (filter, texture, width, height);
}
void
gst_gl_effects_squeeze (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
effects->outtexture, gst_gl_effects_squeeze_callback, effects);
}

View file

@ -0,0 +1,481 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gl/gstglconfig.h>
#include "../gstgleffects.h"
#include "gstgleffectssources.h"
#include <math.h>
/* A common file for sources is needed since shader sources can be
* generic and reused by several effects */
/* FIXME */
/* Move sooner or later into single .frag .vert files and either bake
* them into a c file at compile time or load them at run time */
/* fill a normalized and zero centered gaussian vector for separable
* gaussian convolution */
void
fill_gaussian_kernel (float *kernel, int size, float sigma)
{
int i;
float sum;
int l;
/* need an odd sized vector to center it at zero */
g_return_if_fail ((size % 2) != 0);
sum = 0.0;
l = (size - 1) / 2;
for (i = 0; i < size; i++) {
kernel[i] = expf (-0.5 * pow ((i - l) / sigma, 2.0));
sum += kernel[i];
}
for (i = 0; i < size; i++) {
kernel[i] /= sum;
}
}
/* *INDENT-OFF* */
/* Vertex shader */
const gchar *vertex_shader_source =
"attribute vec4 a_position;"
"attribute vec2 a_texCoord;"
"varying vec2 v_texCoord;"
"void main()"
"{"
" gl_Position = a_position;"
" v_texCoord = a_texCoord;"
"}";
/* Identity effect */
const gchar *identity_fragment_source =
"precision mediump float;"
"varying vec2 v_texCoord;"
"uniform sampler2D tex;"
"void main()"
"{"
" gl_FragColor = texture2D(tex, v_texCoord);"
"}";
/* Mirror effect */
#if GST_GL_HAVE_OPENGL
const gchar *mirror_fragment_source_opengl =
"uniform sampler2D tex;"
"void main () {"
" vec2 texturecoord = gl_TexCoord[0].xy;"
" vec2 normcoord;"
" normcoord = texturecoord - 0.5;"
" normcoord.x *= sign (normcoord.x);"
" texturecoord = normcoord + 0.5;"
" vec4 color = texture2D (tex, texturecoord);"
" gl_FragColor = color * gl_Color;"
"}";
#endif
#if GST_GL_HAVE_GLES2
const gchar *mirror_fragment_source_gles2 =
"precision mediump float;"
"varying vec2 v_texCoord;"
"uniform sampler2D tex;"
"void main () {"
" vec2 texturecoord = v_texCoord.xy;"
" float normcoord = texturecoord.x - 0.5;"
" normcoord *= sign (normcoord);"
" texturecoord.x = normcoord + 0.5;"
" gl_FragColor = texture2D (tex, texturecoord);"
"}";
#endif
/* Squeeze effect */
#if GST_GL_HAVE_OPENGL
const gchar *squeeze_fragment_source_opengl =
"uniform sampler2D tex;"
"void main () {"
" vec2 texturecoord = gl_TexCoord[0].xy;"
" vec2 normcoord = texturecoord - 0.5;"
" float r = length (normcoord);"
" r = pow(r, 0.40)*1.3;"
" normcoord = normcoord / r;"
" texturecoord = (normcoord + 0.5);"
" gl_FragColor = texture2D (tex, texturecoord);"
"}";
#endif
#if GST_GL_HAVE_GLES2
const gchar *squeeze_fragment_source_gles2 =
"precision mediump float;"
"varying vec2 v_texCoord;"
"uniform sampler2D tex;"
"void main () {"
" vec2 texturecoord = v_texCoord.xy;"
" vec2 normcoord = texturecoord - 0.5;"
" float r = length (normcoord);"
" r = pow(r, 0.40)*1.3;"
" normcoord = normcoord / r;"
" texturecoord = (normcoord + 0.5);"
" gl_FragColor = texture2D (tex, texturecoord);"
"}";
#endif
/* Stretch Effect */
const gchar *stretch_fragment_source =
"uniform sampler2D tex;"
"void main () {"
" vec2 texturecoord = gl_TexCoord[0].xy;"
" vec2 normcoord;"
" normcoord = texturecoord - 0.5;"
" float r = length (normcoord);"
" normcoord *= 2.0 - smoothstep(0.0, 0.35, r);"
" texturecoord = normcoord + 0.5;"
" vec4 color = texture2D (tex, texturecoord);"
" gl_FragColor = color * gl_Color;"
"}";
/* Light Tunnel effect */
const gchar *tunnel_fragment_source =
"uniform sampler2D tex;"
"void main () {"
" vec2 texturecoord = gl_TexCoord[0].xy;"
" vec2 normcoord;"
/* little trick with normalized coords to obtain a circle with
* rect textures */
" normcoord = (texturecoord - 0.5);"
" float r = length(normcoord);"
" normcoord *= clamp (r, 0.0, 0.275) / r;"
" texturecoord = normcoord + 0.5;"
" vec4 color = texture2D (tex, texturecoord); "
" gl_FragColor = color;"
"}";
/* FishEye effect */
const gchar *fisheye_fragment_source =
"uniform sampler2D tex;"
"void main () {"
" vec2 texturecoord = gl_TexCoord[0].xy;"
" vec2 normcoord;"
" normcoord = texturecoord - 0.5;"
" float r = length (normcoord);"
" normcoord *= r * sqrt(2);"
" texturecoord = normcoord + 0.5;"
" vec4 color = texture2D (tex, texturecoord);"
" gl_FragColor = color;"
"}";
/* Twirl effect */
const gchar *twirl_fragment_source =
"uniform sampler2D tex;"
"void main () {"
" vec2 texturecoord = gl_TexCoord[0].xy;"
" vec2 normcoord;"
" normcoord = texturecoord - 0.5;"
" float r = length (normcoord);"
/* calculate rotation angle: maximum (about pi/2) at the origin and
* gradually decrease it up to 0.6 of each quadrant */
" float phi = (1.0 - smoothstep (0.0, 0.3, r)) * 1.6;"
/* precalculate sin phi and cos phi, save some alu */
" float s = sin(phi);"
" float c = cos(phi);"
/* rotate */
" normcoord *= mat2(c, s, -s, c);"
" texturecoord = normcoord + 0.5;"
" vec4 color = texture2D (tex, texturecoord); "
" gl_FragColor = color;"
"}";
/* Bulge effect */
const gchar *bulge_fragment_source =
"uniform sampler2D tex;"
"void main () {"
" vec2 texturecoord = gl_TexCoord[0].xy;"
" vec2 normcoord;"
" normcoord = texturecoord - 0.5;"
" float r = length (normcoord);"
" normcoord *= smoothstep (-0.05, 0.25, r);"
" texturecoord = normcoord + 0.5;"
" vec4 color = texture2D (tex, texturecoord);"
" gl_FragColor = color;"
"}";
/* Square Effect */
const gchar *square_fragment_source =
"uniform sampler2D tex;"
"void main () {"
" vec2 texturecoord = gl_TexCoord[0].xy;"
" vec2 normcoord;"
" normcoord = texturecoord - 0.5;"
" float r = length (normcoord);"
" normcoord *= 1.0 + smoothstep(0.125, 0.25, abs(normcoord));"
" normcoord /= 2.0; /* zoom amount */"
" texturecoord = normcoord + 0.5;"
" vec4 color = texture2D (tex, texturecoord);"
" gl_FragColor = color * gl_Color;"
"}";
const gchar *luma_threshold_fragment_source =
"uniform sampler2D tex;"
"void main () {"
" vec2 texturecoord = gl_TexCoord[0].st;"
" vec4 color = texture2D(tex, texturecoord);"
" float luma = dot(color.rgb, vec3(0.2125, 0.7154, 0.0721));" /* BT.709 (from orange book) */
" gl_FragColor = vec4 (vec3 (smoothstep (0.30, 0.50, luma)), color.a);"
"}";
const gchar *sep_sobel_length_fragment_source =
"uniform sampler2D tex;"
"uniform bool invert;"
"void main () {"
" vec4 g = texture2D (tex, gl_TexCoord[0].st);"
/* restore black background with grey edges */
" g -= vec4(0.5, 0.5, 0.0, 0.0);"
" float len = length (g);"
/* little trick to avoid IF operator */
/* TODO: test if a standalone inverting pass is worth */
" gl_FragColor = abs(vec4(vec3(float(invert) - len), 1.0));"
"}";
const gchar *desaturate_fragment_source =
"uniform sampler2D tex;"
"void main () {"
" vec4 color = texture2D (tex, gl_TexCoord[0].st);"
" float luma = dot(color.rgb, vec3(0.2125, 0.7154, 0.0721));"
" gl_FragColor = vec4(vec3(luma), color.a);"
"}";
const gchar *sep_sobel_hconv3_fragment_source =
"uniform sampler2D tex;"
"uniform float width;"
"void main () {"
" float w = 1.0 / width;"
" vec2 texturecoord[3];"
" texturecoord[1] = gl_TexCoord[0].st;"
" texturecoord[0] = texturecoord[1] - vec2(w, 0.0);"
" texturecoord[2] = texturecoord[1] + vec2(w, 0.0);"
" float grad_kern[3];"
" grad_kern[0] = 1.0;"
" grad_kern[1] = 0.0;"
" grad_kern[2] = -1.0;"
" float blur_kern[3];"
" blur_kern[0] = 0.25;"
" blur_kern[1] = 0.5;"
" blur_kern[2] = 0.25;"
" int i;"
" vec4 sum = vec4 (0.0);"
" for (i = 0; i < 3; i++) { "
" vec4 neighbor = texture2D(tex, texturecoord[i]); "
" sum.r = neighbor.r * blur_kern[i] + sum.r;"
" sum.g = neighbor.g * grad_kern[i] + sum.g;"
" }"
" gl_FragColor = sum + vec4(0.0, 0.5, 0.0, 0.0);"
"}";
const gchar *sep_sobel_vconv3_fragment_source =
"uniform sampler2D tex;"
"uniform float height;"
"void main () {"
" float h = 1.0 / height;"
" vec2 texturecoord[3];"
" texturecoord[1] = gl_TexCoord[0].st;"
" texturecoord[0] = texturecoord[1] - vec2(0.0, h);"
" texturecoord[2] = texturecoord[1] + vec2(0.0, h);"
" float grad_kern[3];"
" grad_kern[0] = 1.0;"
" grad_kern[1] = 0.0;"
" grad_kern[2] = -1.0;"
" float blur_kern[3];"
" blur_kern[0] = 0.25;"
" blur_kern[1] = 0.5;"
" blur_kern[2] = 0.25;"
" int i;"
" vec4 sum = vec4 (0.0);"
" for (i = 0; i < 3; i++) { "
" vec4 neighbor = texture2D(tex, texturecoord[i]); "
" sum.r = neighbor.r * grad_kern[i] + sum.r;"
" sum.g = neighbor.g * blur_kern[i] + sum.g;"
" }"
" gl_FragColor = sum + vec4(0.5, 0.0, 0.0, 0.0);"
"}";
/* horizontal convolution 7x7 */
const gchar *hconv7_fragment_source =
"uniform sampler2D tex;"
"uniform float kernel[7];"
"uniform float width;"
"void main () {"
" float w = 1.0 / width;"
" vec2 texturecoord[7];"
" texturecoord[3] = gl_TexCoord[0].st;"
" texturecoord[2] = texturecoord[3] - vec2(w, 0.0);"
" texturecoord[1] = texturecoord[2] - vec2(w, 0.0);"
" texturecoord[0] = texturecoord[1] - vec2(w, 0.0);"
" texturecoord[4] = texturecoord[3] + vec2(w, 0.0);"
" texturecoord[5] = texturecoord[4] + vec2(w, 0.0);"
" texturecoord[6] = texturecoord[5] + vec2(w, 0.0);"
" int i;"
" vec4 sum = vec4 (0.0);"
" for (i = 0; i < 7; i++) { "
" vec4 neighbor = texture2D(tex, texturecoord[i]); "
" sum += neighbor * kernel[i];"
" }"
" gl_FragColor = sum;"
"}";
/* vertical convolution 7x7 */
const gchar *vconv7_fragment_source =
"uniform sampler2D tex;"
"uniform float kernel[7];"
"uniform float height;"
"void main () {"
" float h = 1.0 / height;"
" vec2 texturecoord[7];"
" texturecoord[3] = gl_TexCoord[0].st;"
" texturecoord[2] = texturecoord[3] - vec2(0.0, h);"
" texturecoord[1] = texturecoord[2] - vec2(0.0, h);"
" texturecoord[0] = texturecoord[1] - vec2(0.0, h);"
" texturecoord[4] = texturecoord[3] + vec2(0.0, h);"
" texturecoord[5] = texturecoord[4] + vec2(0.0, h);"
" texturecoord[6] = texturecoord[5] + vec2(0.0, h);"
" int i;"
" vec4 sum = vec4 (0.0);"
" for (i = 0; i < 7; i++) { "
" vec4 neighbor = texture2D(tex, texturecoord[i]);"
" sum += neighbor * kernel[i];"
" }"
" gl_FragColor = sum;"
"}";
/* TODO: support several blend modes */
const gchar *sum_fragment_source =
"uniform sampler2D base;"
"uniform sampler2D blend;"
"uniform float alpha;"
"uniform float beta;"
"void main () {"
" vec4 basecolor = texture2D (base, gl_TexCoord[0].st);"
" vec4 blendcolor = texture2D (blend, gl_TexCoord[0].st);"
" gl_FragColor = alpha * basecolor + beta * blendcolor;"
"}";
const gchar *multiply_fragment_source =
"uniform sampler2D base;"
"uniform sampler2D blend;"
"uniform float alpha;"
"void main () {"
" vec4 basecolor = texture2D (base, gl_TexCoord[0].st);"
" vec4 blendcolor = texture2D (blend, gl_TexCoord[0].st);"
" gl_FragColor = (1.0 - alpha) * basecolor + alpha * basecolor * blendcolor;"
"}";
/* lut operations, map luma to tex1d, see orange book (chapter 19) */
const gchar *luma_to_curve_fragment_source =
"uniform sampler2D tex;"
"uniform sampler1D curve;"
"void main () {"
" vec2 texturecoord = gl_TexCoord[0].st;"
" vec4 color = texture2D (tex, texturecoord);"
" float luma = dot(color.rgb, vec3(0.2125, 0.7154, 0.0721));"
" color = texture1D(curve, luma);"
" gl_FragColor = color;"
"}";
/* lut operations, map rgb to tex1d, see orange book (chapter 19) */
const gchar *rgb_to_curve_fragment_source =
"uniform sampler2D tex;"
"uniform sampler1D curve;"
"void main () {"
" vec4 color = texture2D (tex, gl_TexCoord[0].st);"
" vec4 outcolor;"
" outcolor.r = texture1D(curve, color.r).r;"
" outcolor.g = texture1D(curve, color.g).g;"
" outcolor.b = texture1D(curve, color.b).b;"
" outcolor.a = color.a;"
" gl_FragColor = outcolor;"
"}";
const gchar *sin_fragment_source =
"uniform sampler2D tex;"
"void main () {"
" vec4 color = texture2D (tex, vec2(gl_TexCoord[0].st));"
" float luma = dot(color.rgb, vec3(0.2125, 0.7154, 0.0721));"
/* calculate hue with the Preucil formula */
" float cosh = color.r - 0.5*(color.g + color.b);"
/* sqrt(3)/2 = 0.866 */
" float sinh = 0.866*(color.g - color.b);"
/* hue = atan2 h */
" float sch = (1.0-sinh)*cosh;"
/* ok this is a little trick I came up because I didn't find any
* detailed proof of the Preucil formula. The issue is that tan(h) is
* pi-periodic so the smoothstep thing gives both reds (h = 0) and
* cyans (h = 180). I don't want to use atan since it requires
* branching and doesn't work on i915. So take only the right half of
* the circle where cosine is positive */
/* take a slightly purple color trying to get rid of human skin reds */
/* tanh = +-1.0 for h = +-45, where yellow=60, magenta=-60 */
" float a = smoothstep (0.3, 1.0, sch);"
" float b = smoothstep (-0.4, -0.1, sinh);"
" float mix = a * b;"
" gl_FragColor = color * mix + luma * (1.0 - mix);"
"}";
const gchar *interpolate_fragment_source =
"uniform sampler2D base;"
"uniform sampler2D blend;"
"void main () {"
"vec4 basecolor = texture2D (base, gl_TexCoord[0].st);"
"vec4 blendcolor = texture2D (blend, gl_TexCoord[0].st);"
"vec4 white = vec4(1.0);"
"gl_FragColor = blendcolor + (1.0 - blendcolor.a) * basecolor;"
"}";
const gchar *texture_interp_fragment_source =
"uniform sampler2D base;"
"uniform sampler2D blend;"
"uniform sampler2D alpha;"
"void main () {"
" vec4 basecolor = texture2D (base, gl_TexCoord[0].st);"
" vec4 blendcolor = texture2D (blend, gl_TexCoord[0].st);"
" vec4 alphacolor = texture2D (alpha, gl_TexCoord[0].st);"
" gl_FragColor = (alphacolor * blendcolor) + (1.0 - alphacolor) * basecolor;"
"}";
const gchar *difference_fragment_source =
"uniform sampler2D saved;"
"uniform sampler2D current;"
"void main () {"
"vec4 savedcolor = texture2D (saved, gl_TexCoord[0].st);"
"vec4 currentcolor = texture2D (current, gl_TexCoord[0].st);"
"gl_FragColor = vec4 (step (0.12, length (savedcolor - currentcolor)));"
"}";
/* *INDENT-ON* */

View file

@ -0,0 +1,58 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_GL_EFFECTS_SOURCES_H__
#define __GST_GL_EFFECTS_SOURCES_H__
extern const gchar *vertex_shader_source;
extern const gchar *identity_fragment_source;
#if GST_GL_HAVE_OPENGL
extern const gchar *mirror_fragment_source_opengl;
extern const gchar *squeeze_fragment_source_opengl;
#endif
#if GST_GL_HAVE_GLES2
extern const gchar *mirror_fragment_source_gles2;
extern const gchar *squeeze_fragment_source_gles2;
#endif
extern const gchar *stretch_fragment_source;
extern const gchar *tunnel_fragment_source;
extern const gchar *fisheye_fragment_source;
extern const gchar *twirl_fragment_source;
extern const gchar *bulge_fragment_source;
extern const gchar *square_fragment_source;
extern const gchar *luma_threshold_fragment_source;
extern const gchar *sep_sobel_length_fragment_source;
extern const gchar *desaturate_fragment_source;
extern const gchar *sep_sobel_hconv3_fragment_source;
extern const gchar *sep_sobel_vconv3_fragment_source;
extern const gchar *hconv7_fragment_source;
extern const gchar *vconv7_fragment_source;
extern const gchar *sum_fragment_source;
extern const gchar *luma_to_curve_fragment_source;
extern const gchar *rgb_to_curve_fragment_source;
extern const gchar *sin_fragment_source;
extern const gchar *interpolate_fragment_source;
extern const gchar *texture_interp_fragment_source;
extern const gchar *difference_fragment_source;
extern const gchar *multiply_fragment_source;
void fill_gaussian_kernel (float *kernel, int size, float sigma);
#endif /* __GST_GL_EFFECTS_SOURCES_H__ */

View file

@ -0,0 +1,75 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstgleffects.h"
static void
gst_gl_effects_stretch_callback (gint width, gint height, guint texture,
gpointer data)
{
GstGLShader *shader;
GstGLEffects *effects = GST_GL_EFFECTS (data);
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLContext *context = filter->context;
GstGLFuncs *gl = context->gl_vtable;
shader = g_hash_table_lookup (effects->shaderstable, "stretch0");
if (!shader) {
shader = gst_gl_shader_new (context);
g_hash_table_insert (effects->shaderstable, "stretch0", shader);
}
if (!gst_gl_shader_compile_and_check (shader,
stretch_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
gst_gl_context_set_error (context, "Failed to initialize stretch shader");
GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
("%s", gst_gl_context_get_error ()), (NULL));
return;
}
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gst_gl_shader_use (shader);
gl->ActiveTexture (GL_TEXTURE0);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gst_gl_shader_set_uniform_1i (shader, "tex", 0);
gst_gl_shader_set_uniform_1f (shader, "width", (gfloat) width / 2.0f);
gst_gl_shader_set_uniform_1f (shader, "height", (gfloat) height / 2.0f);
gst_gl_filter_draw_texture (filter, texture, width, height);
}
void
gst_gl_effects_stretch (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
effects->outtexture, gst_gl_effects_stretch_callback, effects);
}

View file

@ -0,0 +1,75 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstgleffects.h"
static void
gst_gl_effects_tunnel_callback (gint width, gint height, guint texture,
gpointer data)
{
GstGLShader *shader;
GstGLEffects *effects = GST_GL_EFFECTS (data);
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLContext *context = filter->context;
GstGLFuncs *gl = context->gl_vtable;
shader = g_hash_table_lookup (effects->shaderstable, "tunnel0");
if (!shader) {
shader = gst_gl_shader_new (context);
g_hash_table_insert (effects->shaderstable, "tunnel0", shader);
}
if (!gst_gl_shader_compile_and_check (shader,
tunnel_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
gst_gl_context_set_error (context, "Failed to initialize tunnel shader");
GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
("%s", gst_gl_context_get_error ()), (NULL));
return;
}
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gst_gl_shader_use (shader);
gl->ActiveTexture (GL_TEXTURE0);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gst_gl_shader_set_uniform_1i (shader, "tex", 0);
gst_gl_shader_set_uniform_1f (shader, "width", (gfloat) width / 2.0f);
gst_gl_shader_set_uniform_1f (shader, "height", (gfloat) height / 2.0f);
gst_gl_filter_draw_texture (filter, texture, width, height);
}
void
gst_gl_effects_tunnel (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
effects->outtexture, gst_gl_effects_tunnel_callback, effects);
}

View file

@ -0,0 +1,75 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstgleffects.h"
static void
gst_gl_effects_twirl_callback (gint width, gint height, guint texture,
gpointer data)
{
GstGLShader *shader;
GstGLEffects *effects = GST_GL_EFFECTS (data);
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLContext *context = filter->context;
GstGLFuncs *gl = context->gl_vtable;
shader = g_hash_table_lookup (effects->shaderstable, "twirl0");
if (!shader) {
shader = gst_gl_shader_new (GST_GL_FILTER (effects)->context);
g_hash_table_insert (effects->shaderstable, "twirl0", shader);
}
if (!gst_gl_shader_compile_and_check (shader,
twirl_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
gst_gl_context_set_error (context, "Failed to initialize twirl shader");
GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
("%s", gst_gl_context_get_error ()), (NULL));
return;
}
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gst_gl_shader_use (shader);
gl->ActiveTexture (GL_TEXTURE0);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gst_gl_shader_set_uniform_1i (shader, "tex", 0);
gst_gl_shader_set_uniform_1f (shader, "width", (gfloat) width / 2.0f);
gst_gl_shader_set_uniform_1f (shader, "height", (gfloat) height / 2.0f);
gst_gl_filter_draw_texture (filter, texture, width, height);
}
void
gst_gl_effects_twirl (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
effects->outtexture, gst_gl_effects_twirl_callback, effects);
}

View file

@ -0,0 +1,380 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gstgleffects.h"
#include "gstgleffectscurves.h"
#include "gstgleffectlumatocurve.h"
static gboolean kernel_ready = FALSE;
static float gauss_kernel[7];
static void
gst_gl_effects_xray_step_one (gint width, gint height, guint texture,
gpointer data)
{
GstGLEffects *effects = GST_GL_EFFECTS (data);
gst_gl_effects_luma_to_curve (effects, xray_curve, GST_GL_EFFECTS_CURVE_XRAY,
width, height, texture);
}
static void
gst_gl_effects_xray_step_two (gint width, gint height, guint texture,
gpointer data)
{
GstGLShader *shader;
GstGLEffects *effects = GST_GL_EFFECTS (data);
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLContext *context = filter->context;
GstGLFuncs *gl = context->gl_vtable;
shader = g_hash_table_lookup (effects->shaderstable, "xray1");
if (!shader) {
shader = gst_gl_shader_new (context);
g_hash_table_insert (effects->shaderstable, "xray1", shader);
}
if (!kernel_ready) {
fill_gaussian_kernel (gauss_kernel, 7, 1.5);
kernel_ready = TRUE;
}
if (!gst_gl_shader_compile_and_check (shader,
hconv7_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
gst_gl_context_set_error (context, "Failed to initialize hconv7 shader");
GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
("%s", gst_gl_context_get_error ()), (NULL));
return;
}
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gst_gl_shader_use (shader);
gl->ActiveTexture (GL_TEXTURE1);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gl->Disable (GL_TEXTURE_2D);
gst_gl_shader_set_uniform_1i (shader, "tex", 1);
gst_gl_shader_set_uniform_1fv (shader, "kernel", 9, gauss_kernel);
gst_gl_shader_set_uniform_1f (shader, "width", width);
gst_gl_filter_draw_texture (filter, texture, width, height);
}
static void
gst_gl_effects_xray_step_three (gint width, gint height, guint texture,
gpointer data)
{
GstGLShader *shader;
GstGLEffects *effects = GST_GL_EFFECTS (data);
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLContext *context = filter->context;
GstGLFuncs *gl = context->gl_vtable;
shader = g_hash_table_lookup (effects->shaderstable, "xray2");
if (!shader) {
shader = gst_gl_shader_new (context);
g_hash_table_insert (effects->shaderstable, "xray2", shader);
}
if (!gst_gl_shader_compile_and_check (shader,
vconv7_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
gst_gl_context_set_error (context, "Failed to initialize vconv7 shader");
GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
("%s", gst_gl_context_get_error ()), (NULL));
return;
}
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gst_gl_shader_use (shader);
gl->ActiveTexture (GL_TEXTURE1);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gl->Disable (GL_TEXTURE_2D);
gst_gl_shader_set_uniform_1i (shader, "tex", 1);
gst_gl_shader_set_uniform_1fv (shader, "kernel", 9, gauss_kernel);
gst_gl_shader_set_uniform_1f (shader, "height", height);
gst_gl_filter_draw_texture (filter, texture, width, height);
}
/* multipass separable sobel */
static void
gst_gl_effects_xray_desaturate (gint width, gint height, guint texture,
gpointer data)
{
GstGLShader *shader;
GstGLEffects *effects = GST_GL_EFFECTS (data);
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLContext *context = filter->context;
GstGLFuncs *gl = context->gl_vtable;
shader = g_hash_table_lookup (effects->shaderstable, "xray_desat");
if (!shader) {
shader = gst_gl_shader_new (context);
g_hash_table_insert (effects->shaderstable, "xray_desat", shader);
}
if (!gst_gl_shader_compile_and_check (shader,
desaturate_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
gst_gl_context_set_error (context,
"Failed to initialize desaturate shader");
GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
("%s", gst_gl_context_get_error ()), (NULL));
return;
}
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gst_gl_shader_use (shader);
gl->ActiveTexture (GL_TEXTURE1);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gl->Disable (GL_TEXTURE_2D);
gst_gl_shader_set_uniform_1i (shader, "tex", 1);
gst_gl_filter_draw_texture (filter, texture, width, height);
}
static void
gst_gl_effects_xray_sobel_hconv (gint width, gint height, guint texture,
gpointer data)
{
GstGLShader *shader;
GstGLEffects *effects = GST_GL_EFFECTS (data);
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLContext *context = filter->context;
GstGLFuncs *gl = context->gl_vtable;
shader = g_hash_table_lookup (effects->shaderstable, "xray_sob_hconv");
if (!shader) {
shader = gst_gl_shader_new (context);
g_hash_table_insert (effects->shaderstable, "xray_sob_hconv", shader);
}
if (!gst_gl_shader_compile_and_check (shader,
sep_sobel_hconv3_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
gst_gl_context_set_error (context,
"Failed to initialize sobel hvonc3 shader");
GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
("%s", gst_gl_context_get_error ()), (NULL));
return;
}
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gst_gl_shader_use (shader);
gl->ActiveTexture (GL_TEXTURE1);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gl->Disable (GL_TEXTURE_2D);
gst_gl_shader_set_uniform_1i (shader, "tex", 1);
gst_gl_shader_set_uniform_1f (shader, "width", width);
gst_gl_filter_draw_texture (filter, texture, width, height);
}
static void
gst_gl_effects_xray_sobel_vconv (gint width, gint height, guint texture,
gpointer data)
{
GstGLShader *shader;
GstGLEffects *effects = GST_GL_EFFECTS (data);
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLContext *context = filter->context;
GstGLFuncs *gl = context->gl_vtable;
shader = g_hash_table_lookup (effects->shaderstable, "xray_sob_vconv");
if (!shader) {
shader = gst_gl_shader_new (context);
g_hash_table_insert (effects->shaderstable, "xray_sob_vconv", shader);
}
if (!gst_gl_shader_compile_and_check (shader,
sep_sobel_vconv3_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
gst_gl_context_set_error (context,
"Failed to initialize sobel vconv3 shader");
GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
("%s", gst_gl_context_get_error ()), (NULL));
return;
}
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gst_gl_shader_use (shader);
gl->ActiveTexture (GL_TEXTURE1);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gl->Disable (GL_TEXTURE_2D);
gst_gl_shader_set_uniform_1i (shader, "tex", 1);
gst_gl_shader_set_uniform_1f (shader, "height", height);
gst_gl_filter_draw_texture (filter, texture, width, height);
}
static void
gst_gl_effects_xray_sobel_length (gint width, gint height, guint texture,
gpointer data)
{
GstGLShader *shader;
GstGLEffects *effects = GST_GL_EFFECTS (data);
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLContext *context = filter->context;
GstGLFuncs *gl = context->gl_vtable;
shader = g_hash_table_lookup (effects->shaderstable, "xray_sob_len");
if (!shader) {
shader = gst_gl_shader_new (context);
g_hash_table_insert (effects->shaderstable, "xray_sob_len", shader);
}
if (!gst_gl_shader_compile_and_check (shader,
sep_sobel_length_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
gst_gl_context_set_error (context,
"Failed to initialize seobel length shader");
GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
("%s", gst_gl_context_get_error ()), (NULL));
return;
}
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gst_gl_shader_use (shader);
gl->ActiveTexture (GL_TEXTURE1);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gl->Disable (GL_TEXTURE_2D);
gst_gl_shader_set_uniform_1i (shader, "tex", 1);
gst_gl_shader_set_uniform_1i (shader, "invert", TRUE);
gst_gl_filter_draw_texture (filter, texture, width, height);
}
/* end of sobel passes */
void
gst_gl_effects_xray_step_five (gint width, gint height, guint texture,
gpointer data)
{
GstGLShader *shader;
GstGLEffects *effects = GST_GL_EFFECTS (data);
GstGLFilter *filter = GST_GL_FILTER (effects);
GstGLContext *context = filter->context;
GstGLFuncs *gl = context->gl_vtable;
shader = g_hash_table_lookup (effects->shaderstable, "xray4");
if (!shader) {
shader = gst_gl_shader_new (context);
g_hash_table_insert (effects->shaderstable, "xray4", shader);
}
if (!gst_gl_shader_compile_and_check (shader,
multiply_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
gst_gl_context_set_error (context, "Failed to initialize multiply shader");
GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
("%s", gst_gl_context_get_error ()), (NULL));
return;
}
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gst_gl_shader_use (shader);
gl->ActiveTexture (GL_TEXTURE2);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, effects->midtexture[2]);
gl->Disable (GL_TEXTURE_2D);
gst_gl_shader_set_uniform_1i (shader, "base", 2);
gl->ActiveTexture (GL_TEXTURE1);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gl->Disable (GL_TEXTURE_2D);
gst_gl_shader_set_uniform_1f (shader, "alpha", (gfloat) 0.5f);
gst_gl_shader_set_uniform_1i (shader, "blend", 1);
gst_gl_filter_draw_texture (filter, texture, width, height);
}
void
gst_gl_effects_xray (GstGLEffects * effects)
{
GstGLFilter *filter = GST_GL_FILTER (effects);
/* map luma to xray curve */
gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
effects->midtexture[0], gst_gl_effects_xray_step_one, effects);
/* horizontal blur */
gst_gl_filter_render_to_target (filter, FALSE, effects->midtexture[0],
effects->midtexture[1], gst_gl_effects_xray_step_two, effects);
/* vertical blur */
gst_gl_filter_render_to_target (filter, FALSE, effects->midtexture[1],
effects->midtexture[2], gst_gl_effects_xray_step_three, effects);
/* detect edges with Sobel */
/* the old version used edges from the blurred texture, this uses
* the ones from original texture, still not sure what I like
* more. This one gives better edges obviously but behaves badly
* with noise */
/* desaturate */
gst_gl_filter_render_to_target (filter, TRUE, effects->intexture,
effects->midtexture[3], gst_gl_effects_xray_desaturate, effects);
/* horizonal convolution */
gst_gl_filter_render_to_target (filter, FALSE, effects->midtexture[3],
effects->midtexture[4], gst_gl_effects_xray_sobel_hconv, effects);
/* vertical convolution */
gst_gl_filter_render_to_target (filter, FALSE, effects->midtexture[4],
effects->midtexture[3], gst_gl_effects_xray_sobel_vconv, effects);
/* gradient length */
gst_gl_filter_render_to_target (filter, FALSE, effects->midtexture[3],
effects->midtexture[4], gst_gl_effects_xray_sobel_length, effects);
/* multiply edges with the blurred image */
gst_gl_filter_render_to_target (filter, FALSE, effects->midtexture[4],
effects->outtexture, gst_gl_effects_xray_step_five, effects);
}

507
ext/gl/gltestsrc.c Normal file
View file

@ -0,0 +1,507 @@
/* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/* non-GST-specific stuff */
#include "gltestsrc.h"
#include <string.h>
#include <stdlib.h>
#include <math.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
enum
{
COLOR_WHITE = 0,
COLOR_YELLOW,
COLOR_CYAN,
COLOR_GREEN,
COLOR_MAGENTA,
COLOR_RED,
COLOR_BLUE,
COLOR_BLACK,
COLOR_NEG_I,
COLOR_POS_Q,
COLOR_SUPER_BLACK,
COLOR_DARK_GREY
};
static const struct vts_color_struct vts_colors[] = {
/* 100% white */
{255, 128, 128, 255, 255, 255, 255},
/* yellow */
{226, 0, 155, 255, 255, 0, 255},
/* cyan */
{179, 170, 0, 0, 255, 255, 255},
/* green */
{150, 46, 21, 0, 255, 0, 255},
/* magenta */
{105, 212, 235, 255, 0, 255, 255},
/* red */
{76, 85, 255, 255, 0, 0, 255},
/* blue */
{29, 255, 107, 0, 0, 255, 255},
/* black */
{16, 128, 128, 0, 0, 0, 255},
/* -I */
{16, 198, 21, 0, 0, 128, 255},
/* +Q */
{16, 235, 198, 0, 128, 255, 255},
/* superblack */
{0, 128, 128, 0, 0, 0, 255},
/* 5% grey */
{32, 128, 128, 32, 32, 32, 255},
};
static void
gst_gl_test_src_unicolor (GstGLTestSrc * v, GstBuffer * buffer, int w,
int h, const struct vts_color_struct *color);
void
gst_gl_test_src_smpte (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
{
#if GST_GL_HAVE_OPENGL
int i;
if (gst_gl_context_get_gl_api (v->context) & GST_GL_API_OPENGL) {
glClearColor (0.0, 0.0, 0.0, 1.0);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDisable (GL_CULL_FACE);
glDisable (GL_TEXTURE_2D);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
for (i = 0; i < 7; i++) {
glColor4f (vts_colors[i].R * (1 / 255.0f), vts_colors[i].G * (1 / 255.0f),
vts_colors[i].B * (1 / 255.0f), 1.0f);
glBegin (GL_QUADS);
glVertex3f (-1.0f + i * (2.0f / 7.0f), -1.0f + 2.0 * (2.0f / 3.0f), 0);
glVertex3f (-1.0f + (i + 1.0f) * (2.0f / 7.0f),
-1.0f + 2.0f * (2.0f / 3.0f), 0);
glVertex3f (-1.0f + (i + 1.0f) * (2.0f / 7.0f), -1.0f, 0);
glVertex3f (-1.0f + i * (2.0f / 7.0f), -1.0f, 0);
glEnd ();
}
for (i = 0; i < 7; i++) {
int k;
if (i & 1) {
k = 7;
} else {
k = 6 - i;
}
glColor4f (vts_colors[k].R * (1 / 255.0f), vts_colors[k].G * (1 / 255.0f),
vts_colors[k].B * (1 / 255.0f), 1.0f);
glBegin (GL_QUADS);
glVertex3f (-1.0f + i * (2.0f / 7.0f), -1.0f + 2.0f * (3.0f / 4.0f), 0);
glVertex3f (-1.0f + (i + 1) * (2.0f / 7.0f), -1.0f + 2.0f * (3.0f / 4.0f),
0);
glVertex3f (-1.0f + (i + 1) * (2.0f / 7.0f), -1.0f + 2.0f * (2.0f / 3.0f),
0);
glVertex3f (-1.0f + i * (2.0f / 7.0f), -1.0f + 2.0f * (2.0f / 3.0f), 0);
glEnd ();
}
for (i = 0; i < 3; i++) {
int k;
if (i == 0) {
k = 8;
} else if (i == 1) {
k = 0;
} else {
k = 9;
}
glColor4f (vts_colors[k].R * (1 / 255.0f), vts_colors[k].G * (1 / 255.0f),
vts_colors[k].B * (1 / 255.0f), 1.0f);
glBegin (GL_QUADS);
glVertex3f (-1.0f + i * (2.0f / 6.0f), -1.0f + 2.0f * 1, 0);
glVertex3f (-1.0f + (i + 1) * (2.0f / 6.0f), -1.0f + 2.0f * 1, 0);
glVertex3f (-1.0f + (i + 1) * (2.0f / 6.0f), -1.0f + 2.0f * (3.0f / 4.0f),
0);
glVertex3f (-1.0f + i * (2.0f / 6.0f), -1.0f + 2.0f * (3.0f / 4.0f), 0);
glEnd ();
}
for (i = 0; i < 3; i++) {
int k;
if (i == 0) {
k = COLOR_SUPER_BLACK;
} else if (i == 1) {
k = COLOR_BLACK;
} else {
k = COLOR_DARK_GREY;
}
glColor4f (vts_colors[k].R * (1 / 255.0f), vts_colors[k].G * (1 / 255.0f),
vts_colors[k].B * (1 / 255.0f), 1.0f);
glBegin (GL_QUADS);
glVertex3f (-1.0f + 2.0f * (0.5f + i * (1.0f / 12.0f)), -1.0 + 2.0f * 1,
0);
glVertex3f (-1.0f + 2.0f * (0.5f + (i + 1) * (1.0f / 12.0f)),
-1.0f + 2.0f * 1, 0);
glVertex3f (-1.0f + 2.0f * (0.5f + (i + 1) * (1.0f / 12.0f)),
-1.0f + 2.0f * (3.0f / 4.0f), 0);
glVertex3f (-1.0f + 2.0f * (0.5f + i * (1.0f / 12.0f)),
-1.0f + 2.0f * (3.0f / 4.0f), 0);
glEnd ();
}
glColor4f (1.0, 1.0, 1.0, 1.0);
glBegin (GL_QUADS);
glVertex3f (-1.0 + 2.0 * (0.75), -1.0 + 2.0 * 1, 0);
glVertex3f (-1.0 + 2.0 * (1.0), -1.0 + 2.0 * 1, 0);
glVertex3f (-1.0 + 2.0 * (1.0), -1.0 + 2.0 * (3.0 / 4.0), 0);
glVertex3f (-1.0 + 2.0 * (0.75), -1.0 + 2.0 * (3.0 / 4.0), 0);
glEnd ();
}
#endif
}
void
gst_gl_test_src_snow (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
{
#if GST_GL_HAVE_OPENGL
if (gst_gl_context_get_gl_api (v->context) & GST_GL_API_OPENGL) {
glClearColor (0.0, 0.0, 0.0, 1.0);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
/* FIXME snow requires a fragment shader. Please write. */
glColor4f (0.5, 0.5, 0.5, 1.0);
glBegin (GL_QUADS);
glVertex3f (-1.0 + 2.0 * (0.0), -1.0 + 2.0 * 1, 0);
glVertex3f (-1.0 + 2.0 * (1.0), -1.0 + 2.0 * 1, 0);
glVertex3f (-1.0 + 2.0 * (1.0), -1.0 + 2.0 * (0.0), 0);
glVertex3f (-1.0 + 2.0 * (0.0), -1.0 + 2.0 * (0.0), 0);
glEnd ();
}
#endif
}
static void
gst_gl_test_src_unicolor (GstGLTestSrc * v, GstBuffer * buffer, int w,
int h, const struct vts_color_struct *color)
{
#if GST_GL_HAVE_OPENGL
if (gst_gl_context_get_gl_api (v->context) & GST_GL_API_OPENGL) {
glClearColor (color->R * (1 / 255.0f), color->G * (1 / 255.0f),
color->B * (1 / 255.0f), 1.0f);
glClear (GL_COLOR_BUFFER_BIT);
}
#endif
}
void
gst_gl_test_src_black (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
{
gst_gl_test_src_unicolor (v, buffer, w, h, vts_colors + COLOR_BLACK);
}
void
gst_gl_test_src_white (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
{
gst_gl_test_src_unicolor (v, buffer, w, h, vts_colors + COLOR_WHITE);
}
void
gst_gl_test_src_red (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
{
gst_gl_test_src_unicolor (v, buffer, w, h, vts_colors + COLOR_RED);
}
void
gst_gl_test_src_green (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
{
gst_gl_test_src_unicolor (v, buffer, w, h, vts_colors + COLOR_GREEN);
}
void
gst_gl_test_src_blue (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
{
gst_gl_test_src_unicolor (v, buffer, w, h, vts_colors + COLOR_BLUE);
}
void
gst_gl_test_src_checkers1 (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
{
#if 0
int x, y;
paintinfo pi = { NULL, };
paintinfo *p = &pi;
struct fourcc_list_struct *fourcc;
p->width = w;
p->height = h;
fourcc = v->fourcc;
if (fourcc == NULL)
return;
fourcc->paint_setup (p, dest);
p->paint_hline = fourcc->paint_hline;
for (y = 0; y < h; y++) {
p->color = vts_colors + COLOR_GREEN;
p->paint_hline (p, 0, y, w);
for (x = (y % 2); x < w; x += 2) {
p->color = vts_colors + COLOR_RED;
p->paint_hline (p, x, y, 1);
}
}
#endif
}
void
gst_gl_test_src_checkers2 (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
{
#if 0
int x, y;
paintinfo pi = { NULL, };
paintinfo *p = &pi;
struct fourcc_list_struct *fourcc;
p->width = w;
p->height = h;
fourcc = v->fourcc;
if (fourcc == NULL)
return;
fourcc->paint_setup (p, dest);
p->paint_hline = fourcc->paint_hline;
p->color = vts_colors + COLOR_GREEN;
for (y = 0; y < h; y++) {
p->paint_hline (p, 0, y, w);
}
for (y = 0; y < h; y += 2) {
for (x = ((y % 4) == 0) ? 0 : 2; x < w; x += 4) {
guint len = (x < (w - 1)) ? 2 : (w - x);
p->color = vts_colors + COLOR_RED;
p->paint_hline (p, x, y + 0, len);
if (G_LIKELY ((y + 1) < h)) {
p->paint_hline (p, x, y + 1, len);
}
}
}
#endif
}
void
gst_gl_test_src_checkers4 (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
{
#if 0
int x, y;
paintinfo pi = { NULL, };
paintinfo *p = &pi;
struct fourcc_list_struct *fourcc;
p->width = w;
p->height = h;
fourcc = v->fourcc;
if (fourcc == NULL)
return;
fourcc->paint_setup (p, dest);
p->paint_hline = fourcc->paint_hline;
p->color = vts_colors + COLOR_GREEN;
for (y = 0; y < h; y++) {
p->paint_hline (p, 0, y, w);
}
for (y = 0; y < h; y += 4) {
for (x = ((y % 8) == 0) ? 0 : 4; x < w; x += 8) {
guint len = (x < (w - 3)) ? 4 : (w - x);
p->color = vts_colors + COLOR_RED;
p->paint_hline (p, x, y + 0, len);
if (G_LIKELY ((y + 1) < h)) {
p->paint_hline (p, x, y + 1, len);
if (G_LIKELY ((y + 2) < h)) {
p->paint_hline (p, x, y + 2, len);
if (G_LIKELY ((y + 3) < h)) {
p->paint_hline (p, x, y + 3, len);
}
}
}
}
}
#endif
}
void
gst_gl_test_src_checkers8 (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
{
#if 0
int x, y;
paintinfo pi = { NULL, };
paintinfo *p = &pi;
struct fourcc_list_struct *fourcc;
p->width = w;
p->height = h;
fourcc = v->fourcc;
if (fourcc == NULL)
return;
fourcc->paint_setup (p, dest);
p->paint_hline = fourcc->paint_hline;
p->color = vts_colors + COLOR_GREEN;
for (y = 0; y < h; y++) {
p->paint_hline (p, 0, y, w);
}
for (y = 0; y < h; y += 8) {
for (x = ((GST_ROUND_UP_8 (y) % 16) == 0) ? 0 : 8; x < w; x += 16) {
guint len = (x < (w - 7)) ? 8 : (w - x);
p->color = vts_colors + COLOR_RED;
p->paint_hline (p, x, y + 0, len);
if (G_LIKELY ((y + 1) < h)) {
p->paint_hline (p, x, y + 1, len);
if (G_LIKELY ((y + 2) < h)) {
p->paint_hline (p, x, y + 2, len);
if (G_LIKELY ((y + 3) < h)) {
p->paint_hline (p, x, y + 3, len);
if (G_LIKELY ((y + 4) < h)) {
p->paint_hline (p, x, y + 4, len);
if (G_LIKELY ((y + 5) < h)) {
p->paint_hline (p, x, y + 5, len);
if (G_LIKELY ((y + 6) < h)) {
p->paint_hline (p, x, y + 6, len);
if (G_LIKELY ((y + 7) < h)) {
p->paint_hline (p, x, y + 7, len);
}
}
}
}
}
}
}
}
}
#endif
}
void
gst_gl_test_src_circular (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
{
#if 0
int i;
int j;
paintinfo pi = { NULL, };
paintinfo *p = &pi;
struct fourcc_list_struct *fourcc;
struct vts_color_struct color;
static uint8_t sine_array[256];
static int sine_array_inited = FALSE;
double freq[8];
#ifdef SCALE_AMPLITUDE
double ampl[8];
#endif
int d;
if (!sine_array_inited) {
for (i = 0; i < 256; i++) {
sine_array[i] =
floor (255 * (0.5 + 0.5 * sin (i * 2 * M_PI / 256)) + 0.5);
}
sine_array_inited = TRUE;
}
p->width = w;
p->height = h;
fourcc = v->fourcc;
if (fourcc == NULL)
return;
fourcc->paint_setup (p, dest);
p->paint_hline = fourcc->paint_hline;
color = vts_colors[COLOR_BLACK];
p->color = &color;
for (i = 1; i < 8; i++) {
freq[i] = 200 * pow (2.0, -(i - 1) / 4.0);
#ifdef SCALE_AMPLITUDE
{
double x;
x = 2 * M_PI * freq[i] / w;
ampl[i] = sin (x) / x;
}
#endif
}
for (i = 0; i < w; i++) {
for (j = 0; j < h; j++) {
double dist;
int seg;
dist =
sqrt ((2 * i - w) * (2 * i - w) + (2 * j - h) * (2 * j -
h)) / (2 * w);
seg = floor (dist * 16);
if (seg == 0 || seg >= 8) {
color.Y = 255;
} else {
#ifdef SCALE_AMPLITUDE
double a;
#endif
d = floor (256 * dist * freq[seg] + 0.5);
#ifdef SCALE_AMPLITUDE
a = ampl[seg];
if (a < 0)
a = 0;
color.Y = 128 + a * (sine_array[d & 0xff] - 128);
#else
color.Y = sine_array[d & 0xff];
#endif
}
color.R = color.Y;
color.G = color.Y;
color.B = color.Y;
p->paint_hline (p, i, j, 1);
}
}
#endif
}

58
ext/gl/gltestsrc.h Normal file
View file

@ -0,0 +1,58 @@
/* GStreamer
* Copyright (C) <2003> David A. Schleef <ds@schleef.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GL_TEST_SRC_H__
#define __GL_TEST_SRC_H__
#include <glib.h>
#include "gstgltestsrc.h"
struct vts_color_struct {
guint8 Y, U, V;
guint8 R, G, B;
guint8 A;
};
void gst_gl_test_src_smpte (GstGLTestSrc * v,
GstBuffer *buffer, int w, int h);
void gst_gl_test_src_snow (GstGLTestSrc * v,
GstBuffer *buffer, int w, int h);
void gst_gl_test_src_black (GstGLTestSrc * v,
GstBuffer *buffer, int w, int h);
void gst_gl_test_src_white (GstGLTestSrc * v,
GstBuffer *buffer, int w, int h);
void gst_gl_test_src_red (GstGLTestSrc * v,
GstBuffer *buffer, int w, int h);
void gst_gl_test_src_green (GstGLTestSrc * v,
GstBuffer *buffer, int w, int h);
void gst_gl_test_src_blue (GstGLTestSrc * v,
GstBuffer *buffer, int w, int h);
void gst_gl_test_src_checkers1 (GstGLTestSrc * v,
GstBuffer *buffer, int w, int h);
void gst_gl_test_src_checkers2 (GstGLTestSrc * v,
GstBuffer *buffer, int w, int h);
void gst_gl_test_src_checkers4 (GstGLTestSrc * v,
GstBuffer *buffer, int w, int h);
void gst_gl_test_src_checkers8 (GstGLTestSrc * v,
GstBuffer *buffer, int w, int h);
void gst_gl_test_src_circular (GstGLTestSrc * v,
GstBuffer *buffer, int w, int h);
#endif

546
ext/gl/gstglbumper.c Normal file
View file

@ -0,0 +1,546 @@
/*
* GStreamer
* Copyright (C) 2008 Cyril Comparon <cyril.comparon@gmail.com>
* Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:element-glbumper
*
* Bump mapping using the normal method.
*
* <refsect2>
* <title>Examples</title>
* |[
* gst-launch -v videotestsrc ! glupload ! glbumper location=normalmap.bmp ! glimagesink
* ]| A pipeline to test normal mapping.
* FBO (Frame Buffer Object) and GLSL (OpenGL Shading Language) are required.
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <png.h>
#include "gstglbumper.h"
#if PNG_LIBPNG_VER >= 10400
#define int_p_NULL NULL
#define png_infopp_NULL NULL
#endif
#define GST_CAT_DEFAULT gst_gl_bumper_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
enum
{
PROP_0,
PROP_LOCATION
};
#define DEBUG_INIT \
GST_DEBUG_CATEGORY_INIT (gst_gl_bumper_debug, "glbumper", 0, "glbumper element");
G_DEFINE_TYPE_WITH_CODE (GstGLBumper, gst_gl_bumper, GST_TYPE_GL_FILTER,
DEBUG_INIT);
static void gst_gl_bumper_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_gl_bumper_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_gl_bumper_reset (GstGLFilter * filter);
static gboolean gst_gl_bumper_init_shader (GstGLFilter * filter);
static gboolean gst_gl_bumper_filter_texture (GstGLFilter * filter,
guint in_tex, guint out_tex);
static void gst_gl_bumper_callback (gint width, gint height, guint texture,
gpointer stuff);
//vertex source
static const gchar *bumper_v_src =
"attribute vec3 aTangent;\n"
"\n"
"varying vec3 vNormal;\n"
"varying vec3 vTangent;\n"
"varying vec3 vVertexToLight0;\n"
"varying vec3 vVertexToLight1;\n"
"\n"
"void main()\n"
"{\n"
" // transform the vertex\n"
" gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n"
"\n"
" // transform the normal and the tangent to scene coords\n"
" vNormal = normalize(gl_NormalMatrix * gl_Normal);\n"
" vTangent = normalize(gl_NormalMatrix * aTangent);\n"
"\n"
" // transforming the vertex position to modelview-space\n"
" //const vec4 vertexInSceneCoords = gl_ModelViewMatrix * gl_Vertex;\n"
"\n"
" // calculate the vector from the vertex position to the light position\n"
" vVertexToLight0 = normalize(gl_LightSource[0].position).xyz;\n"
" vVertexToLight1 = normalize(gl_LightSource[1].position).xyz;\n"
"\n"
" // transit vertex color\n"
" gl_FrontColor = gl_BackColor = gl_Color;\n"
"\n"
" // use the two first sets of texture coordinates in the fragment shader\n"
" gl_TexCoord[0] = gl_MultiTexCoord0;\n"
" gl_TexCoord[1] = gl_MultiTexCoord1;\n" "}\n";
//fragment source
static const gchar *bumper_f_src =
"uniform sampler2D texture0;\n"
"uniform sampler2D texture1;\n"
"\n"
"varying vec3 vNormal;\n"
"varying vec3 vTangent;\n"
"varying vec3 vVertexToLight0;\n"
"varying vec3 vVertexToLight1;\n"
"\n"
"void main()\n"
"{\n"
" // get the color of the textures\n"
" vec4 textureColor = texture2D(texture0, gl_TexCoord[0].st);\n"
" vec3 normalmapItem = texture2D(texture1, gl_TexCoord[1].st).xyz * 2.0 - 1.0;\n"
"\n"
" // calculate matrix that transform from tangent space to normalmap space (contrary of intuition)\n"
" vec3 binormal = cross(vNormal, vTangent);\n"
" mat3 tangentSpace2normalmapSpaceMat = mat3(vTangent, binormal, vNormal);\n"
"\n"
" // disturb the normal\n"
" vec3 disturbedNormal = tangentSpace2normalmapSpaceMat * normalmapItem;\n"
"\n"
" // calculate the diffuse term and clamping it to [0;1]\n"
" float diffuseTerm0 = clamp(dot(disturbedNormal, vVertexToLight0), 0.0, 1.0);\n"
" float diffuseTerm1 = clamp(dot(disturbedNormal, vVertexToLight1), 0.0, 1.0);\n"
"\n"
" vec3 irradiance = (diffuseTerm0 * gl_LightSource[0].diffuse.rgb + diffuseTerm1 * gl_LightSource[1].diffuse.rgb);\n"
"\n"
" // calculate the final color\n"
" gl_FragColor = vec4(irradiance * textureColor.rgb, textureColor.w);\n"
"}\n";
#define LOAD_ERROR(context, msg) { gst_gl_context_set_error (context, "unable to load %s: %s", bumper->location, msg); return; }
//png reading error handler
static void
user_warning_fn (png_structp png_ptr, png_const_charp warning_msg)
{
g_warning ("%s\n", warning_msg);
}
//Called in the gl thread
static void
gst_gl_bumper_init_resources (GstGLFilter * filter)
{
GstGLBumper *bumper = GST_GL_BUMPER (filter);
GstGLContext *context = filter->context;
const GstGLFuncs *gl = context->gl_vtable;
png_structp png_ptr;
png_infop info_ptr;
png_uint_32 width = 0;
png_uint_32 height = 0;
gint bit_depth = 0;
gint color_type = 0;
gint interlace_type = 0;
png_FILE_p fp = NULL;
guint y = 0;
guchar *raw_data = NULL;
guchar **rows = NULL;
png_byte magic[8];
gint n_read;
if (!context)
return;
if (!bumper->location) {
gst_gl_context_set_error (context, "A filename is required");
return;
}
/* BEGIN load png image file */
if ((fp = fopen (bumper->location, "rb")) == NULL)
LOAD_ERROR (context, "file not found");
/* Read magic number */
n_read = fread (magic, 1, sizeof (magic), fp);
if (n_read != sizeof (magic)) {
fclose (fp);
LOAD_ERROR (context, "can't read PNG magic number");
}
/* Check for valid magic number */
if (png_sig_cmp (magic, 0, sizeof (magic))) {
fclose (fp);
LOAD_ERROR (context, "not a valid PNG image");
}
png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL) {
fclose (fp);
LOAD_ERROR (context, "failed to initialize the png_struct");
}
png_set_error_fn (png_ptr, NULL, NULL, user_warning_fn);
info_ptr = png_create_info_struct (png_ptr);
if (info_ptr == NULL) {
fclose (fp);
png_destroy_read_struct (&png_ptr, png_infopp_NULL, png_infopp_NULL);
LOAD_ERROR (context,
"failed to initialize the memory for image information");
}
png_init_io (png_ptr, fp);
png_set_sig_bytes (png_ptr, sizeof (magic));
png_read_info (png_ptr, info_ptr);
png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
&interlace_type, int_p_NULL, int_p_NULL);
if (color_type != PNG_COLOR_TYPE_RGB) {
fclose (fp);
png_destroy_read_struct (&png_ptr, png_infopp_NULL, png_infopp_NULL);
LOAD_ERROR (context, "color type is not rgb");
}
raw_data = (guchar *) malloc (sizeof (guchar) * width * height * 3);
rows = (guchar **) malloc (sizeof (guchar *) * height);
for (y = 0; y < height; ++y)
rows[y] = (guchar *) (raw_data + y * width * 3);
png_read_image (png_ptr, rows);
free (rows);
png_read_end (png_ptr, info_ptr);
png_destroy_read_struct (&png_ptr, &info_ptr, png_infopp_NULL);
fclose (fp);
/* END load png image file */
bumper->bumpmap_width = width;
bumper->bumpmap_height = height;
gl->GenTextures (1, &bumper->bumpmap);
gl->BindTexture (GL_TEXTURE_2D, bumper->bumpmap);
gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGBA,
bumper->bumpmap_width, bumper->bumpmap_height, 0,
GL_RGB, GL_UNSIGNED_BYTE, raw_data);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
free (raw_data);
}
//Called in the gl thread
static void
gst_gl_bumper_reset_resources (GstGLFilter * filter)
{
GstGLBumper *bumper = GST_GL_BUMPER (filter);
if (bumper->bumpmap) {
glDeleteTextures (1, &bumper->bumpmap);
bumper->bumpmap = 0;
}
}
static void
gst_gl_bumper_class_init (GstGLBumperClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *element_class;
gobject_class = (GObjectClass *) klass;
element_class = GST_ELEMENT_CLASS (klass);
gobject_class->set_property = gst_gl_bumper_set_property;
gobject_class->get_property = gst_gl_bumper_get_property;
GST_GL_FILTER_CLASS (klass)->filter_texture = gst_gl_bumper_filter_texture;
GST_GL_FILTER_CLASS (klass)->display_init_cb = gst_gl_bumper_init_resources;
GST_GL_FILTER_CLASS (klass)->display_reset_cb = gst_gl_bumper_reset_resources;
GST_GL_FILTER_CLASS (klass)->onInitFBO = gst_gl_bumper_init_shader;
GST_GL_FILTER_CLASS (klass)->onReset = gst_gl_bumper_reset;
g_object_class_install_property (gobject_class,
PROP_LOCATION, g_param_spec_string ("location",
"Normal map location",
"Normal map location", NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_element_class_set_metadata (element_class, "OpenGL bumper filter",
"Filter/Effect/Video", "Bump mapping filter",
"Cyril Comparon <cyril.comparon@gmail.com>, "
"Julien Isorce <julien.isorce@gmail.com>");
}
static void
gst_gl_bumper_init (GstGLBumper * bumper)
{
bumper->shader = NULL;
bumper->bumpmap = 0;
bumper->bumpmap_width = 0;
bumper->bumpmap_height = 0;
bumper->location = NULL;
}
static void
gst_gl_bumper_reset (GstGLFilter * filter)
{
GstGLBumper *bumper_filter = GST_GL_BUMPER (filter);
//blocking call, wait the opengl thread has destroyed the shader
if (bumper_filter->shader)
gst_gl_context_del_shader (filter->context, bumper_filter->shader);
bumper_filter->shader = NULL;
}
static void
gst_gl_bumper_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstGLBumper *bumper = GST_GL_BUMPER (object);
switch (prop_id) {
case PROP_LOCATION:
if (bumper->location != NULL)
g_free (bumper->location);
bumper->location = g_value_dup_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_bumper_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstGLBumper *bumper = GST_GL_BUMPER (object);
switch (prop_id) {
case PROP_LOCATION:
g_value_set_string (value, bumper->location);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
gst_gl_bumper_init_shader (GstGLFilter * filter)
{
GstGLBumper *bumper = GST_GL_BUMPER (filter);
//blocking call, wait the opengl thread has compiled the shader
return gst_gl_context_gen_shader (filter->context, bumper_v_src, bumper_f_src,
&bumper->shader);
}
static gboolean
gst_gl_bumper_filter_texture (GstGLFilter * filter, guint in_tex, guint out_tex)
{
gpointer bumper_filter = GST_GL_BUMPER (filter);
//blocking call, use a FBO
gst_gl_context_use_fbo (filter->context,
GST_VIDEO_INFO_WIDTH (&filter->out_info),
GST_VIDEO_INFO_HEIGHT (&filter->out_info),
filter->fbo, filter->depthbuffer, out_tex, gst_gl_bumper_callback,
GST_VIDEO_INFO_WIDTH (&filter->in_info),
GST_VIDEO_INFO_HEIGHT (&filter->in_info),
in_tex, 45,
(gdouble) GST_VIDEO_INFO_WIDTH (&filter->out_info) /
(gdouble) GST_VIDEO_INFO_HEIGHT (&filter->out_info), 0.1, 50,
GST_GL_DISPLAY_PROJECTION_PERSPECTIVE, bumper_filter);
return TRUE;
}
typedef struct _MeshData
{
float x, y, z; /* Vertex */
float nx, ny, nz; /* Normal */
float s0, t0; /* TexCoord0 */
float s1, t1; /* TexCoord1 */
float va0, vb0, vc0; /* VertexAttrib */
} MeshData;
//opengl scene, params: input texture (not the output filter->texture)
static void
gst_gl_bumper_callback (gint width, gint height, guint texture, gpointer stuff)
{
static GLfloat xrot = 0;
static GLfloat yrot = 0;
static GLfloat zrot = 0;
GstGLFuncs *gl;
GstGLBumper *bumper = GST_GL_BUMPER (stuff);
GstGLContext *context = GST_GL_FILTER (bumper)->context;
GLint locTangent = 0;
//choose the lights
GLfloat light_direction0[] = { 1.0, 0.0, -1.0, 0.0 }; // light goes along -x
GLfloat light_direction1[] = { -1.0, 0.0, -1.0, 0.0 }; // light goes along x
GLfloat light_diffuse0[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat light_diffuse1[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat mat_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
/* *INDENT-OFF* */
MeshData mesh[] = {
/* | Vertex | Normal |TexCoord0|TexCoord1| VertexAttrib | */
/*F*/ { 1.0, 1.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0},
/*r*/ { 1.0, -1.0, -1.0, 0.0, 0.0, -1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0},
/*o*/ {-1.0, -1.0, -1.0, 0.0, 0.0, -1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0},
{-1.0, 1.0, -1.0, 0.0, 0.0, -1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0},
/*R*/ {-1.0, 1.0, -1.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0},
/*i*/ {-1.0, -1.0, -1.0, -1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0},
/*g*/ {-1.0, -1.0, 1.0, -1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0},
{-1.0, 1.0, 1.0, -1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0},
/*B*/ {-1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0},
/*a*/ {-1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0},
/*c*/ { 1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0},
{ 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0},
/*L*/ { 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0},
/*e*/ { 1.0, -1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0},
/*f*/ { 1.0, -1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0},
{ 1.0, 1.0, -1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0},
/*T*/ { 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0},
/*o*/ { 1.0, 1.0, -1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0},
/*p*/ {-1.0, 1.0, -1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0},
{-1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0},
/*B*/ { 1.0, -1.0, -1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0},
/*o*/ { 1.0, -1.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, -1.0},
/*t*/ {-1.0, -1.0, 1.0, 0.0, -1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, -1.0},
{-1.0, -1.0, -1.0, 0.0, -1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, -1.0},
};
GLushort indices[] = {
0, 1, 2,
0, 2, 3,
4, 5, 6,
4, 6, 7,
8, 9, 10,
8, 10, 11,
12, 13, 14,
12, 14, 15,
16, 17, 18,
16, 18, 19,
20, 21, 22,
20, 22, 23
};
/* *INDENT-ON* */
gl = GST_GL_FILTER (bumper)->context->gl_vtable;
//eye point
gl->MatrixMode (GL_PROJECTION);
gluLookAt (0.0, 0.0, -6.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
gl->MatrixMode (GL_MODELVIEW);
//scene conf
gl->Enable (GL_DEPTH_TEST);
gl->DepthFunc (GL_LEQUAL);
gl->Hint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
gl->ShadeModel (GL_SMOOTH);
//set the lights
gl->Lightfv (GL_LIGHT0, GL_POSITION, light_direction0);
gl->Lightfv (GL_LIGHT0, GL_DIFFUSE, light_diffuse0);
gl->Lightfv (GL_LIGHT1, GL_POSITION, light_direction1);
gl->Lightfv (GL_LIGHT1, GL_DIFFUSE, light_diffuse1);
gl->Materialfv (GL_FRONT, GL_DIFFUSE, mat_diffuse);
gl->ColorMaterial (GL_FRONT_AND_BACK, GL_DIFFUSE);
gl->Enable (GL_COLOR_MATERIAL);
gl->Enable (GL_LIGHTING);
gl->Enable (GL_LIGHT0);
gl->Enable (GL_LIGHT1);
//configure shader
gst_gl_shader_use (bumper->shader);
locTangent =
gst_gl_shader_get_attribute_location (bumper->shader, "aTangent");
//set the normal map
gl->ActiveTexture (GL_TEXTURE1);
gst_gl_shader_set_uniform_1i (bumper->shader, "texture1", 1);
gl->BindTexture (GL_TEXTURE_2D, bumper->bumpmap);
//set the video texture
gl->ActiveTexture (GL_TEXTURE0);
gst_gl_shader_set_uniform_1i (bumper->shader, "texture0", 0);
gl->BindTexture (GL_TEXTURE_2D, texture);
gl->Rotatef (xrot, 1.0f, 0.0f, 0.0f);
gl->Rotatef (yrot, 0.0f, 1.0f, 0.0f);
gl->Rotatef (zrot, 0.0f, 0.0f, 1.0f);
gl->EnableVertexAttribArray (locTangent);
gl->ClientActiveTexture (GL_TEXTURE0);
gl->EnableClientState (GL_TEXTURE_COORD_ARRAY);
gl->EnableClientState (GL_VERTEX_ARRAY);
gl->EnableClientState (GL_NORMAL_ARRAY);
gl->VertexAttribPointer (locTangent, 3, GL_FLOAT, 0, sizeof (MeshData),
&mesh[0].va0);
gl->VertexPointer (3, GL_FLOAT, sizeof (MeshData), &mesh[0].x);
gl->NormalPointer (GL_FLOAT, sizeof (MeshData), &mesh[0].nx);
gl->TexCoordPointer (2, GL_FLOAT, sizeof (MeshData), &mesh[0].s0);
gl->ClientActiveTexture (GL_TEXTURE1);
gl->EnableClientState (GL_TEXTURE_COORD_ARRAY);
gl->TexCoordPointer (2, GL_FLOAT, sizeof (MeshData), &mesh[0].s1);
gl->DrawElements (GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, indices);
gl->DisableClientState (GL_VERTEX_ARRAY);
gl->DisableClientState (GL_TEXTURE_COORD_ARRAY);
gl->DisableClientState (GL_NORMAL_ARRAY);
gl->ClientActiveTexture (GL_TEXTURE0);
gl->DisableClientState (GL_TEXTURE_COORD_ARRAY);
gl->DisableVertexAttribArray (locTangent);
gst_gl_context_clear_shader (context);
gl->Disable (GL_LIGHT0);
gl->Disable (GL_LIGHT1);
gl->Disable (GL_LIGHTING);
gl->Disable (GL_COLOR_MATERIAL);
xrot += 1.0f;
yrot += 0.9f;
zrot += 0.6f;
}

57
ext/gl/gstglbumper.h Normal file
View file

@ -0,0 +1,57 @@
/*
* GStreamer
* Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef _GST_GL_BUMPER_H_
#define _GST_GL_BUMPER_H_
#include <gst/gl/gstglfilter.h>
G_BEGIN_DECLS
#define GST_TYPE_GL_BUMPER (gst_gl_bumper_get_type())
#define GST_GL_BUMPER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_BUMPER,GstGLBumper))
#define GST_IS_GL_BUMPER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_BUMPER))
#define GST_GL_BUMPER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_BUMPER,GstGLBumperClass))
#define GST_IS_GL_BUMPER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_BUMPER))
#define GST_GL_BUMPER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_BUMPER,GstGLBumperClass))
typedef struct _GstGLBumper GstGLBumper;
typedef struct _GstGLBumperClass GstGLBumperClass;
struct _GstGLBumper
{
GstGLFilter filter;
GstGLShader *shader;
GLuint bumpmap;
gint bumpmap_width;
gint bumpmap_height;
gchar *location;
};
struct _GstGLBumperClass
{
GstGLFilterClass filter_class;
};
GType gst_gl_bumper_get_type (void);
G_END_DECLS
#endif /* _GST_GLBUMPER_H_ */

156
ext/gl/gstglcolorscale.c Normal file
View file

@ -0,0 +1,156 @@
/*
* GStreamer
* Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:element-glcolorscale
*
* video frame scaling and colorspace conversion.
*
* <refsect2>
* <title>Scaling and Color space conversion</title>
* <para>
* Equivalent to glupload ! gldownload.
* </para>
* </refsect2>
* <refsect2>
* <title>Examples</title>
* |[
* gst-launch -v videotestsrc ! "video/x-raw-yuv" ! glcolorscale ! ximagesink
* ]| A pipeline to test colorspace conversion.
* FBO is required.
|[
* gst-launch -v videotestsrc ! "video/x-raw-yuv, width=640, height=480, format=(fourcc)AYUV" ! glcolorscale ! \
* "video/x-raw-yuv, width=320, height=240, format=(fourcc)YV12" ! autovideosink
* ]| A pipeline to test hardware scaling and colorspace conversion.
* FBO and GLSL are required.
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstglcolorscale.h"
#define GST_CAT_DEFAULT gst_gl_colorscale_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
/* Properties */
enum
{
PROP_0
};
#define DEBUG_INIT \
GST_DEBUG_CATEGORY_INIT (gst_gl_colorscale_debug, "glcolorscale", 0, "glcolorscale element");
G_DEFINE_TYPE_WITH_CODE (GstGLColorscale, gst_gl_colorscale,
GST_TYPE_GL_FILTER, DEBUG_INIT);
static void gst_gl_colorscale_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_gl_colorscale_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static gboolean gst_gl_colorscale_filter_texture (GstGLFilter * filter,
guint in_tex, guint out_tex);
static void gst_gl_colorscale_callback (gint width, gint height,
guint texture, gpointer stuff);
static void
gst_gl_colorscale_class_init (GstGLColorscaleClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *element_class;
GstGLFilterClass *filter_class;
gobject_class = (GObjectClass *) klass;
element_class = GST_ELEMENT_CLASS (klass);
filter_class = GST_GL_FILTER_CLASS (klass);
gobject_class->set_property = gst_gl_colorscale_set_property;
gobject_class->get_property = gst_gl_colorscale_get_property;
gst_element_class_set_metadata (element_class, "OpenGL color scale",
"Filter/Effect/Video", "Colorspace converter and video scaler",
"Julien Isorce <julien.isorce@gmail.com>");
filter_class->filter_texture = gst_gl_colorscale_filter_texture;
}
static void
gst_gl_colorscale_init (GstGLColorscale * colorscale)
{
}
static void
gst_gl_colorscale_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_colorscale_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
gst_gl_colorscale_filter_texture (GstGLFilter * filter, guint in_tex,
guint out_tex)
{
GstGLColorscale *colorscale;
colorscale = GST_GL_COLORSCALE (filter);
gst_gl_filter_render_to_target (filter, TRUE, in_tex, out_tex,
gst_gl_colorscale_callback, colorscale);
return TRUE;
}
static void
gst_gl_colorscale_callback (gint width, gint height, guint texture,
gpointer stuff)
{
GstGLFilter *filter = GST_GL_FILTER (stuff);
#if GST_GL_HAVE_OPENGL
if (gst_gl_context_get_gl_api (filter->context) & GST_GL_API_OPENGL) {
const GstGLFuncs *gl = filter->context->gl_vtable;
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
}
#endif
gst_gl_filter_draw_texture (filter, texture, width, height);
}

56
ext/gl/gstglcolorscale.h Normal file
View file

@ -0,0 +1,56 @@
/*
* GStreamer
* Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef _GST_GLCOLORSCALE_H_
#define _GST_GLCOLORSCALE_H_
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/gl/gstglfilter.h>
G_BEGIN_DECLS
#define GST_TYPE_GL_COLORSCALE (gst_gl_colorscale_get_type())
#define GST_GL_COLORSCALE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_COLORSCALE,GstGLColorscale))
#define GST_IS_GL_COLORSCALE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_COLORSCALE))
#define GST_GL_COLORSCALE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_COLORSCALE,GstGLColorscaleClass))
#define GST_IS_GL_COLORSCALE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_COLORSCALE))
#define GST_GL_COLORSCALE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_COLORSCALE,GstGLColorscaleClass))
typedef struct _GstGLColorscale GstGLColorscale;
typedef struct _GstGLColorscaleClass GstGLColorscaleClass;
struct _GstGLColorscale
{
GstGLFilter filter;
};
struct _GstGLColorscaleClass
{
GstGLFilterClass filter_class;
};
GType gst_gl_colorscale_get_type (void);
G_END_DECLS
#endif /* _GST_GLCOLORSCALE_H_ */

351
ext/gl/gstgldeinterlace.c Normal file
View file

@ -0,0 +1,351 @@
/*
* GStreamer
* Copyright (C) 2009 Julien Isorce <julien.isorce@mail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:element-deinterlace
*
* Deinterlacing using based on fragment shaders.
*
* <refsect2>
* <title>Examples</title>
* |[
* gst-launch videotestsrc ! glupload ! gldeinterlace ! glimagesink
* ]|
* FBO (Frame Buffer Object) and GLSL (OpenGL Shading Language) are required.
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstgldeinterlace.h"
#define GST_CAT_DEFAULT gst_gl_deinterlace_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
enum
{
PROP_0
};
#define DEBUG_INIT \
GST_DEBUG_CATEGORY_INIT (gst_gl_deinterlace_debug, "gldeinterlace", 0, "gldeinterlace element");
G_DEFINE_TYPE_WITH_CODE (GstGLDeinterlace, gst_gl_deinterlace,
GST_TYPE_GL_FILTER, DEBUG_INIT);
static void gst_gl_deinterlace_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec);
static void gst_gl_deinterlace_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec);
static void gst_gl_deinterlace_reset (GstGLFilter * filter);
static gboolean gst_gl_deinterlace_init_shader (GstGLFilter * filter);
static gboolean gst_gl_deinterlace_filter (GstGLFilter * filter,
GstBuffer * inbuf, GstBuffer * outbuf);
static gboolean gst_gl_deinterlace_filter_texture (GstGLFilter * filter,
guint in_tex, guint out_tex);
static void gst_gl_deinterlace_callback (gint width, gint height,
guint texture, gpointer stuff);
/* *INDENT-OFF* */
static const gchar *greedyh_fragment_source =
"uniform sampler2D tex;\n"
"uniform sampler2D tex_prev;\n"
"uniform float max_comb;\n"
"uniform float motion_threshold;\n"
"uniform float motion_sense;\n"
"uniform float width;\n"
"uniform float height;\n"
"void main () {\n"
" vec2 texcoord = gl_TexCoord[0].xy;\n"
" if (int(mod(texcoord.y * height, 2.0)) == 0) {\n"
" gl_FragColor = vec4(texture2D(tex_prev, texcoord).rgb, 1.0);\n"
" } else {\n"
" vec2 texcoord_L1_a1, texcoord_L3_a1, texcoord_L1, texcoord_L3, texcoord_L1_1, texcoord_L3_1;\n"
" vec3 L1_a1, L3_a1, L1, L3, L1_1, L3_1;\n"
" texcoord_L1 = vec2(texcoord.x, texcoord.y - 1.0 / height);\n"
" texcoord_L3 = vec2(texcoord.x, texcoord.y + 1.0 / height);\n"
" L1 = texture2D(tex_prev, texcoord_L1).rgb;\n"
" L3 = texture2D(tex_prev, texcoord_L3).rgb;\n"
" if (texcoord.x == 1.0 && texcoord.y == 1.0) {\n"
" L1_1 = L1;\n"
" L3_1 = L3;\n"
" } else {\n"
" texcoord_L1_1 = vec2(texcoord.x + 1.0 / width, texcoord.y - 1.0 / height);\n"
" texcoord_L3_1 = vec2(texcoord.x + 1.0 / width, texcoord.y + 1.0 / height);\n"
" L1_1 = texture2D(tex_prev, texcoord_L1_1).rgb;\n"
" L3_1 = texture2D(tex_prev, texcoord_L3_1).rgb;\n"
" }\n"
" if (int(ceil(texcoord.x + texcoord.y)) == 0) {\n"
" L1_a1 = L1;\n"
" L3_a1 = L3;\n"
" } else {\n"
" texcoord_L1_a1 = vec2(texcoord.x - 1.0 / width, texcoord.y - 1.0 / height);\n"
" texcoord_L3_a1 = vec2(texcoord.x - 1.0 / width, texcoord.y + 1.0 / height);\n"
" L1_a1 = texture2D(tex_prev, texcoord_L1_a1).rgb;\n"
" L3_a1 = texture2D(tex_prev, texcoord_L3_a1).rgb;\n"
" }\n"
//STEP 1
" vec3 avg_a1 = (L1_a1 + L3_a1) / 2.0;\n"
" vec3 avg = (L1 + L3) / 2.0;\n"
" vec3 avg_1 = (L1_1 + L3_1) / 2.0;\n"
" vec3 avg_s = (avg_a1 + avg_1) / 2.0;\n"
" vec3 avg_sc = (avg_s + avg) / 2.0;\n"
" vec3 L2 = texture2D(tex, texcoord).rgb;\n"
" vec3 LP2 = texture2D(tex_prev, texcoord).rgb;\n"
" vec3 best;\n"
" if (abs(L2.r - avg_sc.r) < abs(LP2.r - avg_sc.r)) {\n"
" best.r = L2.r;\n" " } else {\n"
" best.r = LP2.r;\n"
" }\n"
" if (abs(L2.g - avg_sc.g) < abs(LP2.g - avg_sc.g)) {\n"
" best.g = L2.g;\n"
" } else {\n"
" best.g = LP2.g;\n"
" }\n"
" if (abs(L2.b - avg_sc.b) < abs(LP2.b - avg_sc.b)) {\n"
" best.b = L2.b;\n"
" } else {\n"
" best.b = LP2.b;\n"
" }\n"
//STEP 2
" vec3 last;\n"
" last.r = clamp(best.r, max(min(L1.r, L3.r) - max_comb, 0.0), min(max(L1.r, L3.r) + max_comb, 1.0));\n"
" last.g = clamp(best.g, max(min(L1.g, L3.g) - max_comb, 0.0), min(max(L1.g, L3.g) + max_comb, 1.0));\n"
" last.b = clamp(best.b, max(min(L1.b, L3.b) - max_comb, 0.0), min(max(L1.b, L3.b) + max_comb, 1.0));\n"
//STEP 3
" const vec3 luma = vec3 (0.299011, 0.586987, 0.114001);"
" float mov = min(max(abs(dot(L2 - LP2, luma)) - motion_threshold, 0.0) * motion_sense, 1.0);\n"
" last = last * (1.0 - mov) + avg_sc * mov;\n"
" gl_FragColor = vec4(last, 1.0);\n"
" }\n"
"}\n";
/* *INDENT-ON* */
static void
gst_gl_deinterlace_class_init (GstGLDeinterlaceClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *element_class;
gobject_class = (GObjectClass *) klass;
element_class = GST_ELEMENT_CLASS (klass);
gobject_class->set_property = gst_gl_deinterlace_set_property;
gobject_class->get_property = gst_gl_deinterlace_get_property;
gst_element_class_set_metadata (element_class,
"OpenGL deinterlacing filter", "Deinterlace",
"Deinterlacing based on fragment shaders",
"Julien Isorce <julien.isorce@mail.com>");
GST_GL_FILTER_CLASS (klass)->filter = gst_gl_deinterlace_filter;
GST_GL_FILTER_CLASS (klass)->filter_texture =
gst_gl_deinterlace_filter_texture;
GST_GL_FILTER_CLASS (klass)->onInitFBO = gst_gl_deinterlace_init_shader;
GST_GL_FILTER_CLASS (klass)->onReset = gst_gl_deinterlace_reset;
}
static void
gst_gl_deinterlace_init (GstGLDeinterlace * filter)
{
filter->shader = NULL;
filter->prev_buffer = NULL;
filter->prev_tex = 0;
}
static void
gst_gl_deinterlace_reset (GstGLFilter * filter)
{
GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (filter);
if (deinterlace_filter->prev_buffer) {
gst_buffer_unref (deinterlace_filter->prev_buffer);
deinterlace_filter->prev_buffer = NULL;
}
//blocking call, wait the opengl thread has destroyed the shader
if (deinterlace_filter->shader)
gst_gl_context_del_shader (filter->context, deinterlace_filter->shader);
deinterlace_filter->shader = NULL;
}
static void
gst_gl_deinterlace_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
//GstGLDeinterlace *filter = GST_GL_DEINTERLACE (object);
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_deinterlace_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
//GstGLDeinterlace *filter = GST_GL_DEINTERLACE (object);
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
gst_gl_deinterlace_init_shader (GstGLFilter * filter)
{
GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (filter);
//blocking call, wait the opengl thread has compiled the shader
return gst_gl_context_gen_shader (filter->context, 0, greedyh_fragment_source,
&deinterlace_filter->shader);
}
static gboolean
gst_gl_deinterlace_filter_texture (GstGLFilter * filter, guint in_tex,
guint out_tex)
{
GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (filter);
//blocking call, use a FBO
gst_gl_filter_render_to_target (filter, TRUE, in_tex, out_tex,
gst_gl_deinterlace_callback, deinterlace_filter);
return TRUE;
}
static gboolean
gst_gl_deinterlace_filter (GstGLFilter * filter, GstBuffer * inbuf,
GstBuffer * outbuf)
{
GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (filter);
gst_gl_filter_filter_texture (filter, inbuf, outbuf);
if (deinterlace_filter->prev_buffer) {
gst_buffer_unref (deinterlace_filter->prev_buffer);
}
deinterlace_filter->prev_buffer = gst_buffer_ref (inbuf);
return TRUE;
}
//opengl scene, params: input texture (not the output filter->texture)
static void
gst_gl_deinterlace_callback (gint width, gint height, guint texture,
gpointer stuff)
{
GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (stuff);
GstGLFilter *filter = GST_GL_FILTER (stuff);
GstGLFuncs *gl = filter->context->gl_vtable;
guint temp;
GLfloat verts[] = { -1.0, -1.0,
1.0, -1.0,
1.0, 1.0,
-1.0, 1.0
};
GLfloat texcoords0[] = { 0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f
};
GLfloat texcoords1[] = { 0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f
};
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gst_gl_shader_use (deinterlace_filter->shader);
gl->Enable (GL_TEXTURE_2D);
if (G_UNLIKELY (deinterlace_filter->prev_tex == 0)) {
gst_gl_context_gen_texture (filter->context,
&deinterlace_filter->prev_tex,
GST_VIDEO_INFO_FORMAT (&filter->out_info),
GST_VIDEO_INFO_WIDTH (&filter->out_info),
GST_VIDEO_INFO_HEIGHT (&filter->out_info));
} else {
gl->ActiveTexture (GL_TEXTURE1);
gst_gl_shader_set_uniform_1i (deinterlace_filter->shader, "tex_prev", 1);
gl->BindTexture (GL_TEXTURE_2D, deinterlace_filter->prev_tex);
}
gl->ActiveTexture (GL_TEXTURE0);
gst_gl_shader_set_uniform_1i (deinterlace_filter->shader, "tex", 0);
gl->BindTexture (GL_TEXTURE_2D, texture);
gst_gl_shader_set_uniform_1f (deinterlace_filter->shader, "max_comb",
5.0f / 255.0f);
gst_gl_shader_set_uniform_1f (deinterlace_filter->shader, "motion_threshold",
25.0f / 255.0f);
gst_gl_shader_set_uniform_1f (deinterlace_filter->shader, "motion_sense",
30.0f / 255.0f);
gst_gl_shader_set_uniform_1f (deinterlace_filter->shader, "width",
GST_VIDEO_INFO_WIDTH (&filter->out_info));
gst_gl_shader_set_uniform_1f (deinterlace_filter->shader, "height",
GST_VIDEO_INFO_HEIGHT (&filter->out_info));
gl->ClientActiveTexture (GL_TEXTURE0);
gl->EnableClientState (GL_TEXTURE_COORD_ARRAY);
gl->EnableClientState (GL_VERTEX_ARRAY);
gl->VertexPointer (2, GL_FLOAT, 0, &verts);
gl->TexCoordPointer (2, GL_FLOAT, 0, &texcoords0);
gl->ClientActiveTexture (GL_TEXTURE1);
gl->EnableClientState (GL_TEXTURE_COORD_ARRAY);
gl->TexCoordPointer (2, GL_FLOAT, 0, &texcoords1);
gl->DrawArrays (GL_TRIANGLE_FAN, 0, 4);
gl->DisableClientState (GL_VERTEX_ARRAY);
gl->DisableClientState (GL_TEXTURE_COORD_ARRAY);
gl->ClientActiveTexture (GL_TEXTURE0);
gl->DisableClientState (GL_TEXTURE_COORD_ARRAY);
gl->Disable (GL_TEXTURE_2D);
if (texture == filter->in_tex_id) {
temp = filter->in_tex_id;
filter->in_tex_id = deinterlace_filter->prev_tex;
deinterlace_filter->prev_tex = temp;
} else {
deinterlace_filter->prev_tex = texture;
}
}

55
ext/gl/gstgldeinterlace.h Normal file
View file

@ -0,0 +1,55 @@
/*
* GStreamer
* Copyright (C) 2009 Julien Isorce <julien.isorce@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef _GST_GL_DEINTERLACE_H_
#define _GST_GL_DEINTERLACE_H_
#include <gst/gl/gstglfilter.h>
G_BEGIN_DECLS
#define GST_TYPE_GL_DEINTERLACE (gst_gl_deinterlace_get_type())
#define GST_GL_DEINTERLACE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_DEINTERLACE,GstGLDeinterlace))
#define GST_IS_GL_DEINTERLACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_DEINTERLACE))
#define GST_GL_DEINTERLACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_DEINTERLACE,GstGLDeinterlaceClass))
#define GST_IS_GL_DEINTERLACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_DEINTERLACE))
#define GST_GL_DEINTERLACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_DEINTERLACE,GstGLDeinterlaceClass))
typedef struct _GstGLDeinterlace GstGLDeinterlace;
typedef struct _GstGLDeinterlaceClass GstGLDeinterlaceClass;
struct _GstGLDeinterlace
{
GstGLFilter filter;
GstGLShader *shader;
GstBuffer *prev_buffer;
guint prev_tex;
};
struct _GstGLDeinterlaceClass
{
GstGLFilterClass filter_class;
};
GType gst_gl_deinterlace_get_type (void);
G_END_DECLS
#endif /* _GST_GLFILTERLAPLACIAN_H_ */

View file

@ -0,0 +1,581 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:element-gldifferencematte.
*
* Saves a background frame and replace it with a pixbuf.
*
* <refsect2>
* <title>Examples</title>
* |[
* gst-launch videotestsrc ! glupload ! gldifferencemate location=backgroundimagefile ! glimagesink
* ]|
* FBO (Frame Buffer Object) and GLSL (OpenGL Shading Language) are required.
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <png.h>
#include "gstgldifferencematte.h"
#include "effects/gstgleffectssources.h"
#if PNG_LIBPNG_VER >= 10400
#define int_p_NULL NULL
#define png_infopp_NULL NULL
#endif
#define GST_CAT_DEFAULT gst_gl_differencematte_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#define DEBUG_INIT \
GST_DEBUG_CATEGORY_INIT (gst_gl_differencematte_debug, "gldifferencematte", 0, "gldifferencematte element");
G_DEFINE_TYPE_WITH_CODE (GstGLDifferenceMatte, gst_gl_differencematte,
GST_TYPE_GL_FILTER, DEBUG_INIT);
static void gst_gl_differencematte_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec);
static void gst_gl_differencematte_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec);
static void gst_gl_differencematte_init_resources (GstGLFilter * filter);
static void gst_gl_differencematte_reset_resources (GstGLFilter * filter);
static gboolean gst_gl_differencematte_filter_texture (GstGLFilter * filter,
guint in_tex, guint out_tex);
static gboolean gst_gl_differencematte_loader (GstGLFilter * filter);
enum
{
PROP_0,
PROP_LOCATION,
};
/* init resources that need a gl context */
static void
gst_gl_differencematte_init_gl_resources (GstGLFilter * filter)
{
GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (filter);
GstGLFuncs *gl = filter->context->gl_vtable;
gint i;
for (i = 0; i < 4; i++) {
gl->GenTextures (1, &differencematte->midtexture[i]);
gl->BindTexture (GL_TEXTURE_2D, differencematte->midtexture[i]);
gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8,
GST_VIDEO_INFO_WIDTH (&filter->out_info),
GST_VIDEO_INFO_HEIGHT (&filter->out_info),
0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
differencematte->shader[i] = gst_gl_shader_new (filter->context);
}
if (!gst_gl_shader_compile_and_check (differencematte->shader[0],
difference_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
gst_gl_context_set_error (GST_GL_FILTER (differencematte)->context,
"Failed to initialize difference shader");
GST_ELEMENT_ERROR (differencematte, RESOURCE, NOT_FOUND,
("%s", gst_gl_context_get_error ()), (NULL));
return;
}
if (!gst_gl_shader_compile_and_check (differencematte->shader[1],
hconv7_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
gst_gl_context_set_error (GST_GL_FILTER (differencematte)->context,
"Failed to initialize hconv7 shader");
GST_ELEMENT_ERROR (differencematte, RESOURCE, NOT_FOUND,
("%s", gst_gl_context_get_error ()), (NULL));
return;
}
if (!gst_gl_shader_compile_and_check (differencematte->shader[2],
vconv7_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
gst_gl_context_set_error (GST_GL_FILTER (differencematte)->context,
"Failed to initialize vconv7 shader");
GST_ELEMENT_ERROR (differencematte, RESOURCE, NOT_FOUND,
("%s", gst_gl_context_get_error ()), (NULL));
return;
}
if (!gst_gl_shader_compile_and_check (differencematte->shader[3],
texture_interp_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) {
gst_gl_context_set_error (GST_GL_FILTER (differencematte)->context,
"Failed to initialize interp shader");
GST_ELEMENT_ERROR (differencematte, RESOURCE, NOT_FOUND,
("%s", gst_gl_context_get_error ()), (NULL));
return;
}
}
/* free resources that need a gl context */
static void
gst_gl_differencematte_reset_gl_resources (GstGLFilter * filter)
{
GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (filter);
GstGLFuncs *gl = filter->context->gl_vtable;
gint i;
gl->DeleteTextures (1, &differencematte->savedbgtexture);
gl->DeleteTextures (1, &differencematte->newbgtexture);
for (i = 0; i < 4; i++) {
if (differencematte->shader[i]) {
gst_object_unref (differencematte->shader[i]);
differencematte->shader[i] = NULL;
}
if (differencematte->midtexture[i]) {
gl->DeleteTextures (1, &differencematte->midtexture[i]);
differencematte->midtexture[i] = 0;
}
}
differencematte->location = NULL;
differencematte->pixbuf = NULL;
differencematte->savedbgtexture = 0;
differencematte->newbgtexture = 0;
differencematte->bg_has_changed = FALSE;
}
static void
gst_gl_differencematte_class_init (GstGLDifferenceMatteClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *element_class;
gobject_class = (GObjectClass *) klass;
element_class = GST_ELEMENT_CLASS (klass);
gobject_class->set_property = gst_gl_differencematte_set_property;
gobject_class->get_property = gst_gl_differencematte_get_property;
GST_GL_FILTER_CLASS (klass)->filter_texture =
gst_gl_differencematte_filter_texture;
GST_GL_FILTER_CLASS (klass)->display_init_cb =
gst_gl_differencematte_init_gl_resources;
GST_GL_FILTER_CLASS (klass)->display_reset_cb =
gst_gl_differencematte_reset_gl_resources;
GST_GL_FILTER_CLASS (klass)->onStart = gst_gl_differencematte_init_resources;
GST_GL_FILTER_CLASS (klass)->onStop = gst_gl_differencematte_reset_resources;
g_object_class_install_property (gobject_class,
PROP_LOCATION,
g_param_spec_string ("location",
"Background image location",
"Background image location", NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_element_class_set_metadata (element_class,
"Gstreamer OpenGL DifferenceMatte", "Filter/Effect/Video",
"Saves a background frame and replace it with a pixbuf",
"Filippo Argiolas <filippo.argiolas@gmail.com>");
}
static void
gst_gl_differencematte_init (GstGLDifferenceMatte * differencematte)
{
differencematte->shader[0] = NULL;
differencematte->shader[1] = NULL;
differencematte->shader[2] = NULL;
differencematte->shader[3] = NULL;
differencematte->location = NULL;
differencematte->pixbuf = NULL;
differencematte->savedbgtexture = 0;
differencematte->newbgtexture = 0;
differencematte->bg_has_changed = FALSE;
fill_gaussian_kernel (differencematte->kernel, 7, 30.0);
}
static void
gst_gl_differencematte_reset_resources (GstGLFilter * filter)
{
// GstGLDifferenceMatte* differencematte = GST_GL_DIFFERENCEMATTE(filter);
}
static void
gst_gl_differencematte_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (object);
switch (prop_id) {
case PROP_LOCATION:
if (differencematte->location != NULL)
g_free (differencematte->location);
differencematte->bg_has_changed = TRUE;
differencematte->location = g_value_dup_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_differencematte_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (object);
switch (prop_id) {
case PROP_LOCATION:
g_value_set_string (value, differencematte->location);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_differencematte_init_resources (GstGLFilter * filter)
{
// GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (filter);
}
static void
gst_gl_differencematte_save_texture (gint width, gint height, guint texture,
gpointer stuff)
{
GstGLFilter *filter = GST_GL_FILTER (stuff);
GstGLFuncs *gl = filter->context->gl_vtable;
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gst_gl_filter_draw_texture (filter, texture, width, height);
}
static void
init_pixbuf_texture (GstGLContext * context, gpointer data)
{
GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (data);
GstGLFilter *filter = GST_GL_FILTER (data);
GstGLFuncs *gl = filter->context->gl_vtable;
gl->DeleteTextures (1, &differencematte->newbgtexture);
gl->GenTextures (1, &differencematte->newbgtexture);
gl->BindTexture (GL_TEXTURE_2D, differencematte->newbgtexture);
gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGBA,
(gint) differencematte->pbuf_width, (gint) differencematte->pbuf_height,
0, GL_RGBA, GL_UNSIGNED_BYTE, differencematte->pixbuf);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if (differencematte->savedbgtexture == 0) {
gl->GenTextures (1, &differencematte->savedbgtexture);
gl->BindTexture (GL_TEXTURE_2D, differencematte->savedbgtexture);
gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8,
GST_VIDEO_INFO_WIDTH (&filter->out_info),
GST_VIDEO_INFO_HEIGHT (&filter->out_info),
0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
}
static void
gst_gl_differencematte_diff (gint width, gint height, guint texture,
gpointer stuff)
{
GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (stuff);
GstGLFilter *filter = GST_GL_FILTER (stuff);
GstGLFuncs *gl = filter->context->gl_vtable;
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gst_gl_shader_use (differencematte->shader[0]);
gl->ActiveTexture (GL_TEXTURE0);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gl->Disable (GL_TEXTURE_2D);
gst_gl_shader_set_uniform_1i (differencematte->shader[0], "current", 0);
gl->ActiveTexture (GL_TEXTURE1);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, differencematte->savedbgtexture);
gl->Disable (GL_TEXTURE_2D);
gst_gl_shader_set_uniform_1i (differencematte->shader[0], "saved", 1);
gst_gl_filter_draw_texture (filter, texture, width, height);
}
static void
gst_gl_differencematte_hblur (gint width, gint height, guint texture,
gpointer stuff)
{
GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (stuff);
GstGLFilter *filter = GST_GL_FILTER (stuff);
GstGLFuncs *gl = filter->context->gl_vtable;
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gst_gl_shader_use (differencematte->shader[1]);
gl->ActiveTexture (GL_TEXTURE0);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gl->Disable (GL_TEXTURE_2D);
gst_gl_shader_set_uniform_1i (differencematte->shader[1], "tex", 0);
gst_gl_shader_set_uniform_1fv (differencematte->shader[1], "kernel", 7,
differencematte->kernel);
gst_gl_shader_set_uniform_1f (differencematte->shader[1], "width", width);
gst_gl_filter_draw_texture (filter, texture, width, height);
}
static void
gst_gl_differencematte_vblur (gint width, gint height, guint texture,
gpointer stuff)
{
GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (stuff);
GstGLFilter *filter = GST_GL_FILTER (stuff);
GstGLFuncs *gl = filter->context->gl_vtable;
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gst_gl_shader_use (differencematte->shader[2]);
gl->ActiveTexture (GL_TEXTURE0);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gl->Disable (GL_TEXTURE_2D);
gst_gl_shader_set_uniform_1i (differencematte->shader[2], "tex", 0);
gst_gl_shader_set_uniform_1fv (differencematte->shader[2], "kernel", 7,
differencematte->kernel);
gst_gl_shader_set_uniform_1f (differencematte->shader[2], "height", height);
gst_gl_filter_draw_texture (filter, texture, width, height);
}
static void
gst_gl_differencematte_interp (gint width, gint height, guint texture,
gpointer stuff)
{
GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (stuff);
GstGLFilter *filter = GST_GL_FILTER (stuff);
GstGLFuncs *gl = filter->context->gl_vtable;
gl->MatrixMode (GL_PROJECTION);
glLoadIdentity ();
gst_gl_shader_use (differencematte->shader[3]);
gl->ActiveTexture (GL_TEXTURE0);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gl->Disable (GL_TEXTURE_2D);
gst_gl_shader_set_uniform_1i (differencematte->shader[3], "blend", 0);
gl->ActiveTexture (GL_TEXTURE1);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, differencematte->newbgtexture);
gl->Disable (GL_TEXTURE_2D);
gst_gl_shader_set_uniform_1i (differencematte->shader[3], "base", 1);
gl->ActiveTexture (GL_TEXTURE2);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, differencematte->midtexture[2]);
gl->Disable (GL_TEXTURE_2D);
gst_gl_shader_set_uniform_1i (differencematte->shader[3], "alpha", 2);
gst_gl_filter_draw_texture (filter, texture, width, height);
}
static void
gst_gl_differencematte_identity (gint width, gint height, guint texture,
gpointer stuff)
{
GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (stuff);
GstGLFilter *filter = GST_GL_FILTER (differencematte);
GstGLFuncs *gl = filter->context->gl_vtable;
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gst_gl_filter_draw_texture (filter, texture, width, height);
}
static gboolean
gst_gl_differencematte_filter_texture (GstGLFilter * filter, guint in_tex,
guint out_tex)
{
GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (filter);
differencematte->intexture = in_tex;
if (differencematte->bg_has_changed && (differencematte->location != NULL)) {
if (!gst_gl_differencematte_loader (filter))
differencematte->pixbuf = NULL;
/* if loader failed then context is turned off */
gst_gl_context_thread_add (filter->context, init_pixbuf_texture,
differencematte);
/* save current frame, needed to calculate difference between
* this frame and next ones */
gst_gl_filter_render_to_target (filter, TRUE, in_tex,
differencematte->savedbgtexture,
gst_gl_differencematte_save_texture, differencematte);
if (differencematte->pixbuf) {
free (differencematte->pixbuf);
differencematte->pixbuf = NULL;
}
differencematte->bg_has_changed = FALSE;
}
if (differencematte->savedbgtexture != 0) {
gst_gl_filter_render_to_target (filter, TRUE, in_tex,
differencematte->midtexture[0], gst_gl_differencematte_diff,
differencematte);
gst_gl_filter_render_to_target (filter, FALSE,
differencematte->midtexture[0], differencematte->midtexture[1],
gst_gl_differencematte_hblur, differencematte);
gst_gl_filter_render_to_target (filter, FALSE,
differencematte->midtexture[1], differencematte->midtexture[2],
gst_gl_differencematte_vblur, differencematte);
gst_gl_filter_render_to_target (filter, TRUE, in_tex, out_tex,
gst_gl_differencematte_interp, differencematte);
} else {
gst_gl_filter_render_to_target (filter, TRUE, in_tex, out_tex,
gst_gl_differencematte_identity, differencematte);
}
return TRUE;
}
static void
user_warning_fn (png_structp png_ptr, png_const_charp warning_msg)
{
g_warning ("%s\n", warning_msg);
}
#define LOAD_ERROR(msg) { GST_WARNING ("unable to load %s: %s", differencematte->location, msg); return FALSE; }
static gboolean
gst_gl_differencematte_loader (GstGLFilter * filter)
{
GstGLDifferenceMatte *differencematte = GST_GL_DIFFERENCEMATTE (filter);
png_structp png_ptr;
png_infop info_ptr;
guint sig_read = 0;
png_uint_32 width = 0;
png_uint_32 height = 0;
gint bit_depth = 0;
gint color_type = 0;
gint interlace_type = 0;
png_FILE_p fp = NULL;
guint y = 0;
guchar **rows = NULL;
gint filler;
if (!filter->context)
return TRUE;
if ((fp = fopen (differencematte->location, "rb")) == NULL)
LOAD_ERROR ("file not found");
png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL) {
fclose (fp);
LOAD_ERROR ("failed to initialize the png_struct");
}
png_set_error_fn (png_ptr, NULL, NULL, user_warning_fn);
info_ptr = png_create_info_struct (png_ptr);
if (info_ptr == NULL) {
fclose (fp);
png_destroy_read_struct (&png_ptr, png_infopp_NULL, png_infopp_NULL);
LOAD_ERROR ("failed to initialize the memory for image information");
}
png_init_io (png_ptr, fp);
png_set_sig_bytes (png_ptr, sig_read);
png_read_info (png_ptr, info_ptr);
png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
&interlace_type, int_p_NULL, int_p_NULL);
if (color_type == PNG_COLOR_TYPE_RGB) {
filler = 0xff;
png_set_filler (png_ptr, filler, PNG_FILLER_AFTER);
color_type = PNG_COLOR_TYPE_RGB_ALPHA;
}
if (color_type != PNG_COLOR_TYPE_RGB_ALPHA) {
fclose (fp);
png_destroy_read_struct (&png_ptr, png_infopp_NULL, png_infopp_NULL);
LOAD_ERROR ("color type is not rgb");
}
differencematte->pbuf_width = width;
differencematte->pbuf_height = height;
differencematte->pixbuf =
(guchar *) malloc (sizeof (guchar) * width * height * 4);
rows = (guchar **) malloc (sizeof (guchar *) * height);
for (y = 0; y < height; ++y)
rows[y] = (guchar *) (differencematte->pixbuf + y * width * 4);
png_read_image (png_ptr, rows);
free (rows);
png_read_end (png_ptr, info_ptr);
png_destroy_read_struct (&png_ptr, &info_ptr, png_infopp_NULL);
fclose (fp);
return TRUE;
}

View file

@ -0,0 +1,59 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef _GST_GL_DIFFERENCEMATTE_H_
#define _GST_GL_DIFFERENCEMATTE_H_
#include <gst/gl/gstglfilter.h>
#define GST_TYPE_GL_DIFFERENCEMATTE (gst_gl_differencematte_get_type())
#define GST_GL_DIFFERENCEMATTE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_GL_DIFFERENCEMATTE,GstGLDifferenceMatte))
#define GST_IS_GL_DIFFERENCEMATTE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_GL_DIFFERENCEMATTE))
#define GST_GL_DIFFERENCEMATTE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) , GST_TYPE_GL_DIFFERENCEMATTE,GstGLDifferenceMatteClass))
#define GST_IS_GL_DIFFERENCEMATTE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) , GST_TYPE_GL_DIFFERENCEMATTE))
#define GST_GL_DIFFERENCEMATTE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) , GST_TYPE_GL_DIFFERENCEMATTE,GstGLDifferenceMatteClass))
typedef struct _GstGLDifferenceMatte GstGLDifferenceMatte;
typedef struct _GstGLDifferenceMatteClass GstGLDifferenceMatteClass;
struct _GstGLDifferenceMatte
{
GstGLFilter filter;
GstGLShader *shader[4];
gchar *location;
gboolean bg_has_changed;
guchar *pixbuf;
gint pbuf_width, pbuf_height;
GLuint savedbgtexture;
GLuint newbgtexture;
GLuint midtexture[4];
GLuint intexture;
float kernel[7];
};
struct _GstGLDifferenceMatteClass
{
GstGLFilterClass filter_class;
};
#endif /* _GST_GL_DIFFERENCEMATTE_H_ */

398
ext/gl/gstgleffects.c Normal file
View file

@ -0,0 +1,398 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:element-gleffects.
*
* GL Shading Language effects.
*
* <refsect2>
* <title>Examples</title>
* |[
* gst-launch videotestsrc ! glupload ! gleffects effect=5 ! glimagesink
* ]|
* FBO (Frame Buffer Object) and GLSL (OpenGL Shading Language) are required.
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gl/gstglconfig.h>
#include "gstgleffects.h"
#define GST_TYPE_GL_EFFECTS (gst_gl_effects_get_type())
#define GST_GL_EFFECTS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_GL_EFFECTS,GstGLEffects))
#define GST_IS_GL_EFFECTS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_GL_EFFECTS))
#define GST_GL_EFFECTS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) , GST_TYPE_GL_EFFECTS,GstGLEffectsClass))
#define GST_IS_GL_EFFECTS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) , GST_TYPE_GL_EFFECTS))
#define GST_GL_EFFECTS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) , GST_TYPE_GL_EFFECTS,GstGLEffectsClass))
#define GST_CAT_DEFAULT gst_gl_effects_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#define DEBUG_INIT \
GST_DEBUG_CATEGORY_INIT (gst_gl_effects_debug, "gleffects", 0, "gleffects element");
G_DEFINE_TYPE_WITH_CODE (GstGLEffects, gst_gl_effects, GST_TYPE_GL_FILTER,
DEBUG_INIT);
static void gst_gl_effects_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_gl_effects_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_gl_effects_init_resources (GstGLFilter * filter);
static void gst_gl_effects_reset_resources (GstGLFilter * filter);
static gboolean gst_gl_effects_on_init_gl_context (GstGLFilter * filter);
static void gst_gl_effects_ghash_func_clean (gpointer key, gpointer value,
gpointer data);
static gboolean gst_gl_effects_filter_texture (GstGLFilter * filter,
guint in_tex, guint out_tex);
/* dont' forget to edit the following when a new effect is added */
typedef enum
{
GST_GL_EFFECT_IDENTITY,
GST_GL_EFFECT_MIRROR,
GST_GL_EFFECT_SQUEEZE,
GST_GL_EFFECT_STRETCH,
GST_GL_EFFECT_TUNNEL,
GST_GL_EFFECT_FISHEYE,
GST_GL_EFFECT_TWIRL,
GST_GL_EFFECT_BULGE,
GST_GL_EFFECT_SQUARE,
GST_GL_EFFECT_HEAT,
GST_GL_EFFECT_SEPIA,
GST_GL_EFFECT_XPRO,
GST_GL_EFFECT_LUMA_XPRO,
GST_GL_EFFECT_XRAY,
GST_GL_EFFECT_SIN,
GST_GL_EFFECT_GLOW,
GST_GL_N_EFFECTS
} GstGLEffectsEffect;
#define GST_TYPE_GL_EFFECTS_EFFECT (gst_gl_effects_effect_get_type ())
static GType
gst_gl_effects_effect_get_type (void)
{
static GType gl_effects_effect_type = 0;
static const GEnumValue effect_types[] = {
{GST_GL_EFFECT_IDENTITY, "Do nothing Effect", "identity"},
{GST_GL_EFFECT_MIRROR, "Mirror Effect", "mirror"},
{GST_GL_EFFECT_SQUEEZE, "Squeeze Effect", "squeeze"},
#if GST_GL_HAVE_OPENGL
{GST_GL_EFFECT_STRETCH, "Stretch Effect", "stretch"},
{GST_GL_EFFECT_FISHEYE, "FishEye Effect", "fisheye"},
{GST_GL_EFFECT_TWIRL, "Twirl Effect", "twirl"},
{GST_GL_EFFECT_BULGE, "Bulge Effect", "bulge"},
{GST_GL_EFFECT_TUNNEL, "Light Tunnel Effect", "tunnel"},
{GST_GL_EFFECT_SQUARE, "Square Effect", "square"},
{GST_GL_EFFECT_HEAT, "Heat Signature Effect", "heat"},
{GST_GL_EFFECT_SEPIA, "Sepia Toning Effect", "sepia"},
{GST_GL_EFFECT_XPRO, "Cross Processing Effect", "xpro"},
{GST_GL_EFFECT_LUMA_XPRO, "Luma Cross Processing Effect", "lumaxpro"},
{GST_GL_EFFECT_XRAY, "Glowing negative effect", "xray"},
{GST_GL_EFFECT_SIN, "All Grey but Red Effect", "sin"},
{GST_GL_EFFECT_GLOW, "Glow Lighting Effect", "glow"},
#endif
{0, NULL, NULL}
};
if (!gl_effects_effect_type) {
gl_effects_effect_type =
g_enum_register_static ("GstGLEffectsEffect", effect_types);
}
return gl_effects_effect_type;
}
static void
gst_gl_effects_set_effect (GstGLEffects * effects, gint effect_type)
{
switch (effect_type) {
case GST_GL_EFFECT_IDENTITY:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_identity;
break;
case GST_GL_EFFECT_MIRROR:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_mirror;
break;
case GST_GL_EFFECT_SQUEEZE:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_squeeze;
break;
#if GST_GL_HAVE_OPENGL
case GST_GL_EFFECT_STRETCH:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_stretch;
break;
case GST_GL_EFFECT_TUNNEL:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_tunnel;
break;
case GST_GL_EFFECT_FISHEYE:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_fisheye;
break;
case GST_GL_EFFECT_TWIRL:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_twirl;
break;
case GST_GL_EFFECT_BULGE:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_bulge;
break;
case GST_GL_EFFECT_SQUARE:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_square;
break;
case GST_GL_EFFECT_HEAT:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_heat;
break;
case GST_GL_EFFECT_SEPIA:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_sepia;
break;
case GST_GL_EFFECT_XPRO:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_xpro;
break;
case GST_GL_EFFECT_LUMA_XPRO:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_luma_xpro;
break;
case GST_GL_EFFECT_XRAY:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_xray;
break;
case GST_GL_EFFECT_SIN:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_sin;
break;
case GST_GL_EFFECT_GLOW:
effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_glow;
break;
#endif
default:
g_assert_not_reached ();
}
effects->current_effect = effect_type;
}
/* init resources that need a gl context */
static void
gst_gl_effects_init_gl_resources (GstGLFilter * filter)
{
GstGLEffects *effects = GST_GL_EFFECTS (filter);
gint i;
for (i = 0; i < NEEDED_TEXTURES; i++) {
glGenTextures (1, &effects->midtexture[i]);
glBindTexture (GL_TEXTURE_2D, effects->midtexture[i]);
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8,
GST_VIDEO_INFO_WIDTH (&filter->out_info),
GST_VIDEO_INFO_HEIGHT (&filter->out_info),
0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
}
/* free resources that need a gl context */
static void
gst_gl_effects_reset_gl_resources (GstGLFilter * filter)
{
GstGLEffects *effects = GST_GL_EFFECTS (filter);
gint i;
for (i = 0; i < NEEDED_TEXTURES; i++) {
glDeleteTextures (1, &effects->midtexture[i]);
effects->midtexture[i] = 0;
}
for (i = 0; i < GST_GL_EFFECTS_N_CURVES; i++) {
glDeleteTextures (1, &effects->curve[i]);
effects->curve[i] = 0;
}
}
static void
gst_gl_effects_class_init (GstGLEffectsClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *element_class;
gobject_class = (GObjectClass *) klass;
element_class = GST_ELEMENT_CLASS (klass);
gobject_class->set_property = gst_gl_effects_set_property;
gobject_class->get_property = gst_gl_effects_get_property;
GST_GL_FILTER_CLASS (klass)->filter_texture = gst_gl_effects_filter_texture;
GST_GL_FILTER_CLASS (klass)->display_init_cb =
gst_gl_effects_init_gl_resources;
GST_GL_FILTER_CLASS (klass)->display_reset_cb =
gst_gl_effects_reset_gl_resources;
GST_GL_FILTER_CLASS (klass)->onStart = gst_gl_effects_init_resources;
GST_GL_FILTER_CLASS (klass)->onStop = gst_gl_effects_reset_resources;
GST_GL_FILTER_CLASS (klass)->onInitFBO = gst_gl_effects_on_init_gl_context;
g_object_class_install_property (gobject_class,
PROP_EFFECT,
g_param_spec_enum ("effect",
"Effect",
"Select which effect apply to GL video texture",
GST_TYPE_GL_EFFECTS_EFFECT,
GST_GL_EFFECT_IDENTITY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_HSWAP,
g_param_spec_boolean ("hswap",
"Horizontal Swap",
"Switch video texture left to right, useful with webcams",
FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_element_class_set_metadata (element_class,
"Gstreamer OpenGL Effects", "Filter/Effect/Video",
"GL Shading Language effects",
"Filippo Argiolas <filippo.argiolas@gmail.com>");
}
static void
set_horizontal_swap (GstGLContext * context, gpointer data)
{
#if GST_GL_HAVE_OPENGL
GstGLFuncs *gl = context->gl_vtable;
if (gst_gl_context_get_gl_api (context) & GST_GL_API_OPENGL) {
const gfloat mirrormatrix[16] = {
-1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0
};
gl->MatrixMode (GL_MODELVIEW);
gl->LoadMatrixf (mirrormatrix);
}
#endif
}
static void
gst_gl_effects_init (GstGLEffects * effects)
{
effects->effect = gst_gl_effects_identity;
effects->horizontal_swap = FALSE;
}
static void
gst_gl_effects_ghash_func_clean (gpointer key, gpointer value, gpointer data)
{
GstGLShader *shader = (GstGLShader *) value;
GstGLFilter *filter = (GstGLFilter *) data;
//blocking call, wait the opengl thread has destroyed the shader
gst_gl_context_del_shader (filter->context, shader);
value = NULL;
}
static void
gst_gl_effects_reset_resources (GstGLFilter * filter)
{
GstGLEffects *effects = GST_GL_EFFECTS (filter);
/* release shaders in the gl thread */
g_hash_table_foreach (effects->shaderstable, gst_gl_effects_ghash_func_clean,
filter);
/* clean the htable without calling values destructors
* because shaders have been released in the glthread
* through the foreach func */
g_hash_table_unref (effects->shaderstable);
effects->shaderstable = NULL;
}
static void
gst_gl_effects_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstGLEffects *effects = GST_GL_EFFECTS (object);
switch (prop_id) {
case PROP_EFFECT:
gst_gl_effects_set_effect (effects, g_value_get_enum (value));
break;
case PROP_HSWAP:
effects->horizontal_swap = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_effects_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstGLEffects *effects = GST_GL_EFFECTS (object);
switch (prop_id) {
case PROP_EFFECT:
g_value_set_enum (value, effects->current_effect);
break;
case PROP_HSWAP:
g_value_set_boolean (value, effects->horizontal_swap);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_effects_init_resources (GstGLFilter * filter)
{
GstGLEffects *effects = GST_GL_EFFECTS (filter);
gint i;
effects->shaderstable = g_hash_table_new (g_str_hash, g_str_equal);
for (i = 0; i < NEEDED_TEXTURES; i++) {
effects->midtexture[i] = 0;
}
for (i = 0; i < GST_GL_EFFECTS_N_CURVES; i++) {
effects->curve[i] = 0;
}
}
static gboolean
gst_gl_effects_on_init_gl_context (GstGLFilter * filter)
{
return TRUE;
}
static gboolean
gst_gl_effects_filter_texture (GstGLFilter * filter, guint in_tex,
guint out_tex)
{
GstGLEffects *effects = GST_GL_EFFECTS (filter);
effects->intexture = in_tex;
effects->outtexture = out_tex;
if (effects->horizontal_swap == TRUE)
gst_gl_context_thread_add (filter->context, set_horizontal_swap, effects);
effects->effect (effects);
return TRUE;
}

105
ext/gl/gstgleffects.h Normal file
View file

@ -0,0 +1,105 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_GL_EFFECTS_H__
#define __GST_GL_EFFECTS_H__
#include <gst/gl/gstglfilter.h>
#include "effects/gstgleffectssources.h"
G_BEGIN_DECLS
#define GST_TYPE_GL_EFFECTS (gst_gl_effects_get_type())
#define GST_GL_EFFECTS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_GL_EFFECTS,GstGLEffects))
#define GST_IS_GL_EFFECTS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_GL_EFFECTS))
#define GST_GL_EFFECTS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) , GST_TYPE_GL_EFFECTS,GstGLEffectsClass))
#define GST_IS_GL_EFFECTS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) , GST_TYPE_GL_EFFECTS))
#define GST_GL_EFFECTS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) , GST_TYPE_GL_EFFECTS,GstGLEffectsClass))
typedef struct _GstGLEffects GstGLEffects;
typedef struct _GstGLEffectsClass GstGLEffectsClass;
typedef void (* GstGLEffectProcessFunc) (GstGLEffects *effects);
#define NEEDED_TEXTURES 5
enum {
GST_GL_EFFECTS_CURVE_HEAT,
GST_GL_EFFECTS_CURVE_SEPIA,
GST_GL_EFFECTS_CURVE_XPRO,
GST_GL_EFFECTS_CURVE_LUMA_XPRO,
GST_GL_EFFECTS_CURVE_XRAY,
GST_GL_EFFECTS_N_CURVES
};
struct _GstGLEffects
{
GstGLFilter filter;
GstGLEffectProcessFunc effect;
gint current_effect;
GLuint intexture;
GLuint midtexture[NEEDED_TEXTURES];
GLuint outtexture;
GLuint curve[GST_GL_EFFECTS_N_CURVES];
GHashTable *shaderstable;
gboolean horizontal_swap; /* switch left to right */
};
struct _GstGLEffectsClass
{
GstGLFilterClass filter_class;
};
enum
{
PROP_0,
PROP_EFFECT,
PROP_HSWAP
};
GType gst_gl_effects_get_type (void);
void gst_gl_effects_identity (GstGLEffects *effects);
void gst_gl_effects_mirror (GstGLEffects *effects);
void gst_gl_effects_squeeze (GstGLEffects *effects);
void gst_gl_effects_stretch (GstGLEffects *effects);
void gst_gl_effects_tunnel (GstGLEffects *effects);
void gst_gl_effects_fisheye (GstGLEffects *effects);
void gst_gl_effects_twirl (GstGLEffects *effects);
void gst_gl_effects_bulge (GstGLEffects *effects);
void gst_gl_effects_square (GstGLEffects *effects);
void gst_gl_effects_heat (GstGLEffects *effects);
void gst_gl_effects_sepia (GstGLEffects *effects);
void gst_gl_effects_xpro (GstGLEffects *effects);
void gst_gl_effects_xray (GstGLEffects *effects);
void gst_gl_effects_luma_xpro (GstGLEffects *effects);
void gst_gl_effects_sin (GstGLEffects *effects);
void gst_gl_effects_glow (GstGLEffects *effects);
G_END_DECLS
#endif /*__GST_GL_EFFECTS_H__ */

214
ext/gl/gstglfilterapp.c Normal file
View file

@ -0,0 +1,214 @@
/*
* GStreamer
* Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:element-glfilterapp
*
* The resize and redraw callbacks can be set from a client code.
*
* <refsect2>
* <title>CLient callbacks</title>
* <para>
* The graphic scene can be written from a client code through the
* two glfilterapp properties.
* </para>
* </refsect2>
* <refsect2>
* <title>Examples</title>
* see gst-plugins-gl/tests/examples/generic/recordgraphic
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstglfilterapp.h"
#define GST_CAT_DEFAULT gst_gl_filter_app_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
enum
{
PROP_0,
PROP_CLIENT_RESHAPE_CALLBACK,
PROP_CLIENT_DRAW_CALLBACK,
PROP_CLIENT_DATA
};
#define DEBUG_INIT \
GST_DEBUG_CATEGORY_INIT (gst_gl_filter_app_debug, "glfilterapp", 0, "glfilterapp element");
G_DEFINE_TYPE_WITH_CODE (GstGLFilterApp, gst_gl_filter_app,
GST_TYPE_GL_FILTER, DEBUG_INIT);
static void gst_gl_filter_app_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_gl_filter_app_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static gboolean gst_gl_filter_app_set_caps (GstGLFilter * filter,
GstCaps * incaps, GstCaps * outcaps);
static gboolean gst_gl_filter_app_filter_texture (GstGLFilter * filter,
guint in_tex, guint out_tex);
static void gst_gl_filter_app_callback (gint width, gint height, guint texture,
gpointer stuff);
static void
gst_gl_filter_app_class_init (GstGLFilterAppClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *element_class;
gobject_class = (GObjectClass *) klass;
element_class = GST_ELEMENT_CLASS (klass);
gobject_class->set_property = gst_gl_filter_app_set_property;
gobject_class->get_property = gst_gl_filter_app_get_property;
GST_GL_FILTER_CLASS (klass)->set_caps = gst_gl_filter_app_set_caps;
GST_GL_FILTER_CLASS (klass)->filter_texture =
gst_gl_filter_app_filter_texture;
g_object_class_install_property (gobject_class, PROP_CLIENT_RESHAPE_CALLBACK,
g_param_spec_pointer ("client-reshape-callback",
"Client reshape callback",
"Define a custom reshape callback in a client code",
G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_CLIENT_DRAW_CALLBACK,
g_param_spec_pointer ("client-draw-callback", "Client draw callback",
"Define a custom draw callback in a client code",
G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_CLIENT_DATA,
g_param_spec_pointer ("client-data", "Client data",
"Pass data to the draw and reshape callbacks",
G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
gst_element_class_set_metadata (element_class,
"OpenGL application filter", "Filter/Effect",
"Use client callbacks to define the scene",
"Julien Isorce <julien.isorce@gmail.com>");
}
static void
gst_gl_filter_app_init (GstGLFilterApp * filter)
{
filter->clientReshapeCallback = NULL;
filter->clientDrawCallback = NULL;
filter->client_data = NULL;
}
static void
gst_gl_filter_app_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstGLFilterApp *filter = GST_GL_FILTER_APP (object);
switch (prop_id) {
case PROP_CLIENT_RESHAPE_CALLBACK:
{
filter->clientReshapeCallback = g_value_get_pointer (value);
break;
}
case PROP_CLIENT_DRAW_CALLBACK:
{
filter->clientDrawCallback = g_value_get_pointer (value);
break;
}
case PROP_CLIENT_DATA:
{
filter->client_data = g_value_get_pointer (value);
break;
}
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_filter_app_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
//GstGLFilterApp* filter = GST_GL_FILTER_APP (object);
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
gst_gl_filter_app_set_caps (GstGLFilter * filter, GstCaps * incaps,
GstCaps * outcaps)
{
//GstGLFilterApp* app_filter = GST_GL_FILTER_APP(filter);
return TRUE;
}
static gboolean
gst_gl_filter_app_filter_texture (GstGLFilter * filter, guint in_tex,
guint out_tex)
{
GstGLFilterApp *app_filter = GST_GL_FILTER_APP (filter);
if (app_filter->clientDrawCallback) {
//blocking call, use a FBO
gst_gl_context_use_fbo (filter->context,
GST_VIDEO_INFO_WIDTH (&filter->out_info),
GST_VIDEO_INFO_HEIGHT (&filter->out_info),
filter->fbo, filter->depthbuffer, out_tex,
app_filter->clientDrawCallback,
GST_VIDEO_INFO_WIDTH (&filter->in_info),
GST_VIDEO_INFO_HEIGHT (&filter->in_info),
in_tex, 45,
(gfloat) GST_VIDEO_INFO_WIDTH (&filter->out_info) /
(gfloat) GST_VIDEO_INFO_HEIGHT (&filter->out_info),
0.1, 100, GST_GL_DISPLAY_PROJECTION_PERSPECTIVE,
app_filter->client_data);
}
//default
else {
//blocking call, use a FBO
gst_gl_filter_render_to_target (filter, TRUE, in_tex, out_tex,
gst_gl_filter_app_callback, filter);
}
return TRUE;
}
//opengl scene, params: input texture (not the output filter->texture)
static void
gst_gl_filter_app_callback (gint width, gint height, guint texture,
gpointer stuff)
{
GstGLFilter *filter = GST_GL_FILTER (stuff);
GstGLFuncs *gl = filter->context->gl_vtable;
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gst_gl_filter_draw_texture (filter, texture, width, height);
}

55
ext/gl/gstglfilterapp.h Normal file
View file

@ -0,0 +1,55 @@
/*
* GStreamer
* Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef _GST_GL_FILTERAPP_H_
#define _GST_GL_FILTERAPP_H_
#include <gst/gl/gstglfilter.h>
G_BEGIN_DECLS
#define GST_TYPE_GL_FILTER_APP (gst_gl_filter_app_get_type())
#define GST_GL_FILTER_APP(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_FILTER_APP,GstGLFilterApp))
#define GST_IS_GL_FILTER_APP(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_FILTER_APP))
#define GST_GL_FILTER_APP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_FILTER_APP,GstGLFilterAppClass))
#define GST_IS_GL_FILTER_APP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_FILTER_APP))
#define GST_GL_FILTER_APP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_FILTER_APP,GstGLFilterAppClass))
typedef struct _GstGLFilterApp GstGLFilterApp;
typedef struct _GstGLFilterAppClass GstGLFilterAppClass;
struct _GstGLFilterApp
{
GstGLFilter filter;
CRCB clientReshapeCallback;
GLCB clientDrawCallback;
gpointer client_data;
};
struct _GstGLFilterAppClass
{
GstGLFilterClass filter_class;
};
GType gst_gl_glfilterapp_get_type (void);
G_END_DECLS
#endif /* _GST_GLFILTERAPP_H_ */

257
ext/gl/gstglfilterblur.c Normal file
View file

@ -0,0 +1,257 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:element-glfilterblur
*
* Blur with 9x9 separable convolution.
*
* <refsect2>
* <title>Examples</title>
* |[
* gst-launch videotestsrc ! glupload ! glfilterblur ! glimagesink
* ]|
* FBO (Frame Buffer Object) and GLSL (OpenGL Shading Language) are required.
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstglfilterblur.h"
#include "effects/gstgleffectssources.h"
#define GST_CAT_DEFAULT gst_gl_filterblur_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#define DEBUG_INIT \
GST_DEBUG_CATEGORY_INIT (gst_gl_filterblur_debug, "glfilterblur", 0, "glfilterblur element");
G_DEFINE_TYPE_WITH_CODE (GstGLFilterBlur, gst_gl_filterblur,
GST_TYPE_GL_FILTER, DEBUG_INIT);
static void gst_gl_filterblur_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_gl_filterblur_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_gl_filter_filterblur_reset (GstGLFilter * filter);
static gboolean gst_gl_filterblur_init_shader (GstGLFilter * filter);
static gboolean gst_gl_filterblur_filter_texture (GstGLFilter * filter,
guint in_tex, guint out_tex);
static void gst_gl_filterblur_hcallback (gint width, gint height, guint texture,
gpointer stuff);
static void gst_gl_filterblur_vcallback (gint width, gint height, guint texture,
gpointer stuff);
static void
gst_gl_filterblur_init_resources (GstGLFilter * filter)
{
GstGLFilterBlur *filterblur = GST_GL_FILTERBLUR (filter);
GstGLFuncs *gl = filter->context->gl_vtable;
gl->GenTextures (1, &filterblur->midtexture);
gl->BindTexture (GL_TEXTURE_2D, filterblur->midtexture);
gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8,
GST_VIDEO_INFO_WIDTH (&filter->out_info),
GST_VIDEO_INFO_HEIGHT (&filter->out_info),
0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
static void
gst_gl_filterblur_reset_resources (GstGLFilter * filter)
{
GstGLFilterBlur *filterblur = GST_GL_FILTERBLUR (filter);
GstGLFuncs *gl = filter->context->gl_vtable;
gl->DeleteTextures (1, &filterblur->midtexture);
}
static void
gst_gl_filterblur_class_init (GstGLFilterBlurClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *element_class;
gobject_class = (GObjectClass *) klass;
element_class = GST_ELEMENT_CLASS (klass);
gobject_class->set_property = gst_gl_filterblur_set_property;
gobject_class->get_property = gst_gl_filterblur_get_property;
gst_element_class_set_metadata (element_class, "Gstreamer OpenGL Blur",
"Filter/Effect/Video", "Blur with 9x9 separable convolution",
"Filippo Argiolas <filippo.argiolas@gmail.com>");
GST_GL_FILTER_CLASS (klass)->filter_texture =
gst_gl_filterblur_filter_texture;
GST_GL_FILTER_CLASS (klass)->display_init_cb =
gst_gl_filterblur_init_resources;
GST_GL_FILTER_CLASS (klass)->display_reset_cb =
gst_gl_filterblur_reset_resources;
GST_GL_FILTER_CLASS (klass)->onInitFBO = gst_gl_filterblur_init_shader;
GST_GL_FILTER_CLASS (klass)->onReset = gst_gl_filter_filterblur_reset;
}
static void
gst_gl_filterblur_init (GstGLFilterBlur * filterblur)
{
filterblur->shader0 = NULL;
filterblur->shader1 = NULL;
filterblur->midtexture = 0;
/* gaussian kernel (well, actually vector), size 9, standard
* deviation 3.0 */
/* FIXME: eventually make this a runtime property */
fill_gaussian_kernel (filterblur->gauss_kernel, 7, 3.0);
}
static void
gst_gl_filter_filterblur_reset (GstGLFilter * filter)
{
GstGLFilterBlur *filterblur = GST_GL_FILTERBLUR (filter);
//blocking call, wait the opengl thread has destroyed the shader
if (filterblur->shader0)
gst_gl_context_del_shader (filter->context, filterblur->shader0);
filterblur->shader0 = NULL;
//blocking call, wait the opengl thread has destroyed the shader
if (filterblur->shader1)
gst_gl_context_del_shader (filter->context, filterblur->shader1);
filterblur->shader1 = NULL;
}
static void
gst_gl_filterblur_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
/* GstGLFilterBlur *filterblur = GST_GL_FILTERBLUR (object); */
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_filterblur_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
/* GstGLFilterBlur *filterblur = GST_GL_FILTERBLUR (object); */
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
gst_gl_filterblur_init_shader (GstGLFilter * filter)
{
GstGLFilterBlur *blur_filter = GST_GL_FILTERBLUR (filter);
//blocking call, wait the opengl thread has compiled the shader
if (!gst_gl_context_gen_shader (filter->context, 0, hconv7_fragment_source,
&blur_filter->shader0))
return FALSE;
//blocking call, wait the opengl thread has compiled the shader
if (!gst_gl_context_gen_shader (filter->context, 0, vconv7_fragment_source,
&blur_filter->shader1))
return FALSE;
return TRUE;
}
static gboolean
gst_gl_filterblur_filter_texture (GstGLFilter * filter, guint in_tex,
guint out_tex)
{
GstGLFilterBlur *filterblur = GST_GL_FILTERBLUR (filter);
gst_gl_filter_render_to_target (filter, TRUE, in_tex,
filterblur->midtexture, gst_gl_filterblur_hcallback, filterblur);
gst_gl_filter_render_to_target (filter, FALSE, filterblur->midtexture,
out_tex, gst_gl_filterblur_vcallback, filterblur);
return TRUE;
}
static void
gst_gl_filterblur_hcallback (gint width, gint height, guint texture,
gpointer stuff)
{
GstGLFilter *filter = GST_GL_FILTER (stuff);
GstGLFilterBlur *filterblur = GST_GL_FILTERBLUR (filter);
GstGLFuncs *gl = filter->context->gl_vtable;
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gst_gl_shader_use (filterblur->shader0);
gl->ActiveTexture (GL_TEXTURE1);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gl->Disable (GL_TEXTURE_2D);
gst_gl_shader_set_uniform_1i (filterblur->shader0, "tex", 1);
gst_gl_shader_set_uniform_1fv (filterblur->shader0, "kernel", 7,
filterblur->gauss_kernel);
gst_gl_shader_set_uniform_1f (filterblur->shader0, "width", width);
gst_gl_filter_draw_texture (filter, texture, width, height);
}
static void
gst_gl_filterblur_vcallback (gint width, gint height, guint texture,
gpointer stuff)
{
GstGLFilter *filter = GST_GL_FILTER (stuff);
GstGLFilterBlur *filterblur = GST_GL_FILTERBLUR (filter);
GstGLFuncs *gl = filter->context->gl_vtable;
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gst_gl_shader_use (filterblur->shader1);
gl->ActiveTexture (GL_TEXTURE1);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gl->Disable (GL_TEXTURE_2D);
gst_gl_shader_set_uniform_1i (filterblur->shader1, "tex", 1);
gst_gl_shader_set_uniform_1fv (filterblur->shader1, "kernel", 7,
filterblur->gauss_kernel);
gst_gl_shader_set_uniform_1f (filterblur->shader1, "height", height);
gst_gl_filter_draw_texture (filter, texture, width, height);
}

53
ext/gl/gstglfilterblur.h Normal file
View file

@ -0,0 +1,53 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef _GST_GL_FILTERBLUR_H_
#define _GST_GL_FILTERBLUR_H_
#include <gst/gl/gstglfilter.h>
#define GST_TYPE_GL_FILTERBLUR (gst_gl_filterblur_get_type())
#define GST_GL_FILTERBLUR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_FILTERBLUR,GstGLFilterBlur))
#define GST_IS_GL_FILTERBLUR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_FILTERBLUR))
#define GST_GL_FILTERBLUR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_FILTERBLUR,GstGLFilterBlurClass))
#define GST_IS_GL_FILTERBLUR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_FILTERBLUR))
#define GST_GL_FILTERBLUR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_FILTERBLUR,GstGLFilterBlurClass))
typedef struct _GstGLFilterBlur GstGLFilterBlur;
typedef struct _GstGLFilterBlurClass GstGLFilterBlurClass;
struct _GstGLFilterBlur
{
GstGLFilter filter;
GstGLShader *shader0;
GstGLShader *shader1;
GLuint midtexture;
float gauss_kernel[7];
};
struct _GstGLFilterBlurClass
{
GstGLFilterClass filter_class;
};
GType gst_gl_glfilterblur_get_type (void);
#endif /* _GST_GL_FILTERBLUR_H_ */

561
ext/gl/gstglfiltercube.c Normal file
View file

@ -0,0 +1,561 @@
/*
* GStreamer
* Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:element-glfiltercube
*
* The resize and redraw callbacks can be set from a client code.
*
* <refsect2>
* <title>Examples</title>
* |[
* gst-launch -v videotestsrc ! glupload ! glfiltercube ! glimagesink
* ]| A pipeline to mpa textures on the 6 cube faces..
* FBO is required.
* |[
* gst-launch -v videotestsrc ! glupload ! glfiltercube ! video/x-raw-gl, width=640, height=480 ! glimagesink
* ]| Resize scene after drawing the cube.
* The scene size is greater than the input video size.
|[
* gst-launch -v videotestsrc ! glupload ! video/x-raw-gl, width=640, height=480 ! glfiltercube ! glimagesink
* ]| Resize scene before drawing the cube.
* The scene size is greater than the input video size.
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gl/gstglapi.h>
#include "gstglfiltercube.h"
#define GST_CAT_DEFAULT gst_gl_filter_cube_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
enum
{
PROP_0,
PROP_RED,
PROP_GREEN,
PROP_BLUE,
PROP_FOVY,
PROP_ASPECT,
PROP_ZNEAR,
PROP_ZFAR
};
#define DEBUG_INIT \
GST_DEBUG_CATEGORY_INIT (gst_gl_filter_cube_debug, "glfiltercube", 0, "glfiltercube element");
G_DEFINE_TYPE_WITH_CODE (GstGLFilterCube, gst_gl_filter_cube,
GST_TYPE_GL_FILTER, DEBUG_INIT);
static void gst_gl_filter_cube_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_gl_filter_cube_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static gboolean gst_gl_filter_cube_set_caps (GstGLFilter * filter,
GstCaps * incaps, GstCaps * outcaps);
#if GST_GL_HAVE_GLES2
static void gst_gl_filter_cube_reset (GstGLFilter * filter);
static gboolean gst_gl_filter_cube_init_shader (GstGLFilter * filter);
static void _callback_gles2 (gint width, gint height, guint texture,
gpointer stuff);
#endif
#if GST_GL_HAVE_OPENGL
static void _callback_opengl (gint width, gint height, guint texture,
gpointer stuff);
#endif
static gboolean gst_gl_filter_cube_filter_texture (GstGLFilter * filter,
guint in_tex, guint out_tex);
#if GST_GL_HAVE_GLES2
/* vertex source */
static const gchar *cube_v_src =
"attribute vec4 a_position; \n"
"attribute vec2 a_texCoord; \n"
"uniform mat4 u_matrix; \n"
"uniform float xrot_degree, yrot_degree, zrot_degree; \n"
"varying vec2 v_texCoord; \n"
"void main() \n"
"{ \n"
" float PI = 3.14159265; \n"
" float xrot = xrot_degree*2.0*PI/360.0; \n"
" float yrot = yrot_degree*2.0*PI/360.0; \n"
" float zrot = zrot_degree*2.0*PI/360.0; \n"
" mat4 matX = mat4 ( \n"
" 1.0, 0.0, 0.0, 0.0, \n"
" 0.0, cos(xrot), sin(xrot), 0.0, \n"
" 0.0, -sin(xrot), cos(xrot), 0.0, \n"
" 0.0, 0.0, 0.0, 1.0 ); \n"
" mat4 matY = mat4 ( \n"
" cos(yrot), 0.0, -sin(yrot), 0.0, \n"
" 0.0, 1.0, 0.0, 0.0, \n"
" sin(yrot), 0.0, cos(yrot), 0.0, \n"
" 0.0, 0.0, 0.0, 1.0 ); \n"
" mat4 matZ = mat4 ( \n"
" cos(zrot), sin(zrot), 0.0, 0.0, \n"
" -sin(zrot), cos(zrot), 0.0, 0.0, \n"
" 0.0, 0.0, 1.0, 0.0, \n"
" 0.0, 0.0, 0.0, 1.0 ); \n"
" gl_Position = u_matrix * matZ * matY * matX * a_position; \n"
" v_texCoord = a_texCoord; \n"
"} \n";
/* fragment source */
static const gchar *cube_f_src =
"precision mediump float; \n"
"varying vec2 v_texCoord; \n"
"uniform sampler2D s_texture; \n"
"void main() \n"
"{ \n"
" gl_FragColor = texture2D( s_texture, v_texCoord );\n"
"} \n";
#endif
static void
gst_gl_filter_cube_class_init (GstGLFilterCubeClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *element_class;
gobject_class = (GObjectClass *) klass;
element_class = GST_ELEMENT_CLASS (klass);
gobject_class->set_property = gst_gl_filter_cube_set_property;
gobject_class->get_property = gst_gl_filter_cube_get_property;
#if GST_GL_HAVE_GLES2
GST_GL_FILTER_CLASS (klass)->onInitFBO = gst_gl_filter_cube_init_shader;
GST_GL_FILTER_CLASS (klass)->onReset = gst_gl_filter_cube_reset;
#endif
GST_GL_FILTER_CLASS (klass)->set_caps = gst_gl_filter_cube_set_caps;
GST_GL_FILTER_CLASS (klass)->filter_texture =
gst_gl_filter_cube_filter_texture;
g_object_class_install_property (gobject_class, PROP_RED,
g_param_spec_float ("red", "Red", "Background red color",
0.0f, 1.0f, 0.0f, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_GREEN,
g_param_spec_float ("green", "Green", "Background reen color",
0.0f, 1.0f, 0.0f, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_BLUE,
g_param_spec_float ("blue", "Blue", "Background blue color",
0.0f, 1.0f, 0.0f, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_FOVY,
g_param_spec_double ("fovy", "Fovy", "Field of view angle in degrees",
0.0, 180.0, 45.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_ASPECT,
g_param_spec_double ("aspect", "Aspect",
"Field of view in the x direction", 0.0, 100, 0.0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_ZNEAR,
g_param_spec_double ("znear", "Znear",
"Specifies the distance from the viewer to the near clipping plane",
0.0, 100.0, 0.1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_ZFAR,
g_param_spec_double ("zfar", "Zfar",
"Specifies the distance from the viewer to the far clipping plane",
0.0, 1000.0, 100.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_element_class_set_metadata (element_class, "OpenGL cube filter",
"Filter/Effect/Video", "Map input texture on the 6 cube faces",
"Julien Isorce <julien.isorce@gmail.com>");
}
static void
gst_gl_filter_cube_init (GstGLFilterCube * filter)
{
filter->shader = NULL;
filter->fovy = 45;
filter->aspect = 0;
filter->znear = 0.1;
filter->zfar = 100;
}
static void
gst_gl_filter_cube_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstGLFilterCube *filter = GST_GL_FILTER_CUBE (object);
switch (prop_id) {
case PROP_RED:
filter->red = g_value_get_float (value);
break;
case PROP_GREEN:
filter->green = g_value_get_float (value);
break;
case PROP_BLUE:
filter->blue = g_value_get_float (value);
break;
case PROP_FOVY:
filter->fovy = g_value_get_double (value);
break;
case PROP_ASPECT:
filter->aspect = g_value_get_double (value);
break;
case PROP_ZNEAR:
filter->znear = g_value_get_double (value);
break;
case PROP_ZFAR:
filter->zfar = g_value_get_double (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_filter_cube_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstGLFilterCube *filter = GST_GL_FILTER_CUBE (object);
switch (prop_id) {
case PROP_RED:
g_value_set_float (value, filter->red);
break;
case PROP_GREEN:
g_value_set_float (value, filter->green);
break;
case PROP_BLUE:
g_value_set_float (value, filter->blue);
break;
case PROP_FOVY:
g_value_set_double (value, filter->fovy);
break;
case PROP_ASPECT:
g_value_set_double (value, filter->aspect);
break;
case PROP_ZNEAR:
g_value_set_double (value, filter->znear);
break;
case PROP_ZFAR:
g_value_set_double (value, filter->zfar);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
gst_gl_filter_cube_set_caps (GstGLFilter * filter, GstCaps * incaps,
GstCaps * outcaps)
{
GstGLFilterCube *cube_filter = GST_GL_FILTER_CUBE (filter);
if (cube_filter->aspect == 0)
cube_filter->aspect = (gdouble) GST_VIDEO_INFO_WIDTH (&filter->out_info) /
(gdouble) GST_VIDEO_INFO_HEIGHT (&filter->out_info);
return TRUE;
}
#if GST_GL_HAVE_GLES2
static void
gst_gl_filter_cube_reset (GstGLFilter * filter)
{
GstGLFilterCube *cube_filter = GST_GL_FILTER_CUBE (filter);
/* blocking call, wait the opengl thread has destroyed the shader */
if (cube_filter->shader)
gst_gl_context_del_shader (filter->context, cube_filter->shader);
cube_filter->shader = NULL;
}
static gboolean
gst_gl_filter_cube_init_shader (GstGLFilter * filter)
{
GstGLFilterCube *cube_filter = GST_GL_FILTER_CUBE (filter);
if (gst_gl_context_get_gl_api (filter->context) & GST_GL_API_GLES2) {
/* blocking call, wait the opengl thread has compiled the shader */
return gst_gl_context_gen_shader (filter->context, cube_v_src, cube_f_src,
&cube_filter->shader);
}
return TRUE;
}
#endif
static gboolean
gst_gl_filter_cube_filter_texture (GstGLFilter * filter, guint in_tex,
guint out_tex)
{
GstGLFilterCube *cube_filter = GST_GL_FILTER_CUBE (filter);
GLCB cb = NULL;
GstGLAPI api;
api = gst_gl_context_get_gl_api (GST_GL_FILTER (cube_filter)->context);
#if GST_GL_HAVE_OPENGL
if (api & GST_GL_API_OPENGL)
cb = _callback_opengl;
#endif
#if GST_GL_HAVE_GLES2
if (api & GST_GL_API_GLES2)
cb = _callback_gles2;
#endif
/* blocking call, use a FBO */
gst_gl_context_use_fbo (filter->context,
GST_VIDEO_INFO_WIDTH (&filter->out_info),
GST_VIDEO_INFO_HEIGHT (&filter->out_info),
filter->fbo, filter->depthbuffer, out_tex,
cb,
GST_VIDEO_INFO_WIDTH (&filter->in_info),
GST_VIDEO_INFO_HEIGHT (&filter->in_info),
in_tex, cube_filter->fovy, cube_filter->aspect,
cube_filter->znear, cube_filter->zfar,
GST_GL_DISPLAY_PROJECTION_PERSPECTIVE, (gpointer) cube_filter);
return TRUE;
}
/* opengl scene, params: input texture (not the output filter->texture) */
#if GST_GL_HAVE_OPENGL
static void
_callback_opengl (gint width, gint height, guint texture, gpointer stuff)
{
GstGLFilterCube *cube_filter = GST_GL_FILTER_CUBE (stuff);
GstGLFilter *filter = GST_GL_FILTER (stuff);
GstGLFuncs *gl = filter->context->gl_vtable;
static GLfloat xrot = 0;
static GLfloat yrot = 0;
static GLfloat zrot = 0;
/* *INDENT-OFF* */
const GLfloat v_vertices[] = {
/*| Vertex | TexCoord |*/
/* front face */
1.0, 1.0, -1.0, 0.0, 0.0,
1.0, -1.0, -1.0, 1.0, 0.0,
-1.0, -1.0, -1.0, 1.0, 1.0,
-1.0, 1.0, -1.0, 0.0, 1.0,
/* back face */
-1.0, 1.0, 1.0, 0.0, 0.0,
-1.0, -1.0, 1.0, 1.0, 0.0,
1.0, -1.0, 1.0, 1.0, 1.0,
1.0, 1.0, 1.0, 0.0, 1.0,
/* right face */
-1.0, 1.0, -1.0, 0.0, 0.0,
-1.0, -1.0, -1.0, 1.0, 0.0,
-1.0, -1.0, 1.0, 1.0, 1.0,
-1.0, 1.0, 1.0, 0.0, 1.0,
/* left face */
1.0, 1.0, 1.0, 0.0, 0.0,
1.0, -1.0, 1.0, 1.0, 0.0,
1.0, -1.0, -1.0, 1.0, 1.0,
1.0, 1.0, -1.0, 0.0, 1.0,
/* top face */
1.0, 1.0, 1.0, 0.0, 0.0,
1.0, 1.0, -1.0, 1.0, 0.0,
-1.0, 1.0, -1.0, 1.0, 1.0,
-1.0, 1.0, 1.0, 0.0, 1.0,
/* bottom face */
1.0, -1.0, 1.0, 0.0, 0.0,
1.0, -1.0, -1.0, 1.0, 0.0,
-1.0, -1.0, -1.0, 1.0, 1.0,
-1.0, -1.0, 1.0, 0.0, 1.0,
};
/* *INDENT-ON* */
GLushort indices[] = {
0, 1, 2,
0, 2, 3,
4, 5, 6,
4, 6, 7,
8, 9, 10,
8, 10, 11,
12, 13, 14,
12, 14, 15,
16, 17, 18,
16, 18, 19,
20, 21, 22,
20, 22, 23
};
gl->Enable (GL_DEPTH_TEST);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gl->ClearColor (cube_filter->red, cube_filter->green, cube_filter->blue, 0.0);
gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
gl->MatrixMode (GL_PROJECTION);
gluLookAt (0.0, 0.0, -6.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
gl->MatrixMode (GL_MODELVIEW);
gl->LoadIdentity ();
// gl->Translatef (0.0f, 0.0f, -5.0f);
gl->Rotatef (xrot, 1.0f, 0.0f, 0.0f);
gl->Rotatef (yrot, 0.0f, 1.0f, 0.0f);
gl->Rotatef (zrot, 0.0f, 0.0f, 1.0f);
gl->ClientActiveTexture (GL_TEXTURE0);
gl->EnableClientState (GL_TEXTURE_COORD_ARRAY);
gl->EnableClientState (GL_VERTEX_ARRAY);
gl->VertexPointer (3, GL_FLOAT, 5 * sizeof (float), v_vertices);
gl->TexCoordPointer (2, GL_FLOAT, 5 * sizeof (float), &v_vertices[3]);
gl->DrawElements (GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, indices);
gl->DisableClientState (GL_TEXTURE_COORD_ARRAY);
gl->DisableClientState (GL_VERTEX_ARRAY);
gl->Disable (GL_DEPTH_TEST);
xrot += 0.3f;
yrot += 0.2f;
zrot += 0.4f;
}
#endif
#if GST_GL_HAVE_GLES2
static void
_callback_gles2 (gint width, gint height, guint texture, gpointer stuff)
{
GstGLFilter *filter = GST_GL_FILTER (stuff);
GstGLFilterCube *cube_filter = GST_GL_FILTER_CUBE (filter);
GstGLFuncs *gl = filter->context->gl_vtable;
static GLfloat xrot = 0;
static GLfloat yrot = 0;
static GLfloat zrot = 0;
/* *INDENT-OFF* */
const GLfloat v_vertices[] = {
/*| Vertex | TexCoord |*/
/* front face */
1.0, 1.0, -1.0, 1.0, 0.0,
1.0, -1.0, -1.0, 1.0, 1.0,
-1.0, -1.0, -1.0, 0.0, 1.0,
-1.0, 1.0, -1.0, 0.0, 0.0,
/* back face */
1.0, 1.0, 1.0, 1.0, 0.0,
-1.0, 1.0, 1.0, 0.0, 0.0,
-1.0, -1.0, 1.0, 0.0, 1.0,
1.0, -1.0, 1.0, 1.0, 1.0,
/* right face */
1.0, 1.0, 1.0, 1.0, 0.0,
1.0, -1.0, 1.0, 0.0, 0.0,
1.0, -1.0, -1.0, 0.0, 1.0,
1.0, 1.0, -1.0, 1.0, 1.0,
/* left face */
-1.0, 1.0, 1.0, 1.0, 0.0,
-1.0, 1.0, -1.0, 1.0, 1.0,
-1.0, -1.0, -1.0, 0.0, 1.0,
-1.0, -1.0, 1.0, 0.0, 0.0,
/* top face */
1.0, -1.0, 1.0, 1.0, 0.0,
-1.0, -1.0, 1.0, 0.0, 0.0,
-1.0, -1.0, -1.0, 0.0, 1.0,
1.0, -1.0, -1.0, 1.0, 1.0,
/* bottom face */
1.0, 1.0, 1.0, 1.0, 0.0,
1.0, 1.0, -1.0, 1.0, 1.0,
-1.0, 1.0, -1.0, 0.0, 1.0,
-1.0, 1.0, 1.0, 0.0, 0.0
};
/* *INDENT-ON* */
GLushort indices[] = {
0, 1, 2,
0, 2, 3,
4, 5, 6,
4, 6, 7,
8, 9, 10,
8, 10, 11,
12, 13, 14,
12, 14, 15,
16, 17, 18,
16, 18, 19,
20, 21, 22,
20, 22, 23
};
GLint attr_position_loc = 0;
GLint attr_texture_loc = 0;
const GLfloat matrix[] = {
0.5f, 0.0f, 0.0f, 0.0f,
0.0f, 0.5f, 0.0f, 0.0f,
0.0f, 0.0f, 0.5f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
};
gl->Enable (GL_DEPTH_TEST);
gl->ClearColor (cube_filter->red, cube_filter->green, cube_filter->blue, 0.0);
gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
gst_gl_shader_use (cube_filter->shader);
attr_position_loc =
gst_gl_shader_get_attribute_location (cube_filter->shader, "a_position");
attr_texture_loc =
gst_gl_shader_get_attribute_location (cube_filter->shader, "a_texCoord");
/* Load the vertex position */
gl->VertexAttribPointer (attr_position_loc, 3, GL_FLOAT,
GL_FALSE, 5 * sizeof (GLfloat), v_vertices);
/* Load the texture coordinate */
gl->VertexAttribPointer (attr_texture_loc, 2, GL_FLOAT,
GL_FALSE, 5 * sizeof (GLfloat), &v_vertices[3]);
gl->EnableVertexAttribArray (attr_position_loc);
gl->EnableVertexAttribArray (attr_texture_loc);
gl->ActiveTexture (GL_TEXTURE0);
gl->BindTexture (GL_TEXTURE_2D, texture);
gst_gl_shader_set_uniform_1i (cube_filter->shader, "s_texture", 0);
gst_gl_shader_set_uniform_1f (cube_filter->shader, "xrot_degree", xrot);
gst_gl_shader_set_uniform_1f (cube_filter->shader, "yrot_degree", yrot);
gst_gl_shader_set_uniform_1f (cube_filter->shader, "zrot_degree", zrot);
gst_gl_shader_set_uniform_matrix_4fv (cube_filter->shader, "u_matrix", 1,
GL_FALSE, matrix);
gl->DrawElements (GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, indices);
gl->DisableVertexAttribArray (attr_position_loc);
gl->DisableVertexAttribArray (attr_texture_loc);
gl->Disable (GL_DEPTH_TEST);
xrot += 0.3f;
yrot += 0.2f;
zrot += 0.4f;
}
#endif

65
ext/gl/gstglfiltercube.h Normal file
View file

@ -0,0 +1,65 @@
/*
* GStreamer
* Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef _GST_GL_FILTERCUBE_H_
#define _GST_GL_FILTERCUBE_H_
#include <gst/gl/gstglfilter.h>
G_BEGIN_DECLS
#define GST_TYPE_GL_FILTER_CUBE (gst_gl_filter_cube_get_type())
#define GST_GL_FILTER_CUBE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_FILTER_CUBE,GstGLFilterCube))
#define GST_IS_GL_FILTER_CUBE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_FILTER_CUBE))
#define GST_GL_FILTER_CUBE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_FILTER_CUBE,GstGLFilterCubeClass))
#define GST_IS_GL_FILTER_CUBE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_FILTER_CUBE))
#define GST_GL_FILTER_CUBE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_FILTER_CUBE,GstGLFilterCubeClass))
typedef struct _GstGLFilterCube GstGLFilterCube;
typedef struct _GstGLFilterCubeClass GstGLFilterCubeClass;
struct _GstGLFilterCube
{
GstGLFilter filter;
GstGLShader *shader;
/* background color */
gfloat red;
gfloat green;
gfloat blue;
/* perspective */
gdouble fovy;
gdouble aspect;
gdouble znear;
gdouble zfar;
};
struct _GstGLFilterCubeClass
{
GstGLFilterClass filter_class;
};
GType gst_gl_glfiltercube_get_type (void);
G_END_DECLS
#endif /* _GST_GLFILTERCUBE_H_ */

406
ext/gl/gstglfilterglass.c Normal file
View file

@ -0,0 +1,406 @@
/*
* GStreamer
* Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.com>
* Inspired from http://www.mdk.org.pl/2007/11/17/gl-colorspace-conversions
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:element-glfilterglass
*
* Map textures on moving glass.
*
* <refsect2>
* <title>Examples</title>
* |[
* gst-launch -v videotestsrc ! glupload ! glfilterglass ! glimagesink
* ]| A pipeline inspired from http://www.mdk.org.pl/2007/11/17/gl-colorspace-conversions
* FBO is required.
* |[
* gst-launch -v videotestsrc ! glupload ! glfilterglass ! "video/x-raw-gl, width=640, height=480" ! glimagesink
* ]| The scene is greater than the input size.
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <math.h>
#include "gstglfilterglass.h"
#define GST_CAT_DEFAULT gst_gl_filter_glass_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
enum
{
PROP_0
};
#define DEBUG_INIT \
GST_DEBUG_CATEGORY_INIT (gst_gl_filter_glass_debug, "glfilterglass", 0, "glfilterglass element");
G_DEFINE_TYPE_WITH_CODE (GstGLFilterGlass, gst_gl_filter_glass,
GST_TYPE_GL_FILTER, DEBUG_INIT);
static void gst_gl_filter_glass_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_gl_filter_glass_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_gl_filter_glass_reset (GstGLFilter * filter);
static gboolean gst_gl_filter_glass_init_shader (GstGLFilter * filter);
static gboolean gst_gl_filter_glass_filter_texture (GstGLFilter * filter,
guint in_tex, guint out_tex);
static void gst_gl_filter_glass_draw_background_gradient ();
static void gst_gl_filter_glass_draw_video_plane (GstGLFilter * filter,
gint width, gint height, guint texture, gfloat center_x, gfloat center_y,
gfloat start_alpha, gfloat stop_alpha, gboolean reversed, gfloat rotation);
static void gst_gl_filter_glass_callback (gpointer stuff);
/* *INDENT-OFF* */
static const gchar *glass_fragment_source =
"uniform sampler2D tex;\n"
"varying float alpha;\n"
"void main () {\n"
" float p = 0.0525;\n"
" float L1 = p*1.0;\n"
" float L2 = 1.0 - L1;\n"
" float L3 = 1.0 - L1;\n"
" float w = 1.0;\n"
" float r = L1;\n"
" if (gl_TexCoord[0].x < L1 && gl_TexCoord[0].y < L1)\n"
" r = sqrt( (gl_TexCoord[0].x - L1) * (gl_TexCoord[0].x - L1) + (gl_TexCoord[0].y - L1) * (gl_TexCoord[0].y - L1) );\n"
" else if (gl_TexCoord[0].x > L2 && gl_TexCoord[0].y < L1)\n"
" r = sqrt( (gl_TexCoord[0].x - L2) * (gl_TexCoord[0].x - L2) + (gl_TexCoord[0].y - L1) * (gl_TexCoord[0].y - L1) );\n"
" else if (gl_TexCoord[0].x > L2 && gl_TexCoord[0].y > L3)\n"
" r = sqrt( (gl_TexCoord[0].x - L2) * (gl_TexCoord[0].x - L2) + (gl_TexCoord[0].y - L3) * (gl_TexCoord[0].y - L3) );\n"
" else if (gl_TexCoord[0].x < L1 && gl_TexCoord[0].y > L3)\n"
" r = sqrt( (gl_TexCoord[0].x - L1) * (gl_TexCoord[0].x - L1) + (gl_TexCoord[0].y - L3) * (gl_TexCoord[0].y - L3) );\n"
" if (r > L1)\n"
" w = 0.0;\n"
" vec4 color = texture2D (tex, gl_TexCoord[0].st);\n"
" gl_FragColor = vec4(color.rgb, alpha * w);\n"
"}\n";
static const gchar *glass_vertex_source =
"uniform float yrot;\n"
"uniform float aspect;\n"
"const float fovy = 80.0;\n"
"const float znear = 1.0;\n"
"const float zfar = 5000.0;\n"
"varying float alpha;\n"
"void main () {\n"
" float f = 1.0/(tan(radians(fovy/2.0)));\n"
" float rot = radians (yrot);\n"
" // replacement for gluPerspective\n"
" mat4 perspective = mat4 (\n"
" f/aspect, 0.0, 0.0, 0.0,\n"
" 0.0, f, 0.0, 0.0,\n"
" 0.0, 0.0, (znear+zfar)/(znear-zfar), 2.0*znear*zfar/(znear-zfar),\n"
" 0.0, 0.0, -1.0, 0.0 );\n"
" mat4 trans = mat4 (\n"
" 1.0, 0.0, 0.0, 0.0,\n"
" 0.0, 1.0, 0.0, 0.0,\n"
" 0.0, 0.0, 1.0, -3.0,\n"
" 0.0, 0.0, 0.0, 1.0 );\n"
" mat4 rotation = mat4 (\n"
" cos(rot), 0.0, sin(rot), 0.0,\n"
" 0.0, 1.0, 0.0, 0.0,\n"
" -sin(rot), 0.0, cos(rot), 0.0,\n"
" 0.0, 0.0, 0.0, 1.0 );\n"
" gl_Position = trans * perspective * rotation * gl_ModelViewProjectionMatrix * gl_Vertex;\n"
" gl_TexCoord[0] = gl_MultiTexCoord0;\n"
" alpha = gl_Color.a;\n"
"}\n";
static const gchar * passthrough_vertex =
"void main () {\n"
" gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
" gl_FrontColor = gl_Color;\n"
"}\n";
static const gchar * passthrough_fragment =
"void main () {\n"
" gl_FragColor = gl_Color;\n"
"}\n";
/* *INDENT-ON* */
static void
gst_gl_filter_glass_class_init (GstGLFilterGlassClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *element_class;
gobject_class = (GObjectClass *) klass;
element_class = GST_ELEMENT_CLASS (klass);
gobject_class->set_property = gst_gl_filter_glass_set_property;
gobject_class->get_property = gst_gl_filter_glass_get_property;
gst_element_class_set_metadata (element_class, "OpenGL glass filter",
"Filter/Effect/Video", "Glass Filter",
"Julien Isorce <julien.isorce@gmail.com>");
GST_GL_FILTER_CLASS (klass)->filter_texture =
gst_gl_filter_glass_filter_texture;
GST_GL_FILTER_CLASS (klass)->onInitFBO = gst_gl_filter_glass_init_shader;
GST_GL_FILTER_CLASS (klass)->onReset = gst_gl_filter_glass_reset;
}
static void
gst_gl_filter_glass_init (GstGLFilterGlass * filter)
{
filter->shader = NULL;
filter->timestamp = 0;
}
static void
gst_gl_filter_glass_reset (GstGLFilter * filter)
{
GstGLFilterGlass *glass_filter = GST_GL_FILTER_GLASS (filter);
//blocking call, wait the opengl thread has destroyed the shader
if (glass_filter->shader)
gst_gl_context_del_shader (filter->context, glass_filter->shader);
glass_filter->shader = NULL;
if (glass_filter->passthrough_shader)
gst_gl_context_del_shader (filter->context,
glass_filter->passthrough_shader);
glass_filter->passthrough_shader = NULL;
}
static void
gst_gl_filter_glass_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
//GstGLFilterGlass *filter = GST_GL_FILTER_GLASS (object);
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_filter_glass_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
//GstGLFilterGlass *filter = GST_GL_FILTER_GLASS (object);
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
gst_gl_filter_glass_init_shader (GstGLFilter * filter)
{
gboolean ret;
GstGLFilterGlass *glass_filter = GST_GL_FILTER_GLASS (filter);
//blocking call, wait the opengl thread has compiled the shader
ret =
gst_gl_context_gen_shader (filter->context, glass_vertex_source,
glass_fragment_source, &glass_filter->shader);
if (ret)
ret =
gst_gl_context_gen_shader (filter->context, passthrough_vertex,
passthrough_fragment, &glass_filter->passthrough_shader);
return ret;
}
static gboolean
gst_gl_filter_glass_filter_texture (GstGLFilter * filter, guint in_tex,
guint out_tex)
{
GstGLFilterGlass *glass_filter = GST_GL_FILTER_GLASS (filter);
glass_filter->in_tex = in_tex;
//blocking call, use a FBO
gst_gl_context_use_fbo_v2 (filter->context,
GST_VIDEO_INFO_WIDTH (&filter->out_info),
GST_VIDEO_INFO_HEIGHT (&filter->out_info),
filter->fbo, filter->depthbuffer, out_tex,
gst_gl_filter_glass_callback, (gpointer) glass_filter);
return TRUE;
}
static gint64
get_time (void)
{
static GTimeVal val;
g_get_current_time (&val);
return (val.tv_sec * G_USEC_PER_SEC) + val.tv_usec;
}
static void
gst_gl_filter_glass_draw_background_gradient (GstGLFilterGlass * glass)
{
GstGLFilter *filter = GST_GL_FILTER (glass);
GstGLFuncs *gl = filter->context->gl_vtable;
/* *INDENT-OFF* */
gfloat mesh[] = {
/* | Vertex | Color | */
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
1.0f, 0.8f, 0.0f, 0.0f, 0.0f, 0.2f, 1.0f,
-1.0f, 0.8f, 0.0f, 0.0f, 0.0f, 0.2f, 1.0f,
-1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.2f, 1.0f,
1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.2f, 1.0f,
};
/* *INDENT-ON* */
GLushort indices[] = {
0, 1, 2,
0, 2, 3,
2, 3, 4,
2, 4, 5
};
gl->ClientActiveTexture (GL_TEXTURE0);
gl->EnableClientState (GL_VERTEX_ARRAY);
gl->EnableClientState (GL_COLOR_ARRAY);
gl->VertexPointer (3, GL_FLOAT, 7 * sizeof (gfloat), mesh);
gl->ColorPointer (4, GL_FLOAT, 7 * sizeof (gfloat), &mesh[3]);
gl->DrawElements (GL_TRIANGLES, 12, GL_UNSIGNED_SHORT, indices);
gl->DisableClientState (GL_VERTEX_ARRAY);
gl->DisableClientState (GL_COLOR_ARRAY);
}
static void
gst_gl_filter_glass_draw_video_plane (GstGLFilter * filter,
gint width, gint height, guint texture,
gfloat center_x, gfloat center_y,
gfloat start_alpha, gfloat stop_alpha, gboolean reversed, gfloat rotation)
{
GstGLFilterGlass *glass_filter = GST_GL_FILTER_GLASS (filter);
GstGLFuncs *gl = filter->context->gl_vtable;
gfloat topy = reversed ? center_y - 1.0f : center_y + 1.0f;
gfloat bottomy = reversed ? center_y + 1.0f : center_y - 1.0f;
/* *INDENT-OFF* */
gfloat mesh[] = {
/*| Vertex |TexCoord0| Colour |*/
center_x-1.6, topy, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, start_alpha,
center_x+1.6, topy, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, start_alpha,
center_x+1.6, bottomy, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, stop_alpha,
center_x-1.6, bottomy, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, stop_alpha,
};
/* *INDENT-ON* */
GLushort indices[] = {
0, 1, 2,
0, 2, 3
};
gl->ActiveTexture (GL_TEXTURE0);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gl->Disable (GL_TEXTURE_2D);
gst_gl_shader_set_uniform_1i (glass_filter->shader, "tex", 0);
gst_gl_shader_set_uniform_1f (glass_filter->shader, "yrot", rotation);
gst_gl_shader_set_uniform_1f (glass_filter->shader, "aspect",
(gfloat) width / (gfloat) height);
gl->ClientActiveTexture (GL_TEXTURE0);
gl->EnableClientState (GL_TEXTURE_COORD_ARRAY);
gl->EnableClientState (GL_VERTEX_ARRAY);
gl->EnableClientState (GL_COLOR_ARRAY);
gl->VertexPointer (3, GL_FLOAT, 9 * sizeof (gfloat), mesh);
gl->TexCoordPointer (2, GL_FLOAT, 9 * sizeof (gfloat), &mesh[3]);
gl->ColorPointer (4, GL_FLOAT, 9 * sizeof (gfloat), &mesh[5]);
gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
gl->DisableClientState (GL_TEXTURE_COORD_ARRAY);
gl->DisableClientState (GL_VERTEX_ARRAY);
gl->DisableClientState (GL_COLOR_ARRAY);
}
//opengl scene, params: input texture (not the output filter->texture)
static void
gst_gl_filter_glass_callback (gpointer stuff)
{
static gint64 start_time = 0;
gfloat rotation;
GstGLFilter *filter = GST_GL_FILTER (stuff);
GstGLFilterGlass *glass_filter = GST_GL_FILTER_GLASS (stuff);
GstGLFuncs *gl = filter->context->gl_vtable;
gint width = GST_VIDEO_INFO_WIDTH (&filter->out_info);
gint height = GST_VIDEO_INFO_HEIGHT (&filter->out_info);
guint texture = glass_filter->in_tex;
if (start_time == 0)
start_time = get_time ();
else {
gint64 time_left =
(glass_filter->timestamp / 1000) - (get_time () - start_time);
time_left -= 1000000 / 25;
if (time_left > 2000) {
GST_LOG ("escape");
return;
}
}
gst_gl_shader_use (glass_filter->passthrough_shader);
gst_gl_filter_glass_draw_background_gradient (glass_filter);
//Rotation
if (start_time != 0) {
gint64 time_passed = get_time () - start_time;
rotation = sin (time_passed / 1200000.0) * 45.0f;
} else {
rotation = 0.0f;
}
gl->Enable (GL_BLEND);
gl->BlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
gst_gl_shader_use (glass_filter->shader);
//Reflection
gst_gl_filter_glass_draw_video_plane (filter, width, height, texture,
0.0f, 2.0f, 0.3f, 0.0f, TRUE, rotation);
//Main video
gst_gl_filter_glass_draw_video_plane (filter, width, height, texture,
0.0f, 0.0f, 1.0f, 1.0f, FALSE, rotation);
gst_gl_context_clear_shader (filter->context);
gl->Disable (GL_TEXTURE_2D);
gl->Disable (GL_BLEND);
}

56
ext/gl/gstglfilterglass.h Normal file
View file

@ -0,0 +1,56 @@
/*
* GStreamer
* Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef _GST_GL_FILTERGLASS_H_
#define _GST_GL_FILTERGLASS_H_
#include <gst/gl/gstglfilter.h>
G_BEGIN_DECLS
#define GST_TYPE_GL_FILTER_GLASS (gst_gl_filter_glass_get_type())
#define GST_GL_FILTER_GLASS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_FILTER_GLASS,GstGLFilterGlass))
#define GST_IS_GL_FILTER_GLASS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_FILTER_GLASS))
#define GST_GL_FILTER_GLASS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_FILTER_GLASS,GstGLFilterGlassClass))
#define GST_IS_GL_FILTER_GLASS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_FILTER_GLASS))
#define GST_GL_FILTER_GLASS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_FILTER_GLASS,GstGLFilterGlassClass))
typedef struct _GstGLFilterGlass GstGLFilterGlass;
typedef struct _GstGLFilterGlassClass GstGLFilterGlassClass;
struct _GstGLFilterGlass
{
GstGLFilter filter;
GstGLShader *passthrough_shader;
GstGLShader *shader;
gint64 timestamp;
guint in_tex;
};
struct _GstGLFilterGlassClass
{
GstGLFilterClass filter_class;
};
GType gst_gl_glfilterglass_get_type (void);
G_END_DECLS
#endif /* _GST_GLFILTERGLASS_H_ */

View file

@ -0,0 +1,222 @@
/*
* GStreamer
* Copyright (C) 2008-2010 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:element-glfilterlaplacian
*
* Laplacian Convolution Demo Filter.
*
* <refsect2>
* <title>Examples</title>
* |[
* gst-launch videotestsrc ! glupload ! glfilterlaplacian ! glimagesink
* ]|
* FBO (Frame Buffer Object) and GLSL (OpenGL Shading Language) are required.
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstglfilterlaplacian.h"
#define GST_CAT_DEFAULT gst_gl_filter_laplacian_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
enum
{
PROP_0
};
#define DEBUG_INIT \
GST_DEBUG_CATEGORY_INIT (gst_gl_filter_laplacian_debug, "glfilterlaplacian", 0, "glfilterlaplacian element");
G_DEFINE_TYPE_WITH_CODE (GstGLFilterLaplacian, gst_gl_filter_laplacian,
GST_TYPE_GL_FILTER, DEBUG_INIT);
static void gst_gl_filter_laplacian_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec);
static void gst_gl_filter_laplacian_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec);
static void gst_gl_filter_laplacian_reset (GstGLFilter * filter);
static gboolean gst_gl_filter_laplacian_init_shader (GstGLFilter * filter);
static gboolean gst_gl_filter_laplacian_filter_texture (GstGLFilter * filter,
guint in_tex, guint out_tex);
static void gst_gl_filter_laplacian_callback (gint width, gint height,
guint texture, gpointer stuff);
/* *INDENT-OFF* */
/* This filter is meant as a demo of gst-plugins-gl + glsl
capabilities. So I'm keeping this shader readable enough. If and
when this shader will be used in production be careful to hard code
kernel into the shader and remove unneeded zero multiplications in
the convolution */
static const gchar *convolution_fragment_source =
"uniform sampler2D tex;"
"uniform float kernel[9];"
"uniform float width, height;"
"void main () {"
" float w = 1.0 / width;"
" float h = 1.0 / height;"
" vec2 texturecoord[9];"
" texturecoord[4] = gl_TexCoord[0].st;" /* 0 0 */
" texturecoord[5] = texturecoord[4] + vec2(w, 0.0);" /* 1 0 */
" texturecoord[2] = texturecoord[5] - vec2(0.0, h);" /* 1 -1 */
" texturecoord[1] = texturecoord[2] - vec2(w, 0.0);" /* 0 -1 */
" texturecoord[0] = texturecoord[1] - vec2(w, 0.0);" /* -1 -1 */
" texturecoord[3] = texturecoord[0] + vec2(0.0, h);" /* -1 0 */
" texturecoord[6] = texturecoord[3] + vec2(0.0, h);" /* -1 1 */
" texturecoord[7] = texturecoord[6] + vec2(w, 0.0);" /* 0 1 */
" texturecoord[8] = texturecoord[7] + vec2(w, 0.0);" /* 1 1 */
" int i;"
" vec4 sum = vec4 (0.0);"
" for (i = 0; i < 9; i++) { "
" vec4 neighbor = texture2D(tex, texturecoord[i]);"
" sum += neighbor * kernel[i];"
" }"
" gl_FragColor = sum;"
"}";
/* *INDENT-ON* */
static void
gst_gl_filter_laplacian_class_init (GstGLFilterLaplacianClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *element_class;
gobject_class = (GObjectClass *) klass;
element_class = GST_ELEMENT_CLASS (klass);
gobject_class->set_property = gst_gl_filter_laplacian_set_property;
gobject_class->get_property = gst_gl_filter_laplacian_get_property;
gst_element_class_set_metadata (element_class,
"OpenGL laplacian filter", "Filter/Effect/Video",
"Laplacian Convolution Demo Filter",
"Filippo Argiolas <filippo.argiolas@gmail.com>");
GST_GL_FILTER_CLASS (klass)->filter_texture =
gst_gl_filter_laplacian_filter_texture;
GST_GL_FILTER_CLASS (klass)->onInitFBO = gst_gl_filter_laplacian_init_shader;
GST_GL_FILTER_CLASS (klass)->onReset = gst_gl_filter_laplacian_reset;
}
static void
gst_gl_filter_laplacian_init (GstGLFilterLaplacian * filter)
{
filter->shader = NULL;
}
static void
gst_gl_filter_laplacian_reset (GstGLFilter * filter)
{
GstGLFilterLaplacian *laplacian_filter = GST_GL_FILTER_LAPLACIAN (filter);
//blocking call, wait the opengl thread has destroyed the shader
if (laplacian_filter->shader)
gst_gl_context_del_shader (filter->context, laplacian_filter->shader);
laplacian_filter->shader = NULL;
}
static void
gst_gl_filter_laplacian_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
//GstGLFilterLaplacian *filter = GST_GL_FILTER_LAPLACIAN (object);
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_filter_laplacian_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
//GstGLFilterLaplacian *filter = GST_GL_FILTER_LAPLACIAN (object);
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
gst_gl_filter_laplacian_init_shader (GstGLFilter * filter)
{
GstGLFilterLaplacian *laplacian_filter = GST_GL_FILTER_LAPLACIAN (filter);
//blocking call, wait the opengl thread has compiled the shader
return gst_gl_context_gen_shader (filter->context, 0,
convolution_fragment_source, &laplacian_filter->shader);
}
static gboolean
gst_gl_filter_laplacian_filter_texture (GstGLFilter * filter, guint in_tex,
guint out_tex)
{
gpointer laplacian_filter = GST_GL_FILTER_LAPLACIAN (filter);
//blocking call, use a FBO
gst_gl_filter_render_to_target (filter, TRUE, in_tex, out_tex,
gst_gl_filter_laplacian_callback, laplacian_filter);
return TRUE;
}
//opengl scene, params: input texture (not the output filter->texture)
static void
gst_gl_filter_laplacian_callback (gint width, gint height, guint texture,
gpointer stuff)
{
GstGLFilter *filter = GST_GL_FILTER (stuff);
GstGLFilterLaplacian *laplacian_filter = GST_GL_FILTER_LAPLACIAN (filter);
GstGLFuncs *gl = filter->context->gl_vtable;
gfloat kernel[9] = { 0.0, -1.0, 0.0,
-1.0, 4.0, -1.0,
0.0, -1.0, 0.0
};
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gst_gl_shader_use (laplacian_filter->shader);
gl->ActiveTexture (GL_TEXTURE0);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gst_gl_shader_set_uniform_1i (laplacian_filter->shader, "tex", 0);
gst_gl_shader_set_uniform_1fv (laplacian_filter->shader, "kernel", 9, kernel);
gst_gl_shader_set_uniform_1f (laplacian_filter->shader, "width",
(gfloat) width);
gst_gl_shader_set_uniform_1f (laplacian_filter->shader, "height",
(gfloat) height);
gst_gl_filter_draw_texture (filter, texture, width, height);
}

View file

@ -0,0 +1,53 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef _GST_GL_FILTERLAPLACIAN_H_
#define _GST_GL_FILTERLAPLACIAN_H_
#include <gst/gl/gstglfilter.h>
G_BEGIN_DECLS
#define GST_TYPE_GL_FILTER_LAPLACIAN (gst_gl_filter_laplacian_get_type())
#define GST_GL_FILTER_LAPLACIAN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_FILTER_LAPLACIAN,GstGLFilterLaplacian))
#define GST_IS_GL_FILTER_LAPLACIAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_FILTER_LAPLACIAN))
#define GST_GL_FILTER_LAPLACIAN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_FILTER_LAPLACIAN,GstGLFilterLaplacianClass))
#define GST_IS_GL_FILTER_LAPLACIAN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_FILTER_LAPLACIAN))
#define GST_GL_FILTER_LAPLACIAN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_FILTER_LAPLACIAN,GstGLFilterLaplacianClass))
typedef struct _GstGLFilterLaplacian GstGLFilterLaplacian;
typedef struct _GstGLFilterLaplacianClass GstGLFilterLaplacianClass;
struct _GstGLFilterLaplacian
{
GstGLFilter filter;
GstGLShader *shader;
};
struct _GstGLFilterLaplacianClass
{
GstGLFilterClass filter_class;
};
GType gst_gl_glfilterlaplacian_get_type (void);
G_END_DECLS
#endif /* _GST_GLFILTERLAPLACIAN_H_ */

View file

@ -0,0 +1,482 @@
/*
* GStreamer
* Copyright (C) 2010 Pierre Pouzol<pierre.pouzol@hotmail.fr>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:element-glfilterreflectedscreen
*
* Map Video Texture upon a screen, on a reflecting surface
*
* <refsect2>
* <title>Examples</title>
* |[
* gst-launch videotestsrc ! glupload ! glfilterreflectedscreen ! glimagesink
* ]|
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <math.h>
#include "gstglfilterreflectedscreen.h"
#define GST_CAT_DEFAULT gst_gl_filter_reflected_screen_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
enum
{
PROP_0,
PROP_ACTIVE_GRAPHIC_MODE,
PROP_SEPARATED_SCREEN,
PROP_SHOW_FLOOR,
PROP_FOVY,
PROP_ASPECT,
PROP_ZNEAR,
PROP_ZFAR
};
#define DEBUG_INIT \
GST_DEBUG_CATEGORY_INIT (gst_gl_filter_reflected_screen_debug, "glfilterreflectedscreen", 0, "glfilterreflectedscreen element");
G_DEFINE_TYPE_WITH_CODE (GstGLFilterReflectedScreen,
gst_gl_filter_reflected_screen, GST_TYPE_GL_FILTER, DEBUG_INIT);
static void gst_gl_filter_reflected_screen_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec);
static void gst_gl_filter_reflected_screen_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec);
static gboolean gst_gl_filter_reflected_screen_filter_texture (GstGLFilter *
filter, guint in_tex, guint out_tex);
static void gst_gl_filter_reflected_screen_draw_background ();
static void gst_gl_filter_reflected_screen_draw_floor ();
static void gst_gl_filter_reflected_screen_draw_screen (GstGLFilter * filter,
gint width, gint height, guint texture);
static void gst_gl_filter_reflected_screen_draw_separated_screen (GstGLFilter *
filter, gint width, gint height, guint texture, gfloat alphs, gfloat alphe);
static void gst_gl_filter_reflected_screen_callback (gint width, gint height,
guint texture, gpointer stuff);
static GLfloat LightPos[] = { 4.0f, -4.0f, 6.0f, 1.0f }; // Light Position
static GLfloat LightAmb[] = { 4.0f, 4.0f, 4.0f, 1.0f }; // Ambient Light
static GLfloat LightDif[] = { 1.0f, 1.0f, 1.0f, 1.0f }; // Diffuse Light
static void
gst_gl_filter_reflected_screen_class_init (GstGLFilterReflectedScreenClass *
klass)
{
GObjectClass *gobject_class;
GstElementClass *element_class;
gobject_class = (GObjectClass *) klass;
element_class = GST_ELEMENT_CLASS (klass);
gobject_class->set_property = gst_gl_filter_reflected_screen_set_property;
gobject_class->get_property = gst_gl_filter_reflected_screen_get_property;
GST_GL_FILTER_CLASS (klass)->filter_texture =
gst_gl_filter_reflected_screen_filter_texture;
g_object_class_install_property (gobject_class, PROP_ACTIVE_GRAPHIC_MODE,
g_param_spec_boolean ("active-graphic-mode",
"Activate graphic mode",
"Allow user to activate stencil buffer and blending.",
TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_SEPARATED_SCREEN,
g_param_spec_boolean ("separated-screen",
"Create a separation space",
"Allow to insert a space between the two screen. Will cancel 'show floor' if active. Value are TRUE or FALSE(default)",
FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_SHOW_FLOOR,
g_param_spec_boolean ("show-floor",
"Show the support",
"Allow the user to show the supportive floor. Will cancel 'separated screen' if active. Value are TRUE(default) or FALSE",
TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_FOVY,
g_param_spec_double ("fovy", "Fovy", "Field of view angle in degrees",
0.0, 180.0, 60, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_ASPECT,
g_param_spec_double ("aspect", "Aspect",
"Field of view in the x direction", 1.0, 100, 1.0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_ZNEAR,
g_param_spec_double ("znear", "Znear",
"Specifies the distance from the viewer to the near clipping plane",
0.0000000001, 100.0, 0.1,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_ZFAR,
g_param_spec_double ("zfar", "Zfar",
"Specifies the distance from the viewer to the far clipping plane",
0.0, 1000.0, 100.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_element_class_set_metadata (element_class,
"OpenGL Reflected Screen filter", "Filter/Effect/Video",
"Reflected Screen Filter", "Pierre POUZOL <pierre.pouzol@hotmail.fr>");
}
static void
gst_gl_filter_reflected_screen_init (GstGLFilterReflectedScreen * filter)
{
filter->active_graphic_mode = TRUE;
filter->separated_screen = FALSE;
filter->show_floor = TRUE;
filter->fovy = 90;
filter->aspect = 1.0;
filter->znear = 0.1;
filter->zfar = 1000;
}
static void
gst_gl_filter_reflected_screen_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstGLFilterReflectedScreen *filter = GST_GL_FILTER_REFLECTED_SCREEN (object);
switch (prop_id) {
case PROP_ACTIVE_GRAPHIC_MODE:
filter->active_graphic_mode = g_value_get_boolean (value);
break;
case PROP_SEPARATED_SCREEN:
filter->separated_screen = g_value_get_boolean (value);
break;
case PROP_SHOW_FLOOR:
filter->show_floor = g_value_get_boolean (value);
break;
case PROP_FOVY:
filter->fovy = g_value_get_double (value);
break;
case PROP_ASPECT:
filter->aspect = g_value_get_double (value);
break;
case PROP_ZNEAR:
filter->znear = g_value_get_double (value);
break;
case PROP_ZFAR:
filter->zfar = g_value_get_double (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_filter_reflected_screen_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstGLFilterReflectedScreen *filter = GST_GL_FILTER_REFLECTED_SCREEN (object);
switch (prop_id) {
case PROP_ACTIVE_GRAPHIC_MODE:
g_value_set_boolean (value, filter->active_graphic_mode);
break;
case PROP_SEPARATED_SCREEN:
g_value_set_boolean (value, filter->separated_screen);
break;
case PROP_SHOW_FLOOR:
g_value_set_boolean (value, filter->show_floor);
break;
case PROP_FOVY:
g_value_set_double (value, filter->fovy);
break;
case PROP_ASPECT:
g_value_set_double (value, filter->aspect);
break;
case PROP_ZNEAR:
g_value_set_double (value, filter->znear);
break;
case PROP_ZFAR:
g_value_set_double (value, filter->zfar);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
gst_gl_filter_reflected_screen_filter_texture (GstGLFilter * filter,
guint in_tex, guint out_tex)
{
GstGLFilterReflectedScreen *reflected_screen_filter =
GST_GL_FILTER_REFLECTED_SCREEN (filter);
//blocking call, use a FBO
gst_gl_context_use_fbo (filter->context,
GST_VIDEO_INFO_WIDTH (&filter->out_info),
GST_VIDEO_INFO_HEIGHT (&filter->out_info),
filter->fbo, filter->depthbuffer, out_tex,
gst_gl_filter_reflected_screen_callback,
GST_VIDEO_INFO_WIDTH (&filter->in_info),
GST_VIDEO_INFO_HEIGHT (&filter->in_info), in_tex,
reflected_screen_filter->fovy, reflected_screen_filter->aspect,
reflected_screen_filter->znear, reflected_screen_filter->zfar,
GST_GL_DISPLAY_PROJECTION_PERSPECTIVE,
(gpointer) reflected_screen_filter);
return TRUE;
}
static void
gst_gl_filter_reflected_screen_draw_separated_screen (GstGLFilter * filter,
gint width, gint height, guint texture, gfloat alphs, gfloat alphe)
{
//enable ARB Rectangular texturing
//that's necessary to have the video displayed on our screen (with gstreamer)
glEnable (GL_TEXTURE_2D);
glBindTexture (GL_TEXTURE_2D, texture);
//configure parameters for the texturing
//the two first are used to specified how the texturing will be done if the screen is greater than the texture herself
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//the next two specified how the texture will comport near the limits
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//creating screen and setting the texture (depending on texture's height and width)
glBegin (GL_QUADS);
// right Face
glColor4f (1.0f, 1.0f, 1.0f, alphs);
glTexCoord2f (0.5f, 1.0f);
glVertex3f (-0.75f, 0.0f, -1.0f);
glColor4f (1.0f, 1.0f, 1.0f, alphe);
glTexCoord2f (0.5f, 0.0f);
glVertex3f (-0.75f, 1.25f, -1.0f);
glTexCoord2f (1.0f, 0.0f);
glVertex3f (1.25f, 1.25f, -1.0f);
glColor4f (1.0f, 1.0f, 1.0f, alphs);
glTexCoord2f (1.0f, 1.0f);
glVertex3f (1.25f, 0.0f, -1.0f);
// Left Face
glColor4f (1.0f, 1.0f, 1.0f, alphs);
glTexCoord2f (0.5f, 1.0f);
glVertex3f (-1.0f, 0.0f, -0.75f);
glTexCoord2f (0.0f, 1.0f);
glVertex3f (-1.0f, 0.0f, 1.25f);
glColor4f (1.0f, 1.0f, 1.0f, alphe);
glTexCoord2f (0.0f, 0.0f);
glVertex3f (-1.0f, 1.25f, 1.25f);
glTexCoord2f (0.5f, 0.0f);
glVertex3f (-1.0f, 1.25f, -0.75f);
glEnd ();
glDisable (GL_TEXTURE_2D);
}
static void
gst_gl_filter_reflected_screen_draw_screen (GstGLFilter * filter,
gint width, gint height, guint texture)
{
//enable ARB Rectangular texturing
//that's necessary to have the video displayed on our screen (with gstreamer)
glEnable (GL_TEXTURE_2D);
glBindTexture (GL_TEXTURE_2D, texture);
//configure parameters for the texturing
//the two first are used to specified how the texturing will be done if the screen is greater than the texture herself
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//the next two specified how the texture will comport near the limits
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//creating screen and setting the texture (depending on texture's height and width)
glBegin (GL_QUADS);
glTexCoord2f (0.5f, 1.0f);
glVertex3f (-1.0f, 0.0f, -1.0f);
glTexCoord2f (0.5f, 0.0f);
glVertex3f (-1.0f, 1.0f, -1.0f);
glTexCoord2f (1.0f, 0.0f);
glVertex3f (1.0f, 1.0f, -1.0f);
glTexCoord2f (1.0f, 1.0f);
glVertex3f (1.0f, 0.0f, -1.0f);
// Left Face
glTexCoord2f (0.5f, 1.0f);
glVertex3f (-1.0f, 0.0f, -1.0f);
glTexCoord2f (0.0f, 1.0f);
glVertex3f (-1.0f, 0.0f, 1.0f);
glTexCoord2f (0.0f, 0.0f);
glVertex3f (-1.0f, 1.0f, 1.0f);
glTexCoord2f (0.5f, 0.0f);
glVertex3f (-1.0f, 1.0f, -1.0f);
glEnd ();
//disable this kind of texturing (useless for the gluDisk)
glDisable (GL_TEXTURE_2D);
}
static void
gst_gl_filter_reflected_screen_draw_background ()
{
glBegin (GL_QUADS);
// right Face
glColor4f (0.0f, 0.0f, 0.0f, 1.0f);
glVertex3f (-10.0f, -10.0f, -1.0f);
glColor4f (0.0f, 0.0f, 0.2f, 1.0f);
glVertex3f (-10.0f, 10.0f, -1.0f);
glVertex3f (10.0f, 10.0f, -1.0f);
glVertex3f (10.0f, -10.0f, -1.0f);
glEnd ();
}
static void
gst_gl_filter_reflected_screen_draw_floor ()
{
GLUquadricObj *q;
//create a quadric for the floor's drawing
q = gluNewQuadric ();
//configure this quadric's parameter (for lighting and texturing)
gluQuadricNormals (q, GL_SMOOTH);
gluQuadricTexture (q, GL_FALSE);
//drawing the disk. The texture are mapped thanks to the parameter we gave to the GLUquadric q
gluDisk (q, 0.0, 2.2, 50, 1);
}
//opengl scene, params: input texture (not the output filter->texture)
static void
gst_gl_filter_reflected_screen_callback (gint width, gint height, guint texture,
gpointer stuff)
{
GstGLFilter *filter = GST_GL_FILTER (stuff);
GstGLFilterReflectedScreen *reflected_screen_filter =
GST_GL_FILTER_REFLECTED_SCREEN (stuff);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
//load identity befor tracing
glLoadIdentity ();
//camera translation
glTranslatef (0.0f, 0.1f, -1.3f);
//camera configuration
if (reflected_screen_filter->separated_screen)
gluLookAt (0.1, -0.25, 2.0, 0.025, 0.0, 0.0, 0.0, 1.0, 0.0);
else
gluLookAt (0.1, -0.35, 2.0, 0.025, 0.0, 0.0, 0.0, 1.0, 0.0);
gst_gl_filter_reflected_screen_draw_background ();
if (reflected_screen_filter->separated_screen) {
glEnable (GL_BLEND);
glPushMatrix ();
glScalef (1.0f, -1.0f, 1.0f);
glTranslatef (0.0f, 0.0f, 1.2f);
glRotatef (-45.0f, 0.0, 1.0, 0.0);
gst_gl_filter_reflected_screen_draw_separated_screen (filter, width, height,
texture, 1.0f, 1.0f);
glPopMatrix ();
if (reflected_screen_filter->active_graphic_mode) {
//configuration of the transparency function
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTranslatef (0.0f, 0.0f, 1.2f);
glRotatef (-45.0f, 0.0, 1.0, 0.0);
gst_gl_filter_reflected_screen_draw_separated_screen (filter, width,
height, texture, 0.5f, 0.0f);
glDisable (GL_BLEND);
}
}
if (reflected_screen_filter->show_floor) {
glLightfv (GL_LIGHT0, GL_AMBIENT, LightAmb);
glLightfv (GL_LIGHT0, GL_DIFFUSE, LightDif);
glLightfv (GL_LIGHT0, GL_POSITION, LightPos);
//enable lighting
glEnable (GL_LIGHT0);
glEnable (GL_LIGHTING);
if (reflected_screen_filter->active_graphic_mode) {
glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
//enable stencil buffer use
glEnable (GL_STENCIL_TEST);
//setting the stencil buffer. Each time a pixel will be drawn by now, this pixel value will be set to 1
glStencilFunc (GL_ALWAYS, 1, 1);
glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE);
//disable the zbuffer
glDisable (GL_DEPTH_TEST);
//make a rotation of 90 degree on x axis. By default, gluDisk draw a disk on z axis
glRotatef (-90.0f, 1.0, 0.0, 0.0);
//draw the floor. Each pixel representing this floor will now have a value of 1 on stencil buffer
gst_gl_filter_reflected_screen_draw_floor ();
//make an anti-rotation of 90 degree to draw the rest of the scene on the right angle
glRotatef (90.0f, 1.0, 0.0, 0.0);
//enable zbuffer again
glEnable (GL_DEPTH_TEST);
//enable the drawing to be shown
glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
//say that the next object have to be drawn ONLY where the stencil buffer's pixel's value is 1
glStencilFunc (GL_EQUAL, 1, 1);
glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
//save the actual matrix
glPushMatrix ();
glLightfv (GL_LIGHT0, GL_POSITION, LightPos);
//translate the object on z axis
glTranslatef (0.0f, 0.0f, 1.4f);
//rotate it (because the drawing method place the user behind the left part of the screen)
glRotatef (-45.0f, 0.0, 1.0, 0.0);
//draw the reflexion
gst_gl_filter_reflected_screen_draw_screen (filter, width, height,
texture);
//return to the saved matrix position
glPopMatrix ();
//end of the stencil buffer uses
glDisable (GL_STENCIL_TEST);
//enable the blending to mix the floor and reflexion color
glEnable (GL_BLEND);
glDisable (GL_LIGHTING);
//specified a white color (for the floor) with 20% transparency
glColor4f (1.0f, 1.0f, 1.0f, 0.8f);
//configuration of the transparency function
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
//draw the floor (which will appear this time)
glRotatef (-90.0f, 1.0, 0.0, 0.0);
gst_gl_filter_reflected_screen_draw_floor ();
glRotatef (90.0f, 1.0, 0.0, 0.0);
glDisable (GL_BLEND);
glEnable (GL_LIGHTING);
//draw the real object
//scale on y axis. The object must be drawn upside down (to suggest a reflexion)
glScalef (1.0f, -1.0f, 1.0f);
glTranslatef (0.0f, 0.0f, 1.4f);
glRotatef (-45.0f, 0.0, 1.0, 0.0);
gst_gl_filter_reflected_screen_draw_screen (filter, width, height, texture);
glDisable (GL_LIGHTING);
}
}

View file

@ -0,0 +1,61 @@
/*
* GStreamer
* Copyright (C) 2008 Pierre Pouzol<pierre.pouzol@hotmail.fr>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef _GST_GL_FILTERREFLECTEDSCREEN_H_
#define _GST_GL_FILTERREFLECTEDSCREEN_H_
#include <gst/gl/gstglfilter.h>
G_BEGIN_DECLS
#define GST_TYPE_GL_FILTER_REFLECTED_SCREEN (gst_gl_filter_reflected_screen_get_type())
#define GST_GL_FILTER_REFLECTED_SCREEN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_FILTER_REFLECTED_SCREEN,GstGLFilterReflectedScreen))
#define GST_IS_GL_FILTER_REFLECTED_SCREEN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_FILTER_REFLECTED_SCREEN))
#define GST_GL_FILTER_REFLECTED_SCREEN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_FILTER_REFLECTED_SCREEN,GstGLFilterReflectedScreenClass))
#define GST_IS_GL_FILTER_REFLECTED_SCREEN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_FILTER_REFLECTED_SCREEN))
#define GST_GL_FILTER_REFLECTED_SCREEN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_FILTER_REFLECTED_SCREEN,GstGLFilterReflectedScreenClass))
typedef struct _GstGLFilterReflectedScreen GstGLFilterReflectedScreen;
typedef struct _GstGLFilterReflectedScreenClass GstGLFilterReflectedScreenClass;
struct _GstGLFilterReflectedScreen
{
GstGLFilter filter;
gdouble fovy;
gdouble aspect;
gdouble znear;
gdouble zfar;
gboolean active_graphic_mode;
gboolean separated_screen;
gboolean show_floor;
};
struct _GstGLFilterReflectedScreenClass
{
GstGLFilterClass filter_class;
};
GType gst_gl_glfilterreflectedscreen_get_type (void);
G_END_DECLS
#endif /* _GST_GLFILTERREFLECTEDSCREEN_H_ */

382
ext/gl/gstglfiltershader.c Normal file
View file

@ -0,0 +1,382 @@
/*
* glshader gstreamer plugin
* Copyrithg (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
* Copyright (C) 2009 Luc Deschenaux <luc.deschenaux@freesurf.ch>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:element-glshader
*
* Filter loading OpenGL fragment shader from file
*
* <refsect2>
* <title>Examples</title>
* |[
* gst-launch videotestsrc ! glupload ! glshader location=myshader.fs ! glimagesink
* ]|
* FBO (Frame Buffer Object) and GLSL (OpenGL Shading Language) are required.
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <gst/gst.h>
#include <gst/gl/gstglshadervariables.h>
#include "gstglfiltershader.h"
/* horizontal filter */
static gchar *hfilter_fragment_source;
static gchar *hfilter_fragment_variables[2];
enum
{
PROP_0,
PROP_LOCATION,
PROP_PRESET,
PROP_VARIABLES
};
#define GST_CAT_DEFAULT gst_gl_filtershader_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#define DEBUG_INIT \
GST_DEBUG_CATEGORY_INIT (gst_gl_filtershader_debug, "glshader", 0, "glshader element");
G_DEFINE_TYPE_WITH_CODE (GstGLFilterShader, gst_gl_filtershader,
GST_TYPE_GL_FILTER, DEBUG_INIT);
static void gst_gl_filtershader_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_gl_filtershader_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_gl_filter_filtershader_reset (GstGLFilter * filter);
static gboolean gst_gl_filtershader_load_shader (GstGLFilterShader *
filter_shader, char *filename, char **storage);
static gboolean gst_gl_filtershader_load_variables (GstGLFilterShader *
filter_shader, char *filename, char **storage);
static gboolean gst_gl_filtershader_init_shader (GstGLFilter * filter);
static gboolean gst_gl_filtershader_filter_texture (GstGLFilter * filter,
guint in_tex, guint out_tex);
static void gst_gl_filtershader_hcallback (gint width, gint height,
guint texture, gpointer stuff);
static void
gst_gl_filtershader_init_resources (GstGLFilter * filter)
{
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8,
GST_VIDEO_INFO_WIDTH (&filter->out_info),
GST_VIDEO_INFO_HEIGHT (&filter->out_info),
0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
static void
gst_gl_filtershader_reset_resources (GstGLFilter * filter)
{
//GstGLFilterShader *filtershader = GST_GL_FILTERSHADER (filter);
}
static void
gst_gl_filtershader_class_init (GstGLFilterShaderClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *element_class;
gobject_class = (GObjectClass *) klass;
element_class = GST_ELEMENT_CLASS (klass);
gobject_class->set_property = gst_gl_filtershader_set_property;
gobject_class->get_property = gst_gl_filtershader_get_property;
g_object_class_install_property (gobject_class, PROP_LOCATION,
g_param_spec_string ("location", "File Location",
"Location of the GLSL file to load", NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_PRESET,
g_param_spec_string ("preset", "Preset File Location",
"Location of the shader uniform variables preset file", NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_VARIABLES,
g_param_spec_string ("vars", "Uniform variables",
"Set the shader uniform variables", NULL,
G_PARAM_WRITABLE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
gst_element_class_set_metadata (element_class,
"OpenGL fragment shader filter", "Filter/Effect",
"Load GLSL fragment shader from file", "<luc.deschenaux@freesurf.ch>");
GST_GL_FILTER_CLASS (klass)->filter_texture =
gst_gl_filtershader_filter_texture;
GST_GL_FILTER_CLASS (klass)->display_init_cb =
gst_gl_filtershader_init_resources;
GST_GL_FILTER_CLASS (klass)->display_reset_cb =
gst_gl_filtershader_reset_resources;
GST_GL_FILTER_CLASS (klass)->onInitFBO = gst_gl_filtershader_init_shader;
GST_GL_FILTER_CLASS (klass)->onReset = gst_gl_filter_filtershader_reset;
}
static void
gst_gl_filtershader_init (GstGLFilterShader * filtershader)
{
filtershader->shader0 = NULL;
}
static void
gst_gl_filter_filtershader_reset (GstGLFilter * filter)
{
GstGLFilterShader *filtershader = GST_GL_FILTERSHADER (filter);
//blocking call, wait the opengl thread has destroyed the shader
if (filtershader->shader0)
gst_gl_context_del_shader (filter->context, filtershader->shader0);
filtershader->shader0 = NULL;
}
static void
gst_gl_filtershader_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstGLFilterShader *filtershader = GST_GL_FILTERSHADER (object);
switch (prop_id) {
case PROP_LOCATION:
if (filtershader->filename) {
g_free (filtershader->filename);
}
if (filtershader->compiled) {
//gst_gl_context_del_shader (filtershader->filter.context, filtershader->shader0);
gst_gl_filter_filtershader_reset (&filtershader->filter);
filtershader->shader0 = 0;
}
filtershader->filename = g_strdup (g_value_get_string (value));
filtershader->compiled = 0;
filtershader->texSet = 0;
break;
case PROP_PRESET:
if (filtershader->presetfile) {
g_free (filtershader->presetfile);
}
filtershader->presetfile = g_strdup (g_value_get_string (value));
if (hfilter_fragment_variables[0]) {
g_free (hfilter_fragment_variables[0]);
hfilter_fragment_variables[0] = 0;
}
if (!filtershader->presetfile[0]) {
g_free (filtershader->presetfile);
filtershader->presetfile = 0;
}
break;
case PROP_VARIABLES:
if (hfilter_fragment_variables[1]) {
g_free (hfilter_fragment_variables[1]);
}
hfilter_fragment_variables[1] = g_strdup (g_value_get_string (value));
if (!hfilter_fragment_variables[1][0]) {
g_free (hfilter_fragment_variables[1]);
hfilter_fragment_variables[1] = 0;
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_filtershader_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstGLFilterShader *filtershader = GST_GL_FILTERSHADER (object);
switch (prop_id) {
case PROP_LOCATION:
g_value_set_string (value, filtershader->filename);
break;
case PROP_PRESET:
g_value_set_string (value, filtershader->presetfile);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
gst_gl_filtershader_load_shader (GstGLFilterShader * filter_shader,
char *filename, char **storage)
{
GError *error = NULL;
gsize length;
g_return_val_if_fail (storage != NULL, FALSE);
if (!filename) {
GST_ELEMENT_ERROR (filter_shader, RESOURCE, NOT_FOUND,
("A shader file is required"), (NULL));
return FALSE;
}
if (!g_file_get_contents (filename, storage, &length, &error)) {
GST_ELEMENT_ERROR (filter_shader, RESOURCE, NOT_FOUND, ("%s",
error->message), (NULL));
g_error_free (error);
return FALSE;
}
return TRUE;
}
static gboolean
gst_gl_filtershader_load_variables (GstGLFilterShader * filter_shader,
char *filename, char **storage)
{
GError *error = NULL;
gsize length;
if (storage[0]) {
g_free (storage[0]);
storage[0] = 0;
}
if (!filename)
return TRUE;
if (!g_file_get_contents (filename, storage, &length, &error)) {
GST_ELEMENT_ERROR (filter_shader, RESOURCE, NOT_FOUND, ("%s",
error->message), (NULL));
g_error_free (error);
return FALSE;
}
return TRUE;
}
static void
gst_gl_filtershader_variables_parse (GstGLShader * shader, gchar * variables)
{
gst_gl_shadervariables_parse (shader, variables, 0);
}
static gboolean
gst_gl_filtershader_init_shader (GstGLFilter * filter)
{
GstGLFilterShader *filtershader = GST_GL_FILTERSHADER (filter);
if (!gst_gl_filtershader_load_shader (filtershader, filtershader->filename,
&hfilter_fragment_source))
return FALSE;
//blocking call, wait the opengl thread has compiled the shader
if (!gst_gl_context_gen_shader (filter->context, 0, hfilter_fragment_source,
&filtershader->shader0))
return FALSE;
if (!gst_gl_filtershader_load_variables (filtershader,
filtershader->presetfile, &hfilter_fragment_variables[0]))
return FALSE;
filtershader->compiled = 1;
return TRUE;
}
static gboolean
gst_gl_filtershader_filter_texture (GstGLFilter * filter, guint in_tex,
guint out_tex)
{
GstGLFilterShader *filtershader = GST_GL_FILTERSHADER (filter);
gst_gl_filter_render_to_target (filter, TRUE, in_tex, out_tex,
gst_gl_filtershader_hcallback, filtershader);
return TRUE;
}
static void
gst_gl_filtershader_hcallback (gint width, gint height, guint texture,
gpointer stuff)
{
GstGLFilter *filter = GST_GL_FILTER (stuff);
GstGLFilterShader *filtershader = GST_GL_FILTERSHADER (filter);
GstGLFuncs *gl = filter->context->gl_vtable;
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gst_gl_shader_use (filtershader->shader0);
gl->ActiveTexture (GL_TEXTURE1);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gl->Disable (GL_TEXTURE_2D);
gst_gl_shader_set_uniform_1i (filtershader->shader0, "tex", 1);
if (hfilter_fragment_variables[0]) {
gst_gl_filtershader_variables_parse (filtershader->shader0,
hfilter_fragment_variables[0]);
g_free (hfilter_fragment_variables[0]);
hfilter_fragment_variables[0] = 0;
}
if (hfilter_fragment_variables[1]) {
gst_gl_filtershader_variables_parse (filtershader->shader0,
hfilter_fragment_variables[1]);
g_free (hfilter_fragment_variables[1]);
hfilter_fragment_variables[1] = 0;
}
gst_gl_filter_draw_texture (filter, texture, width, height);
}

View file

@ -0,0 +1,55 @@
/*
* glshader gstreamer plugin
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
* Copyright (C) 2009 Luc Deschenaux <luc.deschenaux@freesurf.ch>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef _GST_GL_FILTERSHADER_H_
#define _GST_GL_FILTERSHADER_H_
#include <gst/gl/gstglfilter.h>
#define GST_TYPE_GL_FILTERSHADER (gst_gl_filtershader_get_type())
#define GST_GL_FILTERSHADER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_FILTERSHADER,GstGLFilterShader))
#define GST_IS_GL_FILTERSHADER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_FILTERSHADER))
#define GST_GL_FILTERSHADER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_FILTERSHADER,GstGLFilterShaderClass))
#define GST_IS_GL_FILTERSHADER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_FILTERSHADER))
#define GST_GL_FILTERSHADER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_FILTERSHADER,GstGLFilterShaderClass))
typedef struct _GstGLFilterShader GstGLFilterShader;
typedef struct _GstGLFilterShaderClass GstGLFilterShaderClass;
struct _GstGLFilterShader
{
GstGLFilter filter;
GstGLShader *shader0;
int compiled;
gchar *filename;
gchar *presetfile;
int texSet;
};
struct _GstGLFilterShaderClass
{
GstGLFilterClass filter_class;
};
GType gst_gl_glfiltershader_get_type (void);
#endif /* _GST_GL_FILTERSHADER_H_ */

269
ext/gl/gstglfiltersobel.c Normal file
View file

@ -0,0 +1,269 @@
/*
* GStreamer
* Copyright (C) 2008-2010 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:element-glfiltersobel.
*
* Sobel Edge Detection.
*
* <refsect2>
* <title>Examples</title>
* |[
* gst-launch videotestsrc ! glupload ! glfiltersobel ! glimagesink
* ]|
* FBO (Frame Buffer Object) and GLSL (OpenGL Shading Language) are required.
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstglfiltersobel.h"
#include "effects/gstgleffectssources.h"
enum
{
PROP_0,
PROP_INVERT
};
#define GST_CAT_DEFAULT gst_gl_filtersobel_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#define DEBUG_INIT \
GST_DEBUG_CATEGORY_INIT (gst_gl_filtersobel_debug, "glfiltersobel", 0, "glfiltersobel element");
G_DEFINE_TYPE_WITH_CODE (GstGLFilterSobel, gst_gl_filtersobel,
GST_TYPE_GL_FILTER, DEBUG_INIT);
static void gst_gl_filtersobel_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_gl_filtersobel_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_gl_filter_filtersobel_reset (GstGLFilter * filter);
static gboolean gst_gl_filtersobel_init_shader (GstGLFilter * filter);
static gboolean gst_gl_filtersobel_filter_texture (GstGLFilter * filter,
guint in_tex, guint out_tex);
static void gst_gl_filtersobel_length (gint width, gint height, guint texture,
gpointer stuff);
static void
gst_gl_filtersobel_init_resources (GstGLFilter * filter)
{
GstGLFilterSobel *filtersobel = GST_GL_FILTERSOBEL (filter);
GstGLFuncs *gl = filter->context->gl_vtable;
int i;
for (i = 0; i < 2; i++) {
gl->GenTextures (1, &filtersobel->midtexture[i]);
gl->BindTexture (GL_TEXTURE_2D, filtersobel->midtexture[i]);
gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8,
GST_VIDEO_INFO_WIDTH (&filter->out_info),
GST_VIDEO_INFO_HEIGHT (&filter->out_info),
0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
}
static void
gst_gl_filtersobel_reset_resources (GstGLFilter * filter)
{
GstGLFilterSobel *filtersobel = GST_GL_FILTERSOBEL (filter);
GstGLFuncs *gl = filter->context->gl_vtable;
int i;
for (i = 0; i < 2; i++) {
gl->DeleteTextures (1, &filtersobel->midtexture[i]);
}
}
static void
gst_gl_filtersobel_class_init (GstGLFilterSobelClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *element_class;
gobject_class = (GObjectClass *) klass;
element_class = GST_ELEMENT_CLASS (klass);
gobject_class->set_property = gst_gl_filtersobel_set_property;
gobject_class->get_property = gst_gl_filtersobel_get_property;
GST_GL_FILTER_CLASS (klass)->filter_texture =
gst_gl_filtersobel_filter_texture;
GST_GL_FILTER_CLASS (klass)->display_init_cb =
gst_gl_filtersobel_init_resources;
GST_GL_FILTER_CLASS (klass)->display_reset_cb =
gst_gl_filtersobel_reset_resources;
GST_GL_FILTER_CLASS (klass)->onInitFBO = gst_gl_filtersobel_init_shader;
GST_GL_FILTER_CLASS (klass)->onReset = gst_gl_filter_filtersobel_reset;
g_object_class_install_property (gobject_class,
PROP_INVERT,
g_param_spec_boolean ("invert",
"Invert the colors",
"Invert colors to get dark edges on bright background",
FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_element_class_set_metadata (element_class,
"Gstreamer OpenGL Sobel", "Filter/Effect/Video", "Sobel edge detection",
"Filippo Argiolas <filippo.argiolas@gmail.com>");
}
static void
gst_gl_filtersobel_init (GstGLFilterSobel * filtersobel)
{
int i;
filtersobel->hconv = NULL;
filtersobel->vconv = NULL;
filtersobel->invert = FALSE;
for (i = 0; i < 2; i++) {
filtersobel->midtexture[i] = 0;
}
}
static void
gst_gl_filter_filtersobel_reset (GstGLFilter * filter)
{
GstGLFilterSobel *filtersobel = GST_GL_FILTERSOBEL (filter);
//blocking call, wait the opengl thread has destroyed the shader
if (filtersobel->desat)
gst_gl_context_del_shader (filter->context, filtersobel->desat);
filtersobel->desat = NULL;
if (filtersobel->hconv)
gst_gl_context_del_shader (filter->context, filtersobel->hconv);
filtersobel->hconv = NULL;
if (filtersobel->vconv)
gst_gl_context_del_shader (filter->context, filtersobel->vconv);
filtersobel->vconv = NULL;
if (filtersobel->len)
gst_gl_context_del_shader (filter->context, filtersobel->len);
filtersobel->len = NULL;
}
static void
gst_gl_filtersobel_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstGLFilterSobel *filtersobel = GST_GL_FILTERSOBEL (object);
switch (prop_id) {
case PROP_INVERT:
filtersobel->invert = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_filtersobel_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstGLFilterSobel *filtersobel = GST_GL_FILTERSOBEL (object);
switch (prop_id) {
case PROP_INVERT:
g_value_set_boolean (value, filtersobel->invert);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
gst_gl_filtersobel_init_shader (GstGLFilter * filter)
{
GstGLFilterSobel *filtersobel = GST_GL_FILTERSOBEL (filter);
gboolean ret = TRUE;
//blocking call, wait the opengl thread has compiled the shader
ret =
gst_gl_context_gen_shader (filter->context, 0, desaturate_fragment_source,
&filtersobel->desat);
ret &=
gst_gl_context_gen_shader (filter->context, 0,
sep_sobel_hconv3_fragment_source, &filtersobel->hconv);
ret &=
gst_gl_context_gen_shader (filter->context, 0,
sep_sobel_vconv3_fragment_source, &filtersobel->vconv);
ret &=
gst_gl_context_gen_shader (filter->context, 0,
sep_sobel_length_fragment_source, &filtersobel->len);
return ret;
}
static gboolean
gst_gl_filtersobel_filter_texture (GstGLFilter * filter, guint in_tex,
guint out_tex)
{
GstGLFilterSobel *filtersobel = GST_GL_FILTERSOBEL (filter);
gst_gl_filter_render_to_target_with_shader (filter, TRUE, in_tex,
filtersobel->midtexture[0], filtersobel->desat);
gst_gl_filter_render_to_target_with_shader (filter, FALSE,
filtersobel->midtexture[0], filtersobel->midtexture[1],
filtersobel->hconv);
gst_gl_filter_render_to_target_with_shader (filter, FALSE,
filtersobel->midtexture[1], filtersobel->midtexture[0],
filtersobel->vconv);
gst_gl_filter_render_to_target (filter, FALSE, filtersobel->midtexture[0],
out_tex, gst_gl_filtersobel_length, filtersobel);
return TRUE;
}
static void
gst_gl_filtersobel_length (gint width, gint height, guint texture,
gpointer stuff)
{
GstGLFilter *filter = GST_GL_FILTER (stuff);
GstGLFuncs *gl = filter->context->gl_vtable;
GstGLFilterSobel *filtersobel = GST_GL_FILTERSOBEL (filter);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gst_gl_shader_use (filtersobel->len);
gl->ActiveTexture (GL_TEXTURE1);
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, texture);
gl->Disable (GL_TEXTURE_2D);
gst_gl_shader_set_uniform_1i (filtersobel->len, "tex", 1);
gst_gl_shader_set_uniform_1i (filtersobel->len, "invert",
filtersobel->invert);
gst_gl_filter_draw_texture (filter, texture, width, height);
}

56
ext/gl/gstglfiltersobel.h Normal file
View file

@ -0,0 +1,56 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef _GST_GL_FILTERSOBEL_H_
#define _GST_GL_FILTERSOBEL_H_
#include <gst/gl/gstglfilter.h>
#define GST_TYPE_GL_FILTERSOBEL (gst_gl_filtersobel_get_type())
#define GST_GL_FILTERSOBEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_FILTERSOBEL,GstGLFilterSobel))
#define GST_IS_GL_FILTERSOBEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_FILTERSOBEL))
#define GST_GL_FILTERSOBEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_FILTERSOBEL,GstGLFilterSobelClass))
#define GST_IS_GL_FILTERSOBEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_FILTERSOBEL))
#define GST_GL_FILTERSOBEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_FILTERSOBEL,GstGLFilterSobelClass))
typedef struct _GstGLFilterSobel GstGLFilterSobel;
typedef struct _GstGLFilterSobelClass GstGLFilterSobelClass;
struct _GstGLFilterSobel
{
GstGLFilter filter;
GstGLShader *hconv;
GstGLShader *vconv;
GstGLShader *len;
GstGLShader *desat;
GLuint midtexture[5];
gboolean invert;
};
struct _GstGLFilterSobelClass
{
GstGLFilterClass filter_class;
};
GType gst_gl_glfiltersobel_get_type (void);
#endif /* _GST_GL_FILTERSOBEL_H_ */

1206
ext/gl/gstglimagesink.c Normal file

File diff suppressed because it is too large Load diff

102
ext/gl/gstglimagesink.h Normal file
View file

@ -0,0 +1,102 @@
/*
* GStreamer
* Copyright (C) 2003 Julien Moutte <julien@moutte.net>
* Copyright (C) 2005,2006,2007 David A. Schleef <ds@schleef.org>
* Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef _GLIMAGESINK_H_
#define _GLIMAGESINK_H_
#include <gst/gst.h>
#include <gst/video/gstvideosink.h>
#include <gst/video/video.h>
#include <gst/gl/gl.h>
G_BEGIN_DECLS
GST_DEBUG_CATEGORY_EXTERN (gst_debug_glimage_sink);
#define GST_TYPE_GLIMAGE_SINK \
(gst_glimage_sink_get_type())
#define GST_GLIMAGE_SINK(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GLIMAGE_SINK,GstGLImageSink))
#define GST_GLIMAGE_SINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GLIMAGE_SINK,GstGLImageSinkClass))
#define GST_IS_GLIMAGE_SINK(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GLIMAGE_SINK))
#define GST_IS_GLIMAGE_SINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GLIMAGE_SINK))
typedef struct _GstGLImageSink GstGLImageSink;
typedef struct _GstGLImageSinkClass GstGLImageSinkClass;
struct _GstGLImageSink
{
GstVideoSink video_sink;
//properties
gchar *display_name;
guintptr window_id;
guintptr new_window_id;
//caps
GstVideoInfo info;
GstGLDisplay *display;
GstGLContext *context;
GstGLContext *other_context;
GstGLUpload *upload;
GLuint tex_id;
CRCB clientReshapeCallback;
CDCB clientDrawCallback;
gpointer client_data;
volatile gint to_quit;
gboolean keep_aspect_ratio;
gint par_n, par_d;
GstBufferPool *pool;
/* avoid replacing the stored_buffer while drawing */
GMutex drawing_lock;
GLuint redisplay_texture;
#if GST_GL_HAVE_GLES2
GstGLShader *redisplay_shader;
GLint redisplay_attr_position_loc;
GLint redisplay_attr_texture_loc;
#endif
};
struct _GstGLImageSinkClass
{
GstVideoSinkClass video_sink_class;
};
GType gst_glimage_sink_get_type(void);
G_END_DECLS
#endif

365
ext/gl/gstglmosaic.c Normal file
View file

@ -0,0 +1,365 @@
/*
* GStreamer
* Copyright (C) 2009 Julien Isorce <julien.isorce@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:element-glmosaic
*
* glmixer sub element. N gl sink pads to 1 source pad.
* N + 1 OpenGL contexts shared together.
* N <= 6 because the rendering is more a like a cube than a mosaic
* Each opengl input stream is rendered on a cube face
*
* <refsect2>
* <title>Examples</title>
* |[
* gst-launch-0.10 videotestsrc ! "video/x-raw-yuv, format=(fourcc)YUY2" ! glupload ! queue ! glmosaic name=m ! glimagesink videotestsrc pattern=12 ! "video/x-raw-yuv, format=(fourcc)I420, framerate=(fraction)5/1, width=100, height=200" ! glupload ! queue ! m. videotestsrc ! "video/x-raw-rgb, framerate=(fraction)15/1, width=1500, height=1500" ! glupload ! gleffects effect=3 ! queue ! m. videotestsrc ! glupload ! gleffects effect=2 ! queue ! m. videotestsrc ! glupload ! glfiltercube ! queue ! m. videotestsrc ! glupload ! gleffects effect=6 ! queue ! m.
* ]|
* FBO (Frame Buffer Object) is required.
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstglmosaic.h"
#define GST_CAT_DEFAULT gst_gl_mosaic_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
enum
{
PROP_0,
};
#define DEBUG_INIT \
GST_DEBUG_CATEGORY_INIT (gst_gl_mosaic_debug, "glmosaic", 0, "glmosaic element");
G_DEFINE_TYPE_WITH_CODE (GstGLMosaic, gst_gl_mosaic, GST_TYPE_GL_MIXER,
DEBUG_INIT);
static void gst_gl_mosaic_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_gl_mosaic_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_gl_mosaic_reset (GstGLMixer * mixer);
static gboolean gst_gl_mosaic_init_shader (GstGLMixer * mixer,
GstCaps * outcaps);
static gboolean gst_gl_mosaic_process_textures (GstGLMixer * mixer,
GPtrArray * frames, guint out_tex);
static void gst_gl_mosaic_callback (gpointer stuff);
//vertex source
static const gchar *mosaic_v_src =
"uniform mat4 u_matrix; \n"
"uniform float xrot_degree, yrot_degree, zrot_degree; \n"
"attribute vec4 a_position; \n"
"attribute vec2 a_texCoord; \n"
"varying vec2 v_texCoord; \n"
"void main() \n"
"{ \n"
" float PI = 3.14159265; \n"
" float xrot = xrot_degree*2.0*PI/360.0; \n"
" float yrot = yrot_degree*2.0*PI/360.0; \n"
" float zrot = zrot_degree*2.0*PI/360.0; \n"
" mat4 matX = mat4 ( \n"
" 1.0, 0.0, 0.0, 0.0, \n"
" 0.0, cos(xrot), sin(xrot), 0.0, \n"
" 0.0, -sin(xrot), cos(xrot), 0.0, \n"
" 0.0, 0.0, 0.0, 1.0 ); \n"
" mat4 matY = mat4 ( \n"
" cos(yrot), 0.0, -sin(yrot), 0.0, \n"
" 0.0, 1.0, 0.0, 0.0, \n"
" sin(yrot), 0.0, cos(yrot), 0.0, \n"
" 0.0, 0.0, 0.0, 1.0 ); \n"
" mat4 matZ = mat4 ( \n"
" cos(zrot), sin(zrot), 0.0, 0.0, \n"
" -sin(zrot), cos(zrot), 0.0, 0.0, \n"
" 0.0, 0.0, 1.0, 0.0, \n"
" 0.0, 0.0, 0.0, 1.0 ); \n"
" gl_Position = u_matrix * matZ * matY * matX * a_position; \n"
" v_texCoord = a_texCoord; \n"
"} \n";
//fragment source
static const gchar *mosaic_f_src =
"uniform sampler2D s_texture; \n"
"varying vec2 v_texCoord; \n"
"void main() \n"
"{ \n"
//" gl_FragColor = vec4( 1.0, 0.5, 1.0, 1.0 );\n"
" gl_FragColor = texture2D( s_texture, v_texCoord );\n"
"} \n";
static void
gst_gl_mosaic_class_init (GstGLMosaicClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *element_class;
gobject_class = (GObjectClass *) klass;
element_class = GST_ELEMENT_CLASS (klass);
gobject_class->set_property = gst_gl_mosaic_set_property;
gobject_class->get_property = gst_gl_mosaic_get_property;
gst_element_class_set_metadata (element_class, "OpenGL mosaic",
"Filter/Effect/Video", "OpenGL mosaic",
"Julien Isorce <julien.isorce@gmail.com>");
GST_GL_MIXER_CLASS (klass)->set_caps = gst_gl_mosaic_init_shader;
GST_GL_MIXER_CLASS (klass)->reset = gst_gl_mosaic_reset;
GST_GL_MIXER_CLASS (klass)->process_textures = gst_gl_mosaic_process_textures;
}
static void
gst_gl_mosaic_init (GstGLMosaic * mosaic)
{
mosaic->shader = NULL;
mosaic->input_frames = NULL;
}
static void
gst_gl_mosaic_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
//GstGLMosaic *mixer = GST_GL_MOSAIC (object);
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_mosaic_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
//GstGLMosaic* mixer = GST_GL_MOSAIC (object);
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_mosaic_reset (GstGLMixer * mixer)
{
GstGLMosaic *mosaic = GST_GL_MOSAIC (mixer);
mosaic->input_frames = NULL;
//blocking call, wait the opengl thread has destroyed the shader
if (mosaic->shader)
gst_gl_context_del_shader (mixer->context, mosaic->shader);
mosaic->shader = NULL;
}
static gboolean
gst_gl_mosaic_init_shader (GstGLMixer * mixer, GstCaps * outcaps)
{
GstGLMosaic *mosaic = GST_GL_MOSAIC (mixer);
//blocking call, wait the opengl thread has compiled the shader
return gst_gl_context_gen_shader (mixer->context, mosaic_v_src, mosaic_f_src,
&mosaic->shader);
}
static gboolean
gst_gl_mosaic_process_textures (GstGLMixer * mix, GPtrArray * frames,
guint out_tex)
{
GstGLMosaic *mosaic = GST_GL_MOSAIC (mix);
mosaic->input_frames = frames;
//blocking call, use a FBO
gst_gl_context_use_fbo_v2 (mix->context,
GST_VIDEO_INFO_WIDTH (&mix->out_info),
GST_VIDEO_INFO_HEIGHT (&mix->out_info), mix->fbo, mix->depthbuffer,
out_tex, gst_gl_mosaic_callback, (gpointer) mosaic);
return TRUE;
}
/* opengl scene, params: input texture (not the output mixer->texture) */
static void
gst_gl_mosaic_callback (gpointer stuff)
{
GstGLMosaic *mosaic = GST_GL_MOSAIC (stuff);
GstGLMixer *mixer = GST_GL_MIXER (mosaic);
GstGLFuncs *gl = mixer->context->gl_vtable;
static GLfloat xrot = 0;
static GLfloat yrot = 0;
static GLfloat zrot = 0;
GLint attr_position_loc = 0;
GLint attr_texture_loc = 0;
const GLfloat matrix[] = {
0.5f, 0.0f, 0.0f, 0.0f,
0.0f, 0.5f, 0.0f, 0.0f,
0.0f, 0.0f, 0.5f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
};
const GLushort indices[] = {
0, 1, 2,
0, 2, 3
};
guint count = 0;
gst_gl_context_clear_shader (mixer->context);
gl->BindTexture (GL_TEXTURE_2D, 0);
gl->Disable (GL_TEXTURE_2D);
gl->Enable (GL_DEPTH_TEST);
gl->ClearColor (0.0, 0.0, 0.0, 0.0);
gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
gst_gl_shader_use (mosaic->shader);
attr_position_loc =
gst_gl_shader_get_attribute_location (mosaic->shader, "a_position");
attr_texture_loc =
gst_gl_shader_get_attribute_location (mosaic->shader, "a_texCoord");
while (count < mosaic->input_frames->len && count < 6) {
GstGLMixerFrameData *frame;
GLfloat *v_vertices;
guint in_tex;
guint width, height;
frame = g_ptr_array_index (mosaic->input_frames, count);
in_tex = frame->texture;
width = GST_VIDEO_INFO_WIDTH (&frame->pad->in_info);
height = GST_VIDEO_INFO_HEIGHT (&frame->pad->in_info);
if (!frame || !in_tex || width <= 0 || height <= 0) {
GST_DEBUG ("skipping texture:%u frame:%p width:%u height %u",
in_tex, frame, width, height);
count++;
continue;
}
GST_TRACE ("processing texture:%u dimensions:%ux%u", in_tex, width, height);
/* *INDENT-OFF* */
v_vertices = (GLfloat[]) {
/* front face */
1.0f, 1.0f, -1.0f,
1.0f, 0.0f,
1.0f, -1.0f, -1.0f,
1.0f, 1.0f,
-1.0f, -1.0f, -1.0f,
0.0f, 1.0f,
-1.0f, 1.0f, -1.0f,
0.0f, 0.0f,
/* right face */
1.0f, 1.0f, 1.0f,
1.0f, 0.0f,
1.0f, -1.0f, 1.0f,
0.0f, 0.0f,
1.0f, -1.0f, -1.0f,
0.0f, 1.0f,
1.0f, 1.0f, -1.0f,
1.0f, 1.0f,
/* left face */
-1.0f, 1.0f, 1.0f,
1.0f, 0.0f,
-1.0f, 1.0f, -1.0f,
1.0f, 1.0f,
-1.0f, -1.0f, -1.0f,
0.0f, 1.0f,
-1.0f, -1.0f, 1.0f,
0.0f, 0.0f,
/* top face */
1.0f, -1.0f, 1.0f,
1.0f, 0.0f,
-1.0f, -1.0f, 1.0f,
0.0f, 0.0f,
-1.0f, -1.0f, -1.0f,
0.0f, 1.0f,
1.0f, -1.0f, -1.0f,
1.0f, 1.0f,
/* bottom face */
1.0f, 1.0f, 1.0f,
1.0f, 0.0f,
1.0f, 1.0f, -1.0f,
1.0f, 1.0f,
-1.0f, 1.0f, -1.0f,
0.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
0.0f, 0.0f,
/* back face */
1.0f, 1.0f, 1.0f,
1.0f, 0.0f,
-1.0f, 1.0f, 1.0f,
0.0f, 0.0f,
-1.0f, -1.0f, 1.0f,
0.0f, 1.0f,
1.0f, -1.0f, 1.0f,
1.0f, 1.0f
};
/* *INDENT-ON* */
gl->VertexAttribPointer (attr_position_loc, 3, GL_FLOAT,
GL_FALSE, 5 * sizeof (GLfloat), &v_vertices[5 * 4 * count]);
gl->VertexAttribPointer (attr_texture_loc, 2, GL_FLOAT,
GL_FALSE, 5 * sizeof (GLfloat), &v_vertices[5 * 4 * count + 3]);
gl->EnableVertexAttribArray (attr_position_loc);
gl->EnableVertexAttribArray (attr_texture_loc);
gl->ActiveTexture (GL_TEXTURE0);
gl->BindTexture (GL_TEXTURE_2D, in_tex);
gst_gl_shader_set_uniform_1i (mosaic->shader, "s_texture", 0);
gst_gl_shader_set_uniform_1f (mosaic->shader, "xrot_degree", xrot);
gst_gl_shader_set_uniform_1f (mosaic->shader, "yrot_degree", yrot);
gst_gl_shader_set_uniform_1f (mosaic->shader, "zrot_degree", zrot);
gst_gl_shader_set_uniform_matrix_4fv (mosaic->shader, "u_matrix", 1,
GL_FALSE, matrix);
gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
++count;
}
gl->DisableVertexAttribArray (attr_position_loc);
gl->DisableVertexAttribArray (attr_texture_loc);
gl->BindTexture (GL_TEXTURE_2D, 0);
gl->Disable (GL_DEPTH_TEST);
gst_gl_context_clear_shader (mixer->context);
xrot += 0.6f;
yrot += 0.4f;
zrot += 0.8f;
}

55
ext/gl/gstglmosaic.h Normal file
View file

@ -0,0 +1,55 @@
/*
* GStreamer
* Copyright (C) 2009 Julien Isorce <julien.isorce@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef _GST_GL_MOSAIC_H_
#define _GST_GL_MOSAIC_H_
#include <gst/gl/gstglmixer.h>
G_BEGIN_DECLS
#define GST_TYPE_GL_MOSAIC (gst_gl_mosaic_get_type())
#define GST_GL_MOSAIC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_MOSAIC,GstGLMosaic))
#define GST_IS_GL_MOSAIC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_MOSAIC))
#define GST_GL_MOSAIC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_MOSAIC,GstGLMosaicClass))
#define GST_IS_GL_MOSAIC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_MOSAIC))
#define GST_GL_MOSAIC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_MOSAIC,GstGLMosaicClass))
typedef struct _GstGLMosaic GstGLMosaic;
typedef struct _GstGLMosaicClass GstGLMosaicClass;
struct _GstGLMosaic
{
GstGLMixer mixer;
GstGLShader *shader;
GPtrArray *input_frames;
};
struct _GstGLMosaicClass
{
GstGLMixerClass mixer_class;
};
GType gst_gl_mosaic_get_type (void);
G_END_DECLS
#endif /* _GST_GLFILTERCUBE_H_ */

809
ext/gl/gstgloverlay.c Normal file
View file

@ -0,0 +1,809 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:element-gloverlay
*
* Overlay GL video texture with a PNG image
*
* <refsect2>
* <title>Examples</title>
* |[
* gst-launch videotestsrc ! "video/x-raw-rgb" ! glupload ! gloverlay location=imagefile ! glimagesink
* ]|
* FBO (Frame Buffer Object) is required.
* </refsect2>
*/
/* FIXME: Redo this */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gl/gstglconfig.h>
#include "gstgloverlay.h"
#include "effects/gstgleffectssources.h"
#include <stdio.h>
#include <stdlib.h>
#include <jpeglib.h>
#include <png.h>
#if PNG_LIBPNG_VER >= 10400
#define int_p_NULL NULL
#define png_infopp_NULL NULL
#endif
#define GST_CAT_DEFAULT gst_gl_overlay_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#define DEBUG_INIT \
GST_DEBUG_CATEGORY_INIT (gst_gl_overlay_debug, "gloverlay", 0, "gloverlay element");
G_DEFINE_TYPE_WITH_CODE (GstGLOverlay, gst_gl_overlay, GST_TYPE_GL_FILTER,
DEBUG_INIT);
static gboolean gst_gl_overlay_set_caps (GstGLFilter * filter,
GstCaps * incaps, GstCaps * outcaps);
static void gst_gl_overlay_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_gl_overlay_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_gl_overlay_init_resources (GstGLFilter * filter);
static void gst_gl_overlay_reset_resources (GstGLFilter * filter);
static gboolean gst_gl_overlay_filter_texture (GstGLFilter * filter,
guint in_tex, guint out_tex);
static gint gst_gl_overlay_load_png (GstGLFilter * filter);
static gint gst_gl_overlay_load_jpeg (GstGLFilter * filter);
enum
{
PROP_0,
PROP_LOCATION,
PROP_XPOS_PNG,
PROP_YPOS_PNG,
PROP_SIZE_PNG,
PROP_XPOS_VIDEO,
PROP_YPOS_VIDEO,
PROP_SIZE_VIDEO,
PROP_VIDEOTOP,
PROP_ROTATE_PNG,
PROP_ROTATE_VIDEO,
PROP_ANGLE_PNG,
PROP_ANGLE_VIDEO,
PROP_RATIO_VIDEO
};
/* init resources that need a gl context */
static void
gst_gl_overlay_init_gl_resources (GstGLFilter * filter)
{
// GstGLOverlay *overlay = GST_GL_OVERLAY (filter);
}
/* free resources that need a gl context */
static void
gst_gl_overlay_reset_gl_resources (GstGLFilter * filter)
{
GstGLOverlay *overlay = GST_GL_OVERLAY (filter);
const GstGLFuncs *gl = filter->context->gl_vtable;
gl->DeleteTextures (1, &overlay->pbuftexture);
}
static void
gst_gl_overlay_class_init (GstGLOverlayClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *element_class;
gobject_class = (GObjectClass *) klass;
element_class = GST_ELEMENT_CLASS (klass);
gobject_class->set_property = gst_gl_overlay_set_property;
gobject_class->get_property = gst_gl_overlay_get_property;
GST_GL_FILTER_CLASS (klass)->set_caps = gst_gl_overlay_set_caps;
GST_GL_FILTER_CLASS (klass)->filter_texture = gst_gl_overlay_filter_texture;
GST_GL_FILTER_CLASS (klass)->display_init_cb =
gst_gl_overlay_init_gl_resources;
GST_GL_FILTER_CLASS (klass)->display_reset_cb =
gst_gl_overlay_reset_gl_resources;
GST_GL_FILTER_CLASS (klass)->onStart = gst_gl_overlay_init_resources;
GST_GL_FILTER_CLASS (klass)->onStop = gst_gl_overlay_reset_resources;
g_object_class_install_property (gobject_class,
PROP_LOCATION,
g_param_spec_string ("location",
"Location of the image",
"Location of the image", NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_XPOS_PNG,
g_param_spec_int ("xpos-png",
"X position of overlay image in percents",
"X position of overlay image in percents",
0, 100, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_YPOS_PNG,
g_param_spec_int ("ypos-png",
"Y position of overlay image in percents",
"Y position of overlay image in percents",
0, 100, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_SIZE_PNG,
g_param_spec_int ("proportion-png",
"Relative size of overlay image, in percents",
"Relative size of iverlay image, in percents",
0, 100, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_XPOS_VIDEO,
g_param_spec_int ("xpos-video",
"X position of overlay video in percents",
"X position of overlay video in percents",
0, 100, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_YPOS_VIDEO,
g_param_spec_int ("ypos-video",
"Y position of overlay video in percents",
"Y position of overlay video in percents",
0, 100, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_SIZE_VIDEO,
g_param_spec_int ("proportion-video",
"Relative size of overlay video, in percents",
"Relative size of iverlay video, in percents",
0, 100, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_VIDEOTOP,
g_param_spec_boolean ("video-top",
"Video-top", "Video is over png image", FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_ROTATE_PNG,
g_param_spec_int ("rotate-png",
"choose rotation axis for the moment only Y axis is implemented",
"choose rotation axis for the moment only Y axis is implemented",
0, 3, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_ROTATE_VIDEO,
g_param_spec_int ("rotate-video",
"choose rotation axis for the moment only Y axis is implemented",
"choose rotation axis for the moment only Y axis is implemented",
0, 3, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_ANGLE_PNG,
g_param_spec_int ("angle-png",
"choose angle in axis to choosen between -90 and 90",
"choose angle in axis to choosen between -90 and 90",
-90, 90, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_ANGLE_VIDEO,
g_param_spec_int ("angle-video",
"choose angle in axis to choosen between -90 and 90",
"choose angle in axis to choosen between -90 and 90",
-90, 90, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_RATIO_VIDEO,
g_param_spec_int ("ratio-video",
"choose ratio video between 0 and 3\n \t\t\t0 : Default ratio\n\t\t\t1 : 4 / 3\n\t\t\t2 : 16 / 9\n\t\t\t3 : 16 / 10",
"choose ratio video between 0 and 3\n \t\t\t0 : Default ratio\n\t\t\t1 : 4 / 3\n\t\t\t2 : 16 / 9\n\t\t\t3 : 16 / 10",
0, 3, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_element_class_set_metadata (element_class,
"Gstreamer OpenGL Overlay", "Filter/Effect/Video",
"Overlay GL video texture with a PNG image",
"Filippo Argiolas <filippo.argiolas@gmail.com>");
/*
g_object_class_install_property (gobject_class,
PROP_STRETCH,
g_param_spec_boolean ("stretch",
"Stretch the image to texture size",
"Stretch the image to fit video texture size",
TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
*/
}
static void
gst_gl_overlay_calc_ratio_video (GstGLOverlay * o, gfloat * video_ratio_w,
gfloat * video_ratio_h)
{
if (o->ratio_video == 0) {
o->ratio_texture = (gfloat) o->ratio_window;
*video_ratio_w = (gfloat) o->width_window;
*video_ratio_h = (gfloat) o->height_window;
} else if (o->ratio_video == 1) {
o->ratio_texture = (gfloat) 1.33;
*video_ratio_w = 4.0;
*video_ratio_h = 3.0;
} else if (o->ratio_video == 2) {
o->ratio_texture = (gfloat) 1.77;
*video_ratio_w = 16.0;
*video_ratio_h = 9.0;
} else {
o->ratio_texture = (gfloat) 1.6;
*video_ratio_w = 16.0;
*video_ratio_h = 10.0;
}
}
static void
gst_gl_overlay_init_texture (GstGLOverlay * o, GLuint tex, int flag)
{
GstGLFilter *filter = GST_GL_FILTER (o);
const GstGLFuncs *gl = filter->context->gl_vtable;
if (flag == 0 && o->type_file == 2) {
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, tex);
} else {
gl->Enable (GL_TEXTURE_2D);
gl->BindTexture (GL_TEXTURE_2D, tex);
}
}
static void
gst_gl_overlay_draw (GstGLOverlay * o, int flag)
{
GstGLFilter *filter = GST_GL_FILTER (o);
const GstGLFuncs *gl = filter->context->gl_vtable;
float y = 0.0f;
float width = 0.0f;
float height = 0.0f;
/* *INDENT-OFF* */
float v_vertices[] = {
/*| Vertex | TexCoord |*/
-o->ratio_x + o->posx, y, 0.0f, 0.0f, 0.0f,
o->ratio_x + o->posx, y, 0.0f, width, 0.0f,
o->ratio_x + o->posx, y, 0.0f, width, height,
-o->ratio_x + o->posx, y, 0.0f, 0.0, height,
};
GLushort indices[] = {
0, 1, 2,
0, 2, 3,
};
/* *INDENT-ON* */
if (flag == 1) {
width = 1.0f;
height = 1.0f;
} else if (flag == 0 && o->type_file == 1) {
width = (gfloat) o->width;
height = (gfloat) o->height;
} else if (flag == 0 && o->type_file == 2) {
width = 1.0f;
height = 1.0f;
}
v_vertices[8] = width;
v_vertices[13] = width;
v_vertices[14] = height;
v_vertices[19] = height;
y = (o->type_file == 2 && flag == 0 ? o->ratio_y : -o->ratio_y) + o->posy;
v_vertices[1] = y;
v_vertices[6] = y;
y = (o->type_file == 2 && flag == 0 ? -o->ratio_y : o->ratio_y) + o->posy;
v_vertices[11] = y;
v_vertices[16] = y;
gst_gl_context_clear_shader (filter->context);
gl->ClientActiveTexture (GL_TEXTURE0);
gl->EnableClientState (GL_TEXTURE_COORD_ARRAY);
gl->EnableClientState (GL_VERTEX_ARRAY);
gl->VertexPointer (3, GL_FLOAT, 5 * sizeof (float), v_vertices);
gl->TexCoordPointer (2, GL_FLOAT, 5 * sizeof (float), &v_vertices[3]);
gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
gl->DisableClientState (GL_TEXTURE_COORD_ARRAY);
gl->DisableClientState (GL_VERTEX_ARRAY);
}
static void
gst_gl_overlay_calc_proportion (GstGLOverlay * o, int flag, float size_texture,
float width, float height)
{
if ((1.59f < o->ratio_window && o->ratio_window < 1.61f
&& 1.77f < o->ratio_texture && o->ratio_texture < 1.78f)
|| (1.3f < o->ratio_window && o->ratio_window < 1.34f
&& ((1.7f < o->ratio_texture && o->ratio_texture < 1.78f)
|| (1.59f < o->ratio_texture && o->ratio_texture < 1.61f)))) {
o->ratio_x = o->ratio_window * (gfloat) size_texture / 100.0f;
o->ratio_y =
(o->ratio_window / width) * height * (gfloat) size_texture / 100.0f;
} else {
o->ratio_x = o->ratio_texture * (gfloat) size_texture / 100.0f;
o->ratio_y = 1.0f * size_texture / 100.0f;
}
o->posx =
((o->ratio_window - o->ratio_x) * ((flag ==
1 ? o->pos_x_video : o->pos_x_png) - 50.0f) / 50.0f);
o->posy =
(1.0f - o->ratio_y) * (((flag ==
1 ? o->pos_y_video : o->pos_y_png) - 50.0f) / 50.0f);
}
static void
gst_gl_overlay_load_texture (GstGLOverlay * o, GLuint tex, int flag)
{
GstGLFilter *filter = GST_GL_FILTER (o);
const GstGLFuncs *gl = filter->context->gl_vtable;
gfloat video_ratio_w;
gfloat video_ratio_h;
o->ratio_window = (gfloat) o->width_window / (gfloat) o->height_window;
gl->MatrixMode (GL_MODELVIEW);
gl->ActiveTexture (GL_TEXTURE0);
gst_gl_overlay_init_texture (o, tex, flag);
gl->BlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
gl->Enable (GL_BLEND);
gl->Translatef (0.0f, 0.0f, -1.43f);
if (flag == 1) {
if (o->rotate_video)
gl->Rotatef (o->angle_video, 0, 1, 0);
gst_gl_overlay_calc_ratio_video (o, &video_ratio_w, &video_ratio_h);
gst_gl_overlay_calc_proportion (o, flag, o->size_video, video_ratio_w,
video_ratio_h);
} else {
o->ratio_texture = (gfloat) o->width / (gfloat) o->height;
if (o->rotate_png == 2)
gl->Rotatef (o->angle_png, 0, 1, 0);
gst_gl_overlay_calc_proportion (o, flag, o->size_png, (gfloat) o->width,
(gfloat) o->height);
}
gst_gl_overlay_draw (o, flag);
if (flag == 1)
gl->Disable (GL_TEXTURE_2D);
}
static void
gst_gl_overlay_init (GstGLOverlay * overlay)
{
overlay->location = NULL;
overlay->pixbuf = NULL;
overlay->pbuftexture = 0;
overlay->pbuftexture = 0;
overlay->width = 0;
overlay->height = 0;
overlay->pos_x_png = 0;
overlay->pos_y_png = 0;
overlay->size_png = 100;
overlay->pos_x_video = 0;
overlay->pos_y_video = 0;
overlay->size_video = 100;
overlay->video_top = FALSE;
overlay->rotate_png = 0;
overlay->rotate_video = 0;
overlay->angle_png = 0;
overlay->angle_video = 0;
overlay->ratio_video = 0;
// overlay->stretch = TRUE;
overlay->pbuf_has_changed = FALSE;
}
static void
gst_gl_overlay_reset_resources (GstGLFilter * filter)
{
// GstGLOverlay* overlay = GST_GL_OVERLAY(filter);
}
static void
gst_gl_overlay_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstGLOverlay *overlay = GST_GL_OVERLAY (object);
switch (prop_id) {
case PROP_LOCATION:
if (overlay->location != NULL)
g_free (overlay->location);
overlay->pbuf_has_changed = TRUE;
overlay->location = g_value_dup_string (value);
break;
case PROP_XPOS_PNG:
overlay->pos_x_png = g_value_get_int (value);
break;
case PROP_YPOS_PNG:
overlay->pos_y_png = g_value_get_int (value);
break;
case PROP_SIZE_PNG:
overlay->size_png = g_value_get_int (value);
break;
case PROP_XPOS_VIDEO:
overlay->pos_x_video = g_value_get_int (value);
break;
case PROP_YPOS_VIDEO:
overlay->pos_y_video = g_value_get_int (value);
break;
case PROP_SIZE_VIDEO:
overlay->size_video = g_value_get_int (value);
break;
case PROP_VIDEOTOP:
overlay->video_top = g_value_get_boolean (value);
break;
case PROP_ROTATE_PNG:
overlay->rotate_png = g_value_get_int (value);
break;
case PROP_ROTATE_VIDEO:
overlay->rotate_video = g_value_get_int (value);
break;
case PROP_ANGLE_PNG:
overlay->angle_png = g_value_get_int (value);
break;
case PROP_ANGLE_VIDEO:
overlay->angle_video = g_value_get_int (value);
break;
case PROP_RATIO_VIDEO:
overlay->ratio_video = (gfloat) g_value_get_int (value);
break;
/* case PROP_STRETCH:
overlay->stretch = g_value_get_boolean (value);
break;
*/
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_overlay_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstGLOverlay *overlay = GST_GL_OVERLAY (object);
switch (prop_id) {
case PROP_LOCATION:
g_value_set_string (value, overlay->location);
break;
case PROP_XPOS_PNG:
g_value_set_int (value, overlay->pos_x_png);
break;
case PROP_YPOS_PNG:
g_value_set_int (value, overlay->pos_y_png);
break;
case PROP_SIZE_PNG:
g_value_set_int (value, overlay->size_png);
break;
case PROP_XPOS_VIDEO:
g_value_set_int (value, overlay->pos_x_video);
break;
case PROP_YPOS_VIDEO:
g_value_set_int (value, overlay->pos_y_video);
break;
case PROP_SIZE_VIDEO:
g_value_set_int (value, overlay->size_video);
break;
case PROP_VIDEOTOP:
g_value_set_boolean (value, overlay->video_top);
break;
case PROP_ROTATE_PNG:
g_value_set_int (value, overlay->rotate_png);
break;
case PROP_ROTATE_VIDEO:
g_value_set_int (value, overlay->rotate_video);
break;
case PROP_ANGLE_PNG:
g_value_set_int (value, overlay->angle_png);
break;
case PROP_ANGLE_VIDEO:
g_value_set_int (value, overlay->angle_video);
break;
case PROP_RATIO_VIDEO:
g_value_set_int (value, (gint) overlay->ratio_video);
break;
/* case PROP_STRETCH:
g_value_set_boolean (value, overlay->stretch);
break;
*/
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
gst_gl_overlay_set_caps (GstGLFilter * filter, GstCaps * incaps,
GstCaps * outcaps)
{
GstGLOverlay *overlay = GST_GL_OVERLAY (filter);
GstStructure *s = gst_caps_get_structure (incaps, 0);
gint width = 0;
gint height = 0;
gst_structure_get_int (s, "width", &width);
gst_structure_get_int (s, "height", &height);
overlay->width_window = (gfloat) width;
overlay->height_window = (gfloat) height;
return TRUE;
}
static void
gst_gl_overlay_init_resources (GstGLFilter * filter)
{
// GstGLOverlay *overlay = GST_GL_OVERLAY (filter);
}
static void
gst_gl_overlay_callback (gint width, gint height, guint texture, gpointer stuff)
{
GstGLOverlay *overlay = GST_GL_OVERLAY (stuff);
GstGLFilter *filter = GST_GL_FILTER (overlay);
const GstGLFuncs *gl = filter->context->gl_vtable;
gl->MatrixMode (GL_PROJECTION);
gl->LoadIdentity ();
gluPerspective (70.0f,
(GLfloat) overlay->width_window / (GLfloat) overlay->height_window, 1.0f,
1000.0f);
gl->Enable (GL_DEPTH_TEST);
gluLookAt (0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
if (!overlay->video_top) {
if (overlay->pbuftexture != 0)
gst_gl_overlay_load_texture (overlay, overlay->pbuftexture, 0);
// if (overlay->stretch) {
// width = (gfloat) overlay->width;
// height = (gfloat) overlay->height;
// }
gl->LoadIdentity ();
gst_gl_overlay_load_texture (overlay, texture, 1);
} else {
gst_gl_overlay_load_texture (overlay, texture, 1);
if (overlay->pbuftexture == 0)
return;
// if (overlay->stretch) {
// width = (gfloat) overlay->width;
// height = (gfloat) overlay->height;
// }
gl->LoadIdentity ();
gst_gl_overlay_load_texture (overlay, overlay->pbuftexture, 0);
}
}
static void
init_pixbuf_texture (GstGLContext * context, gpointer data)
{
GstGLOverlay *overlay = GST_GL_OVERLAY (data);
GstGLFilter *filter = GST_GL_FILTER (overlay);
const GstGLFuncs *gl = filter->context->gl_vtable;
if (overlay->pixbuf) {
gl->DeleteTextures (1, &overlay->pbuftexture);
gl->GenTextures (1, &overlay->pbuftexture);
if (overlay->type_file == 1) {
gl->BindTexture (GL_TEXTURE_2D, overlay->pbuftexture);
gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGBA,
(gint) overlay->width, (gint) overlay->height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, overlay->pixbuf);
} else if (overlay->type_file == 2) {
gl->BindTexture (GL_TEXTURE_2D, overlay->pbuftexture);
gl->TexImage2D (GL_TEXTURE_2D, 0, overlay->internalFormat,
overlay->width, overlay->height, 0, overlay->format,
GL_UNSIGNED_BYTE, overlay->pixbuf);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
}
}
static gboolean
gst_gl_overlay_filter_texture (GstGLFilter * filter, guint in_tex,
guint out_tex)
{
GstGLOverlay *overlay = GST_GL_OVERLAY (filter);
if (overlay->pbuf_has_changed && (overlay->location != NULL)) {
if ((overlay->type_file = gst_gl_overlay_load_png (filter)) == 0)
if ((overlay->type_file = gst_gl_overlay_load_jpeg (filter)) == 0)
overlay->pixbuf = NULL;
/* if loader failed then context is turned off */
gst_gl_context_thread_add (filter->context, init_pixbuf_texture, overlay);
if (overlay->pixbuf) {
free (overlay->pixbuf);
overlay->pixbuf = NULL;
}
overlay->pbuf_has_changed = FALSE;
}
gst_gl_filter_render_to_target (filter, TRUE, in_tex, out_tex,
gst_gl_overlay_callback, overlay);
return TRUE;
}
static void
user_warning_fn (png_structp png_ptr, png_const_charp warning_msg)
{
g_warning ("%s\n", warning_msg);
}
#define LOAD_ERROR(msg) { GST_WARNING ("unable to load %s: %s", overlay->location, msg); return FALSE; }
static gint
gst_gl_overlay_load_jpeg (GstGLFilter * filter)
{
GstGLOverlay *overlay = GST_GL_OVERLAY (filter);
FILE *fp = NULL;
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
JSAMPROW j;
int i;
fp = fopen (overlay->location, "rb");
if (!fp) {
g_error ("error: couldn't open file!\n");
return 0;
}
jpeg_create_decompress (&cinfo);
cinfo.err = jpeg_std_error (&jerr);
jpeg_stdio_src (&cinfo, fp);
jpeg_read_header (&cinfo, TRUE);
jpeg_start_decompress (&cinfo);
overlay->width = cinfo.image_width;
overlay->height = cinfo.image_height;
overlay->internalFormat = cinfo.num_components;
if (cinfo.num_components == 1)
overlay->format = GL_LUMINANCE;
else
overlay->format = GL_RGB;
overlay->pixbuf = (GLubyte *) malloc (sizeof (GLubyte) * overlay->width
* overlay->height * overlay->internalFormat);
for (i = 0; i < overlay->height; ++i) {
j = (overlay->pixbuf +
(((int) overlay->height - (i +
1)) * (int) overlay->width * overlay->internalFormat));
jpeg_read_scanlines (&cinfo, &j, 1);
}
jpeg_finish_decompress (&cinfo);
jpeg_destroy_decompress (&cinfo);
fclose (fp);
return 2;
}
static gint
gst_gl_overlay_load_png (GstGLFilter * filter)
{
GstGLOverlay *overlay = GST_GL_OVERLAY (filter);
png_structp png_ptr;
png_infop info_ptr;
png_uint_32 width = 0;
png_uint_32 height = 0;
gint bit_depth = 0;
gint color_type = 0;
gint interlace_type = 0;
png_FILE_p fp = NULL;
guint y = 0;
guchar **rows = NULL;
gint filler;
png_byte magic[8];
gint n_read;
if (!filter->context)
return 1;
if ((fp = fopen (overlay->location, "rb")) == NULL)
LOAD_ERROR ("file not found");
/* Read magic number */
n_read = fread (magic, 1, sizeof (magic), fp);
if (n_read != sizeof (magic)) {
fclose (fp);
LOAD_ERROR ("can't read PNG magic number");
}
/* Check for valid magic number */
if (png_sig_cmp (magic, 0, sizeof (magic))) {
fclose (fp);
LOAD_ERROR ("not a valid PNG image");
}
png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL) {
fclose (fp);
LOAD_ERROR ("failed to initialize the png_struct");
}
png_set_error_fn (png_ptr, NULL, NULL, user_warning_fn);
info_ptr = png_create_info_struct (png_ptr);
if (info_ptr == NULL) {
fclose (fp);
png_destroy_read_struct (&png_ptr, png_infopp_NULL, png_infopp_NULL);
LOAD_ERROR ("failed to initialize the memory for image information");
}
png_init_io (png_ptr, fp);
png_set_sig_bytes (png_ptr, sizeof (magic));
png_read_info (png_ptr, info_ptr);
png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
&interlace_type, int_p_NULL, int_p_NULL);
if (color_type == PNG_COLOR_TYPE_RGB) {
filler = 0xff;
png_set_filler (png_ptr, filler, PNG_FILLER_AFTER);
color_type = PNG_COLOR_TYPE_RGB_ALPHA;
}
if (color_type != PNG_COLOR_TYPE_RGB_ALPHA) {
fclose (fp);
png_destroy_read_struct (&png_ptr, png_infopp_NULL, png_infopp_NULL);
LOAD_ERROR ("color type is not rgb");
}
overlay->width = width;
overlay->height = height;
overlay->pixbuf = (guchar *) malloc (sizeof (guchar) * width * height * 4);
rows = (guchar **) malloc (sizeof (guchar *) * height);
for (y = 0; y < height; ++y)
rows[y] = (guchar *) (overlay->pixbuf + y * width * 4);
png_read_image (png_ptr, rows);
free (rows);
png_read_end (png_ptr, info_ptr);
png_destroy_read_struct (&png_ptr, &info_ptr, png_infopp_NULL);
fclose (fp);
return 1;
}

80
ext/gl/gstgloverlay.h Normal file
View file

@ -0,0 +1,80 @@
/*
* GStreamer
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef _GST_GL_OVERLAY_H_
#define _GST_GL_OVERLAY_H_
#include <gst/gl/gstglfilter.h>
G_BEGIN_DECLS
#define GST_TYPE_GL_OVERLAY (gst_gl_overlay_get_type())
#define GST_GL_OVERLAY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_GL_OVERLAY,GstGLOverlay))
#define GST_IS_GL_OVERLAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_GL_OVERLAY))
#define GST_GL_OVERLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) , GST_TYPE_GL_OVERLAY,GstGLOverlayClass))
#define GST_IS_GL_OVERLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) , GST_TYPE_GL_OVERLAY))
#define GST_GL_OVERLAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) , GST_TYPE_GL_OVERLAY,GstGLOverlayClass))
typedef struct _GstGLOverlay GstGLOverlay;
typedef struct _GstGLOverlayClass GstGLOverlayClass;
struct _GstGLOverlay
{
GstGLFilter filter;
gchar *location;
gboolean pbuf_has_changed;
gint8 pos_x_png;
gint8 pos_y_png;
guint8 size_png;
gint8 pos_x_video;
gint8 pos_y_video;
guint8 size_video;
gboolean video_top;
guint8 rotate_png;
guint8 rotate_video;
gint8 angle_png;
gint8 angle_video;
guchar *pixbuf;
gint width, height;
GLuint pbuftexture;
GLint internalFormat;
GLenum format;
gint type_file; // 0 = No; 1 = PNG and 2 = JPEG
gfloat width_window;
gfloat height_window;
gfloat posx;
gfloat posy;
gfloat ratio_window;
gfloat ratio_texture;
gfloat ratio_x;
gfloat ratio_y;
gfloat ratio_video;
/* gboolean stretch; */
};
struct _GstGLOverlayClass
{
GstGLFilterClass filter_class;
};
G_END_DECLS
#endif /* _GST_GL_OVERLAY_H_ */

708
ext/gl/gstgltestsrc.c Normal file
View file

@ -0,0 +1,708 @@
/*
* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
* Copyright (C) 2002,2007 David A. Schleef <ds@schleef.org>
* Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:element-gltestsrc
*
* <refsect2>
* <para>
* The gltestsrc element is used to produce test video texture.
* The video test produced can be controlled with the "pattern"
* property.
* </para>
* <title>Example launch line</title>
* <para>
* <programlisting>
* gst-launch -v gltestsrc pattern=smpte ! glimagesink
* </programlisting>
* Shows original SMPTE color bars in a window.
* </para>
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstgltestsrc.h"
#include "gltestsrc.h"
#include <gst/gst-i18n-plugin.h>
#define USE_PEER_BUFFERALLOC
GST_DEBUG_CATEGORY_STATIC (gl_test_src_debug);
#define GST_CAT_DEFAULT gl_test_src_debug
enum
{
PROP_0,
PROP_PATTERN,
PROP_TIMESTAMP_OFFSET,
PROP_IS_LIVE
/* FILL ME */
};
#define gst_gl_test_src_parent_class parent_class
G_DEFINE_TYPE (GstGLTestSrc, gst_gl_test_src, GST_TYPE_PUSH_SRC);
static void gst_gl_test_src_set_pattern (GstGLTestSrc * gltestsrc,
int pattern_type);
static void gst_gl_test_src_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_gl_test_src_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static gboolean gst_gl_test_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps);
static GstCaps *gst_gl_test_src_fixate (GstBaseSrc * bsrc, GstCaps * caps);
static gboolean gst_gl_test_src_is_seekable (GstBaseSrc * psrc);
static gboolean gst_gl_test_src_do_seek (GstBaseSrc * bsrc,
GstSegment * segment);
static gboolean gst_gl_test_src_query (GstBaseSrc * bsrc, GstQuery * query);
static void gst_gl_test_src_set_context (GstElement * element,
GstContext * context);
static void gst_gl_test_src_get_times (GstBaseSrc * basesrc,
GstBuffer * buffer, GstClockTime * start, GstClockTime * end);
static GstFlowReturn gst_gl_test_src_fill (GstPushSrc * psrc,
GstBuffer * buffer);
static gboolean gst_gl_test_src_start (GstBaseSrc * basesrc);
static gboolean gst_gl_test_src_stop (GstBaseSrc * basesrc);
static gboolean gst_gl_test_src_decide_allocation (GstBaseSrc * basesrc,
GstQuery * query);
static void gst_gl_test_src_callback (gpointer stuff);
#define GST_TYPE_GL_TEST_SRC_PATTERN (gst_gl_test_src_pattern_get_type ())
static GType
gst_gl_test_src_pattern_get_type (void)
{
static GType gl_test_src_pattern_type = 0;
static const GEnumValue pattern_types[] = {
{GST_GL_TEST_SRC_SMPTE, "SMPTE 100% color bars", "smpte"},
{GST_GL_TEST_SRC_SNOW, "Random (television snow)", "snow"},
{GST_GL_TEST_SRC_BLACK, "100% Black", "black"},
{GST_GL_TEST_SRC_WHITE, "100% White", "white"},
{GST_GL_TEST_SRC_RED, "Red", "red"},
{GST_GL_TEST_SRC_GREEN, "Green", "green"},
{GST_GL_TEST_SRC_BLUE, "Blue", "blue"},
{GST_GL_TEST_SRC_CHECKERS1, "Checkers 1px", "checkers-1"},
{GST_GL_TEST_SRC_CHECKERS2, "Checkers 2px", "checkers-2"},
{GST_GL_TEST_SRC_CHECKERS4, "Checkers 4px", "checkers-4"},
{GST_GL_TEST_SRC_CHECKERS8, "Checkers 8px", "checkers-8"},
{GST_GL_TEST_SRC_CIRCULAR, "Circular", "circular"},
{GST_GL_TEST_SRC_BLINK, "Blink", "blink"},
{0, NULL, NULL}
};
if (!gl_test_src_pattern_type) {
gl_test_src_pattern_type =
g_enum_register_static ("GstGLTestSrcPattern", pattern_types);
}
return gl_test_src_pattern_type;
}
static void
gst_gl_test_src_class_init (GstGLTestSrcClass * klass)
{
GObjectClass *gobject_class;
GstBaseSrcClass *gstbasesrc_class;
GstPushSrcClass *gstpushsrc_class;
GstElementClass *element_class;
GST_DEBUG_CATEGORY_INIT (gl_test_src_debug, "gltestsrc", 0,
"Video Test Source");
gobject_class = (GObjectClass *) klass;
gstbasesrc_class = (GstBaseSrcClass *) klass;
gstpushsrc_class = (GstPushSrcClass *) klass;
element_class = GST_ELEMENT_CLASS (klass);
gobject_class->set_property = gst_gl_test_src_set_property;
gobject_class->get_property = gst_gl_test_src_get_property;
g_object_class_install_property (gobject_class, PROP_PATTERN,
g_param_spec_enum ("pattern", "Pattern",
"Type of test pattern to generate", GST_TYPE_GL_TEST_SRC_PATTERN,
GST_GL_TEST_SRC_SMPTE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_TIMESTAMP_OFFSET, g_param_spec_int64 ("timestamp-offset",
"Timestamp offset",
"An offset added to timestamps set on buffers (in ns)", G_MININT64,
G_MAXINT64, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_IS_LIVE,
g_param_spec_boolean ("is-live", "Is Live",
"Whether to act as a live source", FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_element_class_set_metadata (element_class, "Video test source",
"Source/Video", "Creates a test video stream",
"David A. Schleef <ds@schleef.org>");
gst_element_class_add_pad_template (element_class,
gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
gst_caps_from_string (GST_GL_DOWNLOAD_VIDEO_CAPS)));
element_class->set_context = gst_gl_test_src_set_context;
gstbasesrc_class->set_caps = gst_gl_test_src_setcaps;
gstbasesrc_class->is_seekable = gst_gl_test_src_is_seekable;
gstbasesrc_class->do_seek = gst_gl_test_src_do_seek;
gstbasesrc_class->query = gst_gl_test_src_query;
gstbasesrc_class->get_times = gst_gl_test_src_get_times;
gstbasesrc_class->start = gst_gl_test_src_start;
gstbasesrc_class->stop = gst_gl_test_src_stop;
gstbasesrc_class->fixate = gst_gl_test_src_fixate;
gstbasesrc_class->decide_allocation = gst_gl_test_src_decide_allocation;
gstpushsrc_class->fill = gst_gl_test_src_fill;
}
static void
gst_gl_test_src_init (GstGLTestSrc * src)
{
gst_gl_test_src_set_pattern (src, GST_GL_TEST_SRC_SMPTE);
src->timestamp_offset = 0;
/* we operate in time */
gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME);
gst_base_src_set_live (GST_BASE_SRC (src), FALSE);
}
static GstCaps *
gst_gl_test_src_fixate (GstBaseSrc * bsrc, GstCaps * caps)
{
GstStructure *structure;
GST_DEBUG ("fixate");
caps = gst_caps_make_writable (caps);
structure = gst_caps_get_structure (caps, 0);
gst_structure_fixate_field_nearest_int (structure, "width", 320);
gst_structure_fixate_field_nearest_int (structure, "height", 240);
gst_structure_fixate_field_nearest_fraction (structure, "framerate", 30, 1);
caps = GST_BASE_SRC_CLASS (parent_class)->fixate (bsrc, caps);
return caps;
}
static void
gst_gl_test_src_set_pattern (GstGLTestSrc * gltestsrc, gint pattern_type)
{
gltestsrc->pattern_type = pattern_type;
GST_DEBUG_OBJECT (gltestsrc, "setting pattern to %d", pattern_type);
switch (pattern_type) {
case GST_GL_TEST_SRC_SMPTE:
gltestsrc->make_image = gst_gl_test_src_smpte;
break;
case GST_GL_TEST_SRC_SNOW:
gltestsrc->make_image = gst_gl_test_src_snow;
break;
case GST_GL_TEST_SRC_BLACK:
gltestsrc->make_image = gst_gl_test_src_black;
break;
case GST_GL_TEST_SRC_WHITE:
gltestsrc->make_image = gst_gl_test_src_white;
break;
case GST_GL_TEST_SRC_RED:
gltestsrc->make_image = gst_gl_test_src_red;
break;
case GST_GL_TEST_SRC_GREEN:
gltestsrc->make_image = gst_gl_test_src_green;
break;
case GST_GL_TEST_SRC_BLUE:
gltestsrc->make_image = gst_gl_test_src_blue;
break;
case GST_GL_TEST_SRC_CHECKERS1:
gltestsrc->make_image = gst_gl_test_src_checkers1;
break;
case GST_GL_TEST_SRC_CHECKERS2:
gltestsrc->make_image = gst_gl_test_src_checkers2;
break;
case GST_GL_TEST_SRC_CHECKERS4:
gltestsrc->make_image = gst_gl_test_src_checkers4;
break;
case GST_GL_TEST_SRC_CHECKERS8:
gltestsrc->make_image = gst_gl_test_src_checkers8;
break;
case GST_GL_TEST_SRC_CIRCULAR:
gltestsrc->make_image = gst_gl_test_src_circular;
break;
case GST_GL_TEST_SRC_BLINK:
gltestsrc->make_image = gst_gl_test_src_black;
break;
default:
g_assert_not_reached ();
}
}
static void
gst_gl_test_src_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstGLTestSrc *src = GST_GL_TEST_SRC (object);
switch (prop_id) {
case PROP_PATTERN:
gst_gl_test_src_set_pattern (src, g_value_get_enum (value));
break;
case PROP_TIMESTAMP_OFFSET:
src->timestamp_offset = g_value_get_int64 (value);
break;
case PROP_IS_LIVE:
gst_base_src_set_live (GST_BASE_SRC (src), g_value_get_boolean (value));
break;
default:
break;
}
}
static void
gst_gl_test_src_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstGLTestSrc *src = GST_GL_TEST_SRC (object);
switch (prop_id) {
case PROP_PATTERN:
g_value_set_enum (value, src->pattern_type);
break;
case PROP_TIMESTAMP_OFFSET:
g_value_set_int64 (value, src->timestamp_offset);
break;
case PROP_IS_LIVE:
g_value_set_boolean (value, gst_base_src_is_live (GST_BASE_SRC (src)));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
gst_gl_test_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps)
{
GstGLTestSrc *gltestsrc = GST_GL_TEST_SRC (bsrc);
GST_DEBUG ("setcaps");
if (!gst_video_info_from_caps (&gltestsrc->out_info, caps))
goto wrong_caps;
gltestsrc->negotiated = TRUE;
return TRUE;
/* ERRORS */
wrong_caps:
{
GST_WARNING ("wrong caps");
return FALSE;
}
}
static void
gst_gl_test_src_set_context (GstElement * element, GstContext * context)
{
GstGLTestSrc *src = GST_GL_TEST_SRC (element);
gst_gl_handle_set_context (element, context, &src->display);
}
static gboolean
gst_gl_test_src_query (GstBaseSrc * bsrc, GstQuery * query)
{
gboolean res = FALSE;
GstGLTestSrc *src;
src = GST_GL_TEST_SRC (bsrc);
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_CONTEXT:
{
res = gst_gl_handle_context_query ((GstElement *) src, query,
&src->display);
break;
}
case GST_QUERY_CONVERT:
{
GstFormat src_fmt, dest_fmt;
gint64 src_val, dest_val;
gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
res =
gst_video_info_convert (&src->out_info, src_fmt, src_val, dest_fmt,
&dest_val);
gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
break;
}
default:
res = GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query);
}
return res;
}
static void
gst_gl_test_src_get_times (GstBaseSrc * basesrc, GstBuffer * buffer,
GstClockTime * start, GstClockTime * end)
{
/* for live sources, sync on the timestamp of the buffer */
if (gst_base_src_is_live (basesrc)) {
GstClockTime timestamp = GST_BUFFER_TIMESTAMP (buffer);
if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
/* get duration to calculate end time */
GstClockTime duration = GST_BUFFER_DURATION (buffer);
if (GST_CLOCK_TIME_IS_VALID (duration))
*end = timestamp + duration;
*start = timestamp;
}
} else {
*start = -1;
*end = -1;
}
}
static gboolean
gst_gl_test_src_do_seek (GstBaseSrc * bsrc, GstSegment * segment)
{
GstClockTime time;
GstGLTestSrc *src;
src = GST_GL_TEST_SRC (bsrc);
segment->time = segment->start;
time = segment->position;
/* now move to the time indicated */
if (src->out_info.fps_n) {
src->n_frames = gst_util_uint64_scale (time,
src->out_info.fps_n, src->out_info.fps_d * GST_SECOND);
} else
src->n_frames = 0;
if (src->out_info.fps_n) {
src->running_time = gst_util_uint64_scale (src->n_frames,
src->out_info.fps_d * GST_SECOND, src->out_info.fps_n);
} else {
/* FIXME : Not sure what to set here */
src->running_time = 0;
}
g_return_val_if_fail (src->running_time <= time, FALSE);
return TRUE;
}
static gboolean
gst_gl_test_src_is_seekable (GstBaseSrc * psrc)
{
/* we're seekable... */
return TRUE;
}
static GstFlowReturn
gst_gl_test_src_fill (GstPushSrc * psrc, GstBuffer * buffer)
{
GstGLTestSrc *src;
GstClockTime next_time;
gint width, height;
GstVideoFrame out_frame;
gboolean out_gl_wrapped = FALSE;
guint out_tex;
src = GST_GL_TEST_SRC (psrc);
if (G_UNLIKELY (!src->negotiated))
goto not_negotiated;
width = GST_VIDEO_INFO_WIDTH (&src->out_info);
height = GST_VIDEO_INFO_HEIGHT (&src->out_info);
/* 0 framerate and we are at the second frame, eos */
if (G_UNLIKELY (GST_VIDEO_INFO_FPS_N (&src->out_info) == 0
&& src->n_frames == 1))
goto eos;
if (src->pattern_type == GST_GL_TEST_SRC_BLINK) {
if (src->n_frames & 0x1)
src->make_image = gst_gl_test_src_white;
else
src->make_image = gst_gl_test_src_black;
}
if (!gst_video_frame_map (&out_frame, &src->out_info, buffer,
GST_MAP_WRITE | GST_MAP_GL)) {
return GST_FLOW_NOT_NEGOTIATED;
}
if (gst_is_gl_memory (out_frame.map[0].memory)) {
out_tex = *(guint *) out_frame.data[0];
} else {
GST_INFO ("Output Buffer does not contain correct meta, "
"attempting to wrap for download");
if (!src->out_tex_id) {
gst_gl_context_gen_texture (src->context, &src->out_tex_id,
GST_VIDEO_FORMAT_RGBA, GST_VIDEO_FRAME_WIDTH (&out_frame),
GST_VIDEO_FRAME_HEIGHT (&out_frame));
}
out_tex = src->out_tex_id;
if (!src->download) {
src->download = gst_gl_download_new (src->context);
if (!gst_gl_download_init_format (src->download,
GST_VIDEO_FRAME_FORMAT (&out_frame),
GST_VIDEO_FRAME_WIDTH (&out_frame),
GST_VIDEO_FRAME_HEIGHT (&out_frame))) {
GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
("%s", "Failed to init download format"), (NULL));
return FALSE;
}
}
out_gl_wrapped = TRUE;
}
gst_buffer_replace (&src->buffer, buffer);
//blocking call, generate a FBO
if (!gst_gl_context_use_fbo_v2 (src->context, width, height, src->fbo,
src->depthbuffer, out_tex, gst_gl_test_src_callback,
(gpointer) src)) {
goto not_negotiated;
}
if (out_gl_wrapped) {
if (!gst_gl_download_perform_with_data (src->download, out_tex,
out_frame.data)) {
GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, ("%s",
"Failed to init upload format"), (NULL));
return FALSE;
}
}
gst_video_frame_unmap (&out_frame);
GST_BUFFER_TIMESTAMP (buffer) = src->timestamp_offset + src->running_time;
GST_BUFFER_OFFSET (buffer) = src->n_frames;
src->n_frames++;
GST_BUFFER_OFFSET_END (buffer) = src->n_frames;
if (src->out_info.fps_n) {
next_time = gst_util_uint64_scale_int (src->n_frames * GST_SECOND,
src->out_info.fps_d, src->out_info.fps_n);
GST_BUFFER_DURATION (buffer) = next_time - src->running_time;
} else {
next_time = src->timestamp_offset;
/* NONE means forever */
GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
}
src->running_time = next_time;
return GST_FLOW_OK;
not_negotiated:
{
GST_ELEMENT_ERROR (src, CORE, NEGOTIATION, (NULL),
(_("format wasn't negotiated before get function")));
return GST_FLOW_NOT_NEGOTIATED;
}
eos:
{
GST_DEBUG_OBJECT (src, "eos: 0 framerate, frame %d", (gint) src->n_frames);
return GST_FLOW_EOS;
}
}
static gboolean
gst_gl_test_src_start (GstBaseSrc * basesrc)
{
GstGLTestSrc *src = GST_GL_TEST_SRC (basesrc);
if (!gst_gl_ensure_display (src, &src->display))
return FALSE;
src->running_time = 0;
src->n_frames = 0;
src->negotiated = FALSE;
return TRUE;
}
static gboolean
gst_gl_test_src_stop (GstBaseSrc * basesrc)
{
GstGLTestSrc *src = GST_GL_TEST_SRC (basesrc);
if (src->context) {
if (src->out_tex_id) {
gst_gl_context_del_texture (src->context, &src->out_tex_id);
}
if (src->download) {
gst_object_unref (src->download);
src->download = NULL;
}
//blocking call, delete the FBO
gst_gl_context_del_fbo (src->context, src->fbo, src->depthbuffer);
gst_object_unref (src->context);
src->context = NULL;
}
if (src->display) {
gst_object_unref (src->display);
src->display = NULL;
}
return TRUE;
}
static gboolean
gst_gl_test_src_decide_allocation (GstBaseSrc * basesrc, GstQuery * query)
{
GstGLTestSrc *src = GST_GL_TEST_SRC (basesrc);
GstBufferPool *pool = NULL;
GstStructure *config;
GstCaps *caps;
guint min, max, size;
gboolean update_pool;
GError *error = NULL;
guint idx;
guint out_width, out_height;
GstGLContext *other_context = NULL;
gst_query_parse_allocation (query, &caps, NULL);
if (gst_query_get_n_allocation_pools (query) > 0) {
gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
update_pool = TRUE;
} else {
GstVideoInfo vinfo;
gst_video_info_init (&vinfo);
gst_video_info_from_caps (&vinfo, caps);
size = vinfo.size;
min = max = 0;
update_pool = FALSE;
}
if (!gst_gl_ensure_display (src, &src->display))
return FALSE;
if (gst_query_find_allocation_meta (query,
GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, &idx)) {
GstGLContext *context;
const GstStructure *upload_meta_params;
gpointer handle;
gchar *type;
gchar *apis;
gst_query_parse_nth_allocation_meta (query, idx, &upload_meta_params);
if (gst_structure_get (upload_meta_params, "gst.gl.GstGLContext",
GST_GL_TYPE_CONTEXT, &context, NULL) && context) {
GstGLContext *old = src->context;
src->context = context;
if (old)
gst_object_unref (old);
} else if (gst_structure_get (upload_meta_params, "gst.gl.context.handle",
G_TYPE_POINTER, &handle, "gst.gl.context.type", G_TYPE_STRING,
&type, "gst.gl.context.apis", G_TYPE_STRING, &apis, NULL)
&& handle) {
GstGLPlatform platform = GST_GL_PLATFORM_NONE;
GstGLAPI gl_apis;
GST_DEBUG ("got GL context handle 0x%p with type %s and apis %s", handle,
type, apis);
if (g_strcmp0 (type, "glx") == 0)
platform = GST_GL_PLATFORM_GLX;
gl_apis = gst_gl_api_from_string (apis);
if (gl_apis && platform)
other_context =
gst_gl_context_new_wrapped (src->display, (guintptr) handle,
platform, gl_apis);
}
}
if (!src->context) {
src->context = gst_gl_context_new (src->display);
if (!gst_gl_context_create (src->context, other_context, &error))
goto context_error;
}
out_width = GST_VIDEO_INFO_WIDTH (&src->out_info);
out_height = GST_VIDEO_INFO_HEIGHT (&src->out_info);
if (!gst_gl_context_gen_fbo (src->context, out_width, out_height,
&src->fbo, &src->depthbuffer))
goto context_error;
if (!pool)
pool = gst_gl_buffer_pool_new (src->context);
config = gst_buffer_pool_get_config (pool);
gst_buffer_pool_config_set_params (config, caps, size, min, max);
gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
gst_buffer_pool_set_config (pool, config);
if (update_pool)
gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
else
gst_query_add_allocation_pool (query, pool, size, min, max);
gst_object_unref (pool);
return TRUE;
context_error:
{
GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, ("%s", error->message),
(NULL));
return FALSE;
}
}
//opengl scene
static void
gst_gl_test_src_callback (gpointer stuff)
{
GstGLTestSrc *src = GST_GL_TEST_SRC (stuff);
src->make_image (src, src->buffer, GST_VIDEO_INFO_WIDTH (&src->out_info),
GST_VIDEO_INFO_HEIGHT (&src->out_info));
gst_buffer_unref (src->buffer);
src->buffer = NULL;
}

125
ext/gl/gstgltestsrc.h Normal file
View file

@ -0,0 +1,125 @@
/*
* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
* Copyright (C) 2002,2007 David A. Schleef <ds@schleef.org>
* Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_GL_TEST_SRC_H__
#define __GST_GL_TEST_SRC_H__
#include <gst/gst.h>
#include <gst/base/gstpushsrc.h>
#include <gst/gl/gl.h>
G_BEGIN_DECLS
#define GST_TYPE_GL_TEST_SRC \
(gst_gl_test_src_get_type())
#define GST_GL_TEST_SRC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_TEST_SRC,GstGLTestSrc))
#define GST_GL_TEST_SRC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GL_TEST_SRC,GstGLTestSrcClass))
#define GST_IS_GL_TEST_SRC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_TEST_SRC))
#define GST_IS_GL_TEST_SRC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GL_TEST_SRC))
/**
* GstGLTestSrcPattern:
* @GST_GL_TEST_SRC_SMPTE: A standard SMPTE test pattern
* @GST_GL_TEST_SRC_SNOW: Random noise
* @GST_GL_TEST_SRC_BLACK: A black image
* @GST_GL_TEST_SRC_WHITE: A white image
* @GST_GL_TEST_SRC_RED: A red image
* @GST_GL_TEST_SRC_GREEN: A green image
* @GST_GL_TEST_SRC_BLUE: A blue image
* @GST_GL_TEST_SRC_CHECKERS1: Checkers pattern (1px)
* @GST_GL_TEST_SRC_CHECKERS2: Checkers pattern (2px)
* @GST_GL_TEST_SRC_CHECKERS4: Checkers pattern (4px)
* @GST_GL_TEST_SRC_CHECKERS8: Checkers pattern (8px)
* @GST_GL_TEST_SRC_CIRCULAR: Circular pattern
* @GST_GL_TEST_SRC_BLINK: Alternate between black and white
*
* The test pattern to produce.
*/
typedef enum {
GST_GL_TEST_SRC_SMPTE,
GST_GL_TEST_SRC_SNOW,
GST_GL_TEST_SRC_BLACK,
GST_GL_TEST_SRC_WHITE,
GST_GL_TEST_SRC_RED,
GST_GL_TEST_SRC_GREEN,
GST_GL_TEST_SRC_BLUE,
GST_GL_TEST_SRC_CHECKERS1,
GST_GL_TEST_SRC_CHECKERS2,
GST_GL_TEST_SRC_CHECKERS4,
GST_GL_TEST_SRC_CHECKERS8,
GST_GL_TEST_SRC_CIRCULAR,
GST_GL_TEST_SRC_BLINK
} GstGLTestSrcPattern;
typedef struct _GstGLTestSrc GstGLTestSrc;
typedef struct _GstGLTestSrcClass GstGLTestSrcClass;
/**
* GstGLTestSrc:
*
* Opaque data structure.
*/
struct _GstGLTestSrc {
GstPushSrc element;
/*< private >*/
/* type of output */
GstGLTestSrcPattern pattern_type;
/* video state */
char *format_name;
GstVideoInfo out_info;
GLuint fbo;
GLuint depthbuffer;
GstBuffer* buffer;
GstBufferPool *pool;
guint out_tex_id;
GstGLDownload *download;
GstGLDisplay *display;
GstGLContext *context;
gint64 timestamp_offset; /* base offset */
GstClockTime running_time; /* total running time */
gint64 n_frames; /* total frames sent */
gboolean negotiated;
void (*make_image) (GstGLTestSrc* v, GstBuffer* buffer, gint w, gint h);
};
struct _GstGLTestSrcClass {
GstPushSrcClass parent_class;
};
GType gst_gl_test_src_get_type (void);
G_END_DECLS
#endif /* __GST_GL_TEST_SRC_H__ */

294
ext/gl/gstglvideomixer.c Normal file
View file

@ -0,0 +1,294 @@
/*
* GStreamer
* Copyright (C) 2009 Julien Isorce <julien.isorce@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:element-glvideomixer
*
* glmixer sub element. N gl sink pads to 1 source pad.
* N + 1 OpenGL contexts shared together.
* N <= 6 because the rendering is more a like a cube than a video_mixer
* Each opengl input stream is rendered on a cube face
*
* <refsect2>
* <title>Examples</title>
* |[
* gst-launch-0.10 videotestsrc ! "video/x-raw-yuv, format=(fourcc)YUY2" ! glupload ! queue ! glvideomixer name=m ! glimagesink videotestsrc pattern=12 ! "video/x-raw-yuv, format=(fourcc)I420, framerate=(fraction)5/1, width=100, height=200" ! glupload ! queue ! m. videotestsrc ! "video/x-raw-rgb, framerate=(fraction)15/1, width=1500, height=1500" ! glupload ! gleffects effect=3 ! queue ! m. videotestsrc ! glupload ! gleffects effect=2 ! queue ! m. videotestsrc ! glupload ! glfiltercube ! queue ! m. videotestsrc ! glupload ! gleffects effect=6 ! queue ! m.
* ]|
* FBO (Frame Buffer Object) is required.
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstglvideomixer.h"
#define GST_CAT_DEFAULT gst_gl_video_mixer_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
enum
{
PROP_0,
};
#define DEBUG_INIT \
GST_DEBUG_CATEGORY_INIT (gst_gl_video_mixer_debug, "glvideomixer", 0, "glvideomixer element");
G_DEFINE_TYPE_WITH_CODE (GstGLVideoMixer, gst_gl_video_mixer, GST_TYPE_GL_MIXER,
DEBUG_INIT);
static void gst_gl_video_mixer_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_gl_video_mixer_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_gl_video_mixer_reset (GstGLMixer * mixer);
static gboolean gst_gl_video_mixer_init_shader (GstGLMixer * mixer,
GstCaps * outcaps);
static gboolean gst_gl_video_mixer_process_textures (GstGLMixer * mixer,
GPtrArray * in_frames, guint out_tex);
static void gst_gl_video_mixer_callback (gpointer stuff);
/* vertex source */
static const gchar *video_mixer_v_src =
"attribute vec4 a_position; \n"
"attribute vec2 a_texCoord; \n"
"uniform float x_scale; \n"
"uniform float y_scale; \n"
"varying vec2 v_texCoord; \n"
"void main() \n"
"{ \n"
" gl_Position = a_position * vec4(x_scale, y_scale, 1.0, 1.0);\n"
" v_texCoord = a_texCoord; \n" "}";
/* fragment source */
static const gchar *video_mixer_f_src =
"uniform sampler2D texture; \n"
"varying vec2 v_texCoord; \n"
"void main() \n"
"{ \n"
" vec4 rgba = texture2D( texture, v_texCoord );\n"
" gl_FragColor = vec4(rgba.rgb, 1.0);\n"
"} \n";
static void
gst_gl_video_mixer_class_init (GstGLVideoMixerClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *element_class;
gobject_class = (GObjectClass *) klass;
element_class = GST_ELEMENT_CLASS (klass);
gobject_class->set_property = gst_gl_video_mixer_set_property;
gobject_class->get_property = gst_gl_video_mixer_get_property;
gst_element_class_set_metadata (element_class, "OpenGL video_mixer",
"Filter/Effect/Video", "OpenGL video_mixer",
"Julien Isorce <julien.isorce@gmail.com>");
GST_GL_MIXER_CLASS (klass)->set_caps = gst_gl_video_mixer_init_shader;
GST_GL_MIXER_CLASS (klass)->reset = gst_gl_video_mixer_reset;
GST_GL_MIXER_CLASS (klass)->process_textures =
gst_gl_video_mixer_process_textures;
}
static void
gst_gl_video_mixer_init (GstGLVideoMixer * video_mixer)
{
video_mixer->shader = NULL;
video_mixer->input_frames = NULL;
}
static void
gst_gl_video_mixer_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_video_mixer_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_gl_video_mixer_reset (GstGLMixer * mixer)
{
GstGLVideoMixer *video_mixer = GST_GL_VIDEO_MIXER (mixer);
video_mixer->input_frames = NULL;
if (video_mixer->shader)
gst_gl_context_del_shader (mixer->context, video_mixer->shader);
video_mixer->shader = NULL;
}
static gboolean
gst_gl_video_mixer_init_shader (GstGLMixer * mixer, GstCaps * outcaps)
{
GstGLVideoMixer *video_mixer = GST_GL_VIDEO_MIXER (mixer);
return gst_gl_context_gen_shader (mixer->context, video_mixer_v_src,
video_mixer_f_src, &video_mixer->shader);
}
static gboolean
gst_gl_video_mixer_process_textures (GstGLMixer * mix, GPtrArray * frames,
guint out_tex)
{
GstGLVideoMixer *video_mixer = GST_GL_VIDEO_MIXER (mix);
video_mixer->input_frames = frames;
gst_gl_context_use_fbo_v2 (mix->context,
GST_VIDEO_INFO_WIDTH (&mix->out_info),
GST_VIDEO_INFO_HEIGHT (&mix->out_info), mix->fbo, mix->depthbuffer,
out_tex, gst_gl_video_mixer_callback, (gpointer) video_mixer);
return TRUE;
}
/* opengl scene, params: input texture (not the output mixer->texture) */
static void
gst_gl_video_mixer_callback (gpointer stuff)
{
GstGLVideoMixer *video_mixer = GST_GL_VIDEO_MIXER (stuff);
GstGLMixer *mixer = GST_GL_MIXER (video_mixer);
GstGLFuncs *gl = mixer->context->gl_vtable;
GLint attr_position_loc = 0;
GLint attr_texture_loc = 0;
guint out_width, out_height;
const GLushort indices[] = {
0, 1, 2,
0, 2, 3
};
guint count = 0;
out_width = GST_VIDEO_INFO_WIDTH (&mixer->out_info);
out_height = GST_VIDEO_INFO_HEIGHT (&mixer->out_info);
gst_gl_context_clear_shader (mixer->context);
gl->BindTexture (GL_TEXTURE_2D, 0);
gl->Disable (GL_TEXTURE_2D);
gl->Disable (GL_DEPTH_TEST);
gl->Disable (GL_CULL_FACE);
gl->ClearColor (0.0, 0.0, 0.0, 0.0);
gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
gst_gl_shader_use (video_mixer->shader);
attr_position_loc =
gst_gl_shader_get_attribute_location (video_mixer->shader, "a_position");
attr_texture_loc =
gst_gl_shader_get_attribute_location (video_mixer->shader, "a_texCoord");
gl->Enable (GL_BLEND);
while (count < video_mixer->input_frames->len) {
GstGLMixerFrameData *frame;
GLfloat *v_vertices;
guint in_tex;
guint in_width, in_height;
gfloat w, h;
frame = g_ptr_array_index (video_mixer->input_frames, count);
in_tex = frame->texture;
in_width = GST_VIDEO_INFO_WIDTH (&frame->pad->in_info);
in_height = GST_VIDEO_INFO_HEIGHT (&frame->pad->in_info);
if (!frame || !in_tex || in_width <= 0 || in_height <= 0) {
GST_DEBUG ("skipping texture:%u frame:%p width:%u height %u",
in_tex, frame, in_width, in_height);
count++;
continue;
}
GST_TRACE ("processing texture:%u dimensions:%ux%u", in_tex, in_width,
in_height);
w = ((gfloat) in_width / (gfloat) out_width);
h = ((gfloat) in_height / (gfloat) out_height);
GST_TRACE ("processing texture:%u dimensions:%ux%u, %fx%f", in_tex,
in_width, in_height, w, h);
/* *INDENT-OFF* */
v_vertices = (GLfloat[]) {
/* front face */
-1.0, -1.0, -1.0f,
0.0f, 0.0f,
1.0, -1.0, -1.0f,
1.0f, 0.0f,
1.0, 1.0, -1.0f,
1.0f, 1.0f,
-1.0, 1.0, -1.0f,
0.0f, 1.0f,
};
/* *INDENT-ON* */
gl->VertexAttribPointer (attr_position_loc, 3, GL_FLOAT,
GL_FALSE, 5 * sizeof (GLfloat), &v_vertices[0]);
gl->VertexAttribPointer (attr_texture_loc, 2, GL_FLOAT,
GL_FALSE, 5 * sizeof (GLfloat), &v_vertices[3]);
gl->EnableVertexAttribArray (attr_position_loc);
gl->EnableVertexAttribArray (attr_texture_loc);
gl->BlendFunc (GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR);
gl->BlendEquation (GL_FUNC_ADD);
gl->ActiveTexture (GL_TEXTURE0);
gl->BindTexture (GL_TEXTURE_2D, in_tex);
gst_gl_shader_set_uniform_1i (video_mixer->shader, "texture", 0);
gst_gl_shader_set_uniform_1f (video_mixer->shader, "x_scale", w);
gst_gl_shader_set_uniform_1f (video_mixer->shader, "y_scale", h);
gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
++count;
}
gl->DisableVertexAttribArray (attr_position_loc);
gl->DisableVertexAttribArray (attr_texture_loc);
gl->BindTexture (GL_TEXTURE_2D, 0);
gl->Disable (GL_BLEND);
gst_gl_context_clear_shader (mixer->context);
}

55
ext/gl/gstglvideomixer.h Normal file
View file

@ -0,0 +1,55 @@
/*
* GStreamer
* Copyright (C) 2009 Julien Isorce <julien.isorce@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef _GST_GL_VIDEO_MIXER_H_
#define _GST_GL_VIDEO_MIXER_H_
#include <gst/gl/gstglmixer.h>
G_BEGIN_DECLS
#define GST_TYPE_GL_VIDEO_MIXER (gst_gl_video_mixer_get_type())
#define GST_GL_VIDEO_MIXER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_VIDEO_MIXER,GstGLVideoMixer))
#define GST_IS_GL_VIDEO_MIXER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_VIDEO_MIXER))
#define GST_GL_VIDEO_MIXER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_VIDEO_MIXER,GstGLVideoMixerClass))
#define GST_IS_GL_VIDEO_MIXER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_VIDEO_MIXER))
#define GST_GL_VIDEO_MIXER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_VIDEO_MIXER,GstGLVideoMixerClass))
typedef struct _GstGLVideoMixer GstGLVideoMixer;
typedef struct _GstGLVideoMixerClass GstGLVideoMixerClass;
struct _GstGLVideoMixer
{
GstGLMixer mixer;
GstGLShader *shader;
GPtrArray *input_frames;
};
struct _GstGLVideoMixerClass
{
GstGLMixerClass mixer_class;
};
GType gst_gl_video_mixer_get_type (void);
G_END_DECLS
#endif /* _GST_GLFILTERCUBE_H_ */

212
ext/gl/gstopengl.c Normal file
View file

@ -0,0 +1,212 @@
/*
* GStreamer
* Copyright (C) 2003 Julien Moutte <julien@moutte.net>
* Copyright (C) 2005,2006,2007 David A. Schleef <ds@schleef.org>
* Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.com>
* Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:plugin-opengl
*
* Cross-platform OpenGL plugin.
* <refsect2>
* <title>Debugging</title>
* </refsect2>
* <refsect2>
* <title>Examples</title>
* |[
* gst-launch-0.10 --gst-debug=gldisplay:3 videotestsrc ! glimagesink
* ]| A debugging pipeline.
|[
* GST_GL_SHADER_DEBUG=1 gst-launch-0.10 videotestsrc ! glimagesink
* ]| A debugging pipelines related to shaders.
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef USE_EGL_RPI
#include <bcm_host.h>
#endif
#include <gst/gl/gstglconfig.h>
#include "gstglimagesink.h"
#include "gstglfiltercube.h"
#include "gstgleffects.h"
#include "gstglcolorscale.h"
GType gst_gl_filter_cube_get_type (void);
GType gst_gl_effects_get_type (void);
#if GST_GL_HAVE_OPENGL
#include "gstgltestsrc.h"
#include "gstglfilterlaplacian.h"
#include "gstglfilterglass.h"
#include "gstglfilterapp.h"
#include "gstglfilterreflectedscreen.h"
#include "gstglfiltershader.h"
#include "gstgldeinterlace.h"
#include "gstglmosaic.h"
#include "gstglvideomixer.h"
GType gst_gl_deinterlace_get_type (void);
GType gst_gl_filter_app_get_type (void);
GType gst_gl_filter_reflected_screen_get_type (void);
GType gst_gl_filterblur_get_type (void);
GType gst_gl_filtershader_get_type (void);
GType gst_gl_filtersobel_get_type (void);
GType gst_gl_filter_laplacian_get_type (void);
GType gst_gl_filter_glass_get_type (void);
GType gst_gl_mosaic_get_type (void);
#if HAVE_PNG
#include "gstgldifferencematte.h"
#include "gstglbumper.h"
GType gst_gl_differencematte_get_type (void);
GType gst_gl_bumper_get_type (void);
#if HAVE_JPEG
#include "gstgloverlay.h"
GType gst_gl_overlay_get_type (void);
#endif /* HAVE_JPEG */
#endif /* HAVE_PNG */
#endif /* GST_GL_HAVE_OPENGL */
#define GST_CAT_DEFAULT gst_gl_gstgl_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
/* Register filters that make up the gstgl plugin */
static gboolean
plugin_init (GstPlugin * plugin)
{
GST_DEBUG_CATEGORY_INIT (gst_gl_gstgl_debug, "gstopengl", 0, "gstopengl");
#ifdef USE_EGL_RPI
GST_DEBUG ("Initialize BCM host");
bcm_host_init ();
#endif
if (!gst_element_register (plugin, "glimagesink",
GST_RANK_MARGINAL, GST_TYPE_GLIMAGE_SINK)) {
return FALSE;
}
if (!gst_element_register (plugin, "glfiltercube",
GST_RANK_NONE, GST_TYPE_GL_FILTER_CUBE)) {
return FALSE;
}
if (!gst_element_register (plugin, "gleffects",
GST_RANK_NONE, gst_gl_effects_get_type ())) {
return FALSE;
}
if (!gst_element_register (plugin, "glcolorscale",
GST_RANK_NONE, GST_TYPE_GL_COLORSCALE)) {
return FALSE;
}
#if GST_GL_HAVE_OPENGL
if (!gst_element_register (plugin, "gltestsrc",
GST_RANK_NONE, GST_TYPE_GL_TEST_SRC)) {
return FALSE;
}
if (!gst_element_register (plugin, "glfilterblur",
GST_RANK_NONE, gst_gl_filterblur_get_type ())) {
return FALSE;
}
if (!gst_element_register (plugin, "glshader",
GST_RANK_NONE, gst_gl_filtershader_get_type ())) {
return FALSE;
}
if (!gst_element_register (plugin, "glfiltersobel",
GST_RANK_NONE, gst_gl_filtersobel_get_type ())) {
return FALSE;
}
if (!gst_element_register (plugin, "glfilterlaplacian",
GST_RANK_NONE, GST_TYPE_GL_FILTER_LAPLACIAN)) {
return FALSE;
}
if (!gst_element_register (plugin, "glfilterglass",
GST_RANK_NONE, GST_TYPE_GL_FILTER_GLASS)) {
return FALSE;
}
if (!gst_element_register (plugin, "glfilterapp",
GST_RANK_NONE, GST_TYPE_GL_FILTER_APP)) {
return FALSE;
}
if (!gst_element_register (plugin, "glfilterreflectedscreen",
GST_RANK_NONE, GST_TYPE_GL_FILTER_REFLECTED_SCREEN)) {
return FALSE;
}
if (!gst_element_register (plugin, "gldeinterlace",
GST_RANK_NONE, GST_TYPE_GL_DEINTERLACE)) {
return FALSE;
}
if (!gst_element_register (plugin, "glmosaic",
GST_RANK_NONE, GST_TYPE_GL_MOSAIC)) {
return FALSE;
}
if (!gst_element_register (plugin, "glvideomixer",
GST_RANK_NONE, GST_TYPE_GL_VIDEO_MIXER)) {
return FALSE;
}
#if HAVE_PNG
if (!gst_element_register (plugin, "gldifferencematte",
GST_RANK_NONE, gst_gl_differencematte_get_type ())) {
return FALSE;
}
if (!gst_element_register (plugin, "glbumper",
GST_RANK_NONE, gst_gl_bumper_get_type ())) {
return FALSE;
}
#if HAVE_JPEG
if (!gst_element_register (plugin, "gloverlay",
GST_RANK_NONE, gst_gl_overlay_get_type ())) {
return FALSE;
}
#endif /* HAVE_JPEG */
#endif /* HAVE_PNG */
#endif /* GST_GL_HAVE_OPENGL */
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
opengl,
"OpenGL plugin",
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)