mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-19 14:56:36 +00:00
move gl elements to ext subdirectory
This commit is contained in:
parent
4a18aa4b70
commit
a884d6feee
59 changed files with 12789 additions and 0 deletions
3
ext/gl/BUGS
Normal file
3
ext/gl/BUGS
Normal file
|
@ -0,0 +1,3 @@
|
|||
|
||||
known issues:
|
||||
|
96
ext/gl/Makefile.am
Normal file
96
ext/gl/Makefile.am
Normal 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)
|
||||
|
75
ext/gl/effects/gstgleffectbulge.c
Normal file
75
ext/gl/effects/gstgleffectbulge.c
Normal 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);
|
||||
}
|
75
ext/gl/effects/gstgleffectfisheye.c
Normal file
75
ext/gl/effects/gstgleffectfisheye.c
Normal 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);
|
||||
}
|
223
ext/gl/effects/gstgleffectglow.c
Normal file
223
ext/gl/effects/gstgleffectglow.c
Normal 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);
|
||||
}
|
95
ext/gl/effects/gstgleffectidentity.c
Normal file
95
ext/gl/effects/gstgleffectidentity.c
Normal 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);
|
||||
}
|
148
ext/gl/effects/gstgleffectlumatocurve.c
Normal file
148
ext/gl/effects/gstgleffectlumatocurve.c
Normal 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);
|
||||
}
|
35
ext/gl/effects/gstgleffectlumatocurve.h
Normal file
35
ext/gl/effects/gstgleffectlumatocurve.h
Normal 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__ */
|
120
ext/gl/effects/gstgleffectmirror.c
Normal file
120
ext/gl/effects/gstgleffectmirror.c
Normal 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);
|
||||
}
|
110
ext/gl/effects/gstgleffectrgbtocurve.c
Normal file
110
ext/gl/effects/gstgleffectrgbtocurve.c
Normal 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);
|
||||
}
|
212
ext/gl/effects/gstgleffectscurves.h
Normal file
212
ext/gl/effects/gstgleffectscurves.h
Normal 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
|
72
ext/gl/effects/gstgleffectsin.c
Normal file
72
ext/gl/effects/gstgleffectsin.c
Normal 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);
|
||||
}
|
75
ext/gl/effects/gstgleffectsquare.c
Normal file
75
ext/gl/effects/gstgleffectsquare.c
Normal 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);
|
||||
}
|
119
ext/gl/effects/gstgleffectsqueeze.c
Normal file
119
ext/gl/effects/gstgleffectsqueeze.c
Normal 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);
|
||||
}
|
481
ext/gl/effects/gstgleffectssources.c
Normal file
481
ext/gl/effects/gstgleffectssources.c
Normal 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* */
|
58
ext/gl/effects/gstgleffectssources.h
Normal file
58
ext/gl/effects/gstgleffectssources.h
Normal 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__ */
|
75
ext/gl/effects/gstgleffectstretch.c
Normal file
75
ext/gl/effects/gstgleffectstretch.c
Normal 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);
|
||||
}
|
75
ext/gl/effects/gstgleffecttunnel.c
Normal file
75
ext/gl/effects/gstgleffecttunnel.c
Normal 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);
|
||||
}
|
75
ext/gl/effects/gstgleffecttwirl.c
Normal file
75
ext/gl/effects/gstgleffecttwirl.c
Normal 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);
|
||||
}
|
380
ext/gl/effects/gstgleffectxray.c
Normal file
380
ext/gl/effects/gstgleffectxray.c
Normal 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
507
ext/gl/gltestsrc.c
Normal 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 = π
|
||||
struct fourcc_list_struct *fourcc;
|
||||
|
||||
p->width = w;
|
||||
p->height = h;
|
||||
fourcc = v->fourcc;
|
||||
if (fourcc == NULL)
|
||||
return;
|
||||
|
||||
fourcc->paint_setup (p, dest);
|
||||
p->paint_hline = fourcc->paint_hline;
|
||||
|
||||
for (y = 0; y < h; y++) {
|
||||
p->color = vts_colors + COLOR_GREEN;
|
||||
p->paint_hline (p, 0, y, w);
|
||||
for (x = (y % 2); x < w; x += 2) {
|
||||
p->color = vts_colors + COLOR_RED;
|
||||
p->paint_hline (p, x, y, 1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
gst_gl_test_src_checkers2 (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
|
||||
{
|
||||
#if 0
|
||||
int x, y;
|
||||
paintinfo pi = { NULL, };
|
||||
paintinfo *p = π
|
||||
struct fourcc_list_struct *fourcc;
|
||||
|
||||
p->width = w;
|
||||
p->height = h;
|
||||
fourcc = v->fourcc;
|
||||
if (fourcc == NULL)
|
||||
return;
|
||||
|
||||
fourcc->paint_setup (p, dest);
|
||||
p->paint_hline = fourcc->paint_hline;
|
||||
|
||||
p->color = vts_colors + COLOR_GREEN;
|
||||
for (y = 0; y < h; y++) {
|
||||
p->paint_hline (p, 0, y, w);
|
||||
}
|
||||
|
||||
for (y = 0; y < h; y += 2) {
|
||||
for (x = ((y % 4) == 0) ? 0 : 2; x < w; x += 4) {
|
||||
guint len = (x < (w - 1)) ? 2 : (w - x);
|
||||
|
||||
p->color = vts_colors + COLOR_RED;
|
||||
p->paint_hline (p, x, y + 0, len);
|
||||
if (G_LIKELY ((y + 1) < h)) {
|
||||
p->paint_hline (p, x, y + 1, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
gst_gl_test_src_checkers4 (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
|
||||
{
|
||||
#if 0
|
||||
int x, y;
|
||||
paintinfo pi = { NULL, };
|
||||
paintinfo *p = π
|
||||
struct fourcc_list_struct *fourcc;
|
||||
|
||||
p->width = w;
|
||||
p->height = h;
|
||||
fourcc = v->fourcc;
|
||||
if (fourcc == NULL)
|
||||
return;
|
||||
|
||||
fourcc->paint_setup (p, dest);
|
||||
p->paint_hline = fourcc->paint_hline;
|
||||
|
||||
p->color = vts_colors + COLOR_GREEN;
|
||||
for (y = 0; y < h; y++) {
|
||||
p->paint_hline (p, 0, y, w);
|
||||
}
|
||||
|
||||
for (y = 0; y < h; y += 4) {
|
||||
for (x = ((y % 8) == 0) ? 0 : 4; x < w; x += 8) {
|
||||
guint len = (x < (w - 3)) ? 4 : (w - x);
|
||||
|
||||
p->color = vts_colors + COLOR_RED;
|
||||
p->paint_hline (p, x, y + 0, len);
|
||||
if (G_LIKELY ((y + 1) < h)) {
|
||||
p->paint_hline (p, x, y + 1, len);
|
||||
if (G_LIKELY ((y + 2) < h)) {
|
||||
p->paint_hline (p, x, y + 2, len);
|
||||
if (G_LIKELY ((y + 3) < h)) {
|
||||
p->paint_hline (p, x, y + 3, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
gst_gl_test_src_checkers8 (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
|
||||
{
|
||||
#if 0
|
||||
int x, y;
|
||||
paintinfo pi = { NULL, };
|
||||
paintinfo *p = π
|
||||
struct fourcc_list_struct *fourcc;
|
||||
|
||||
p->width = w;
|
||||
p->height = h;
|
||||
fourcc = v->fourcc;
|
||||
if (fourcc == NULL)
|
||||
return;
|
||||
|
||||
fourcc->paint_setup (p, dest);
|
||||
p->paint_hline = fourcc->paint_hline;
|
||||
|
||||
p->color = vts_colors + COLOR_GREEN;
|
||||
for (y = 0; y < h; y++) {
|
||||
p->paint_hline (p, 0, y, w);
|
||||
}
|
||||
|
||||
for (y = 0; y < h; y += 8) {
|
||||
for (x = ((GST_ROUND_UP_8 (y) % 16) == 0) ? 0 : 8; x < w; x += 16) {
|
||||
guint len = (x < (w - 7)) ? 8 : (w - x);
|
||||
|
||||
p->color = vts_colors + COLOR_RED;
|
||||
p->paint_hline (p, x, y + 0, len);
|
||||
if (G_LIKELY ((y + 1) < h)) {
|
||||
p->paint_hline (p, x, y + 1, len);
|
||||
if (G_LIKELY ((y + 2) < h)) {
|
||||
p->paint_hline (p, x, y + 2, len);
|
||||
if (G_LIKELY ((y + 3) < h)) {
|
||||
p->paint_hline (p, x, y + 3, len);
|
||||
if (G_LIKELY ((y + 4) < h)) {
|
||||
p->paint_hline (p, x, y + 4, len);
|
||||
if (G_LIKELY ((y + 5) < h)) {
|
||||
p->paint_hline (p, x, y + 5, len);
|
||||
if (G_LIKELY ((y + 6) < h)) {
|
||||
p->paint_hline (p, x, y + 6, len);
|
||||
if (G_LIKELY ((y + 7) < h)) {
|
||||
p->paint_hline (p, x, y + 7, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
gst_gl_test_src_circular (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
|
||||
{
|
||||
#if 0
|
||||
int i;
|
||||
int j;
|
||||
paintinfo pi = { NULL, };
|
||||
paintinfo *p = π
|
||||
struct fourcc_list_struct *fourcc;
|
||||
struct vts_color_struct color;
|
||||
static uint8_t sine_array[256];
|
||||
static int sine_array_inited = FALSE;
|
||||
double freq[8];
|
||||
|
||||
#ifdef SCALE_AMPLITUDE
|
||||
double ampl[8];
|
||||
#endif
|
||||
int d;
|
||||
|
||||
if (!sine_array_inited) {
|
||||
for (i = 0; i < 256; i++) {
|
||||
sine_array[i] =
|
||||
floor (255 * (0.5 + 0.5 * sin (i * 2 * M_PI / 256)) + 0.5);
|
||||
}
|
||||
sine_array_inited = TRUE;
|
||||
}
|
||||
|
||||
p->width = w;
|
||||
p->height = h;
|
||||
fourcc = v->fourcc;
|
||||
if (fourcc == NULL)
|
||||
return;
|
||||
|
||||
fourcc->paint_setup (p, dest);
|
||||
p->paint_hline = fourcc->paint_hline;
|
||||
|
||||
color = vts_colors[COLOR_BLACK];
|
||||
p->color = &color;
|
||||
|
||||
for (i = 1; i < 8; i++) {
|
||||
freq[i] = 200 * pow (2.0, -(i - 1) / 4.0);
|
||||
#ifdef SCALE_AMPLITUDE
|
||||
{
|
||||
double x;
|
||||
|
||||
x = 2 * M_PI * freq[i] / w;
|
||||
ampl[i] = sin (x) / x;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
for (i = 0; i < w; i++) {
|
||||
for (j = 0; j < h; j++) {
|
||||
double dist;
|
||||
int seg;
|
||||
|
||||
dist =
|
||||
sqrt ((2 * i - w) * (2 * i - w) + (2 * j - h) * (2 * j -
|
||||
h)) / (2 * w);
|
||||
seg = floor (dist * 16);
|
||||
if (seg == 0 || seg >= 8) {
|
||||
color.Y = 255;
|
||||
} else {
|
||||
#ifdef SCALE_AMPLITUDE
|
||||
double a;
|
||||
#endif
|
||||
d = floor (256 * dist * freq[seg] + 0.5);
|
||||
#ifdef SCALE_AMPLITUDE
|
||||
a = ampl[seg];
|
||||
if (a < 0)
|
||||
a = 0;
|
||||
color.Y = 128 + a * (sine_array[d & 0xff] - 128);
|
||||
#else
|
||||
color.Y = sine_array[d & 0xff];
|
||||
#endif
|
||||
}
|
||||
color.R = color.Y;
|
||||
color.G = color.Y;
|
||||
color.B = color.Y;
|
||||
p->paint_hline (p, i, j, 1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
58
ext/gl/gltestsrc.h
Normal file
58
ext/gl/gltestsrc.h
Normal 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
546
ext/gl/gstglbumper.c
Normal 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
57
ext/gl/gstglbumper.h
Normal 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
156
ext/gl/gstglcolorscale.c
Normal 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
56
ext/gl/gstglcolorscale.h
Normal 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
351
ext/gl/gstgldeinterlace.c
Normal 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
55
ext/gl/gstgldeinterlace.h
Normal 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_ */
|
581
ext/gl/gstgldifferencematte.c
Normal file
581
ext/gl/gstgldifferencematte.c
Normal 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;
|
||||
}
|
59
ext/gl/gstgldifferencematte.h
Normal file
59
ext/gl/gstgldifferencematte.h
Normal 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
398
ext/gl/gstgleffects.c
Normal 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
105
ext/gl/gstgleffects.h
Normal 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
214
ext/gl/gstglfilterapp.c
Normal 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
55
ext/gl/gstglfilterapp.h
Normal 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
257
ext/gl/gstglfilterblur.c
Normal 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
53
ext/gl/gstglfilterblur.h
Normal 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
561
ext/gl/gstglfiltercube.c
Normal 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
65
ext/gl/gstglfiltercube.h
Normal 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
406
ext/gl/gstglfilterglass.c
Normal 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
56
ext/gl/gstglfilterglass.h
Normal 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_ */
|
222
ext/gl/gstglfilterlaplacian.c
Normal file
222
ext/gl/gstglfilterlaplacian.c
Normal 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);
|
||||
}
|
53
ext/gl/gstglfilterlaplacian.h
Normal file
53
ext/gl/gstglfilterlaplacian.h
Normal 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_ */
|
482
ext/gl/gstglfilterreflectedscreen.c
Normal file
482
ext/gl/gstglfilterreflectedscreen.c
Normal 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);
|
||||
}
|
||||
}
|
61
ext/gl/gstglfilterreflectedscreen.h
Normal file
61
ext/gl/gstglfilterreflectedscreen.h
Normal 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
382
ext/gl/gstglfiltershader.c
Normal 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);
|
||||
|
||||
}
|
55
ext/gl/gstglfiltershader.h
Normal file
55
ext/gl/gstglfiltershader.h
Normal 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
269
ext/gl/gstglfiltersobel.c
Normal 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
56
ext/gl/gstglfiltersobel.h
Normal 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
1206
ext/gl/gstglimagesink.c
Normal file
File diff suppressed because it is too large
Load diff
102
ext/gl/gstglimagesink.h
Normal file
102
ext/gl/gstglimagesink.h
Normal 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
365
ext/gl/gstglmosaic.c
Normal 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
55
ext/gl/gstglmosaic.h
Normal 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
809
ext/gl/gstgloverlay.c
Normal 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
80
ext/gl/gstgloverlay.h
Normal 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
708
ext/gl/gstgltestsrc.c
Normal 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
125
ext/gl/gstgltestsrc.h
Normal 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
294
ext/gl/gstglvideomixer.c
Normal 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
55
ext/gl/gstglvideomixer.h
Normal 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
212
ext/gl/gstopengl.c
Normal 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)
|
Loading…
Reference in a new issue